UNPKG

@zenfs/core

Version:

A filesystem, anywhere

392 lines (391 loc) 18.8 kB
// SPDX-License-Identifier: LGPL-3.0-or-later /* ioctl stuff. The majority of the code here is ported from Linux See: - include/uapi/asm-generic/ioctl.h - include/uapi/linux/fs.h (`FS_IOC_*`) */ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); var _, done = false; for (var i = decorators.length - 1; i >= 0; i--) { var context = {}; for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; for (var p in contextIn.access) context.access[p] = contextIn.access[p]; context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); if (kind === "accessor") { if (result === void 0) continue; if (result === null || typeof result !== "object") throw new TypeError("Object expected"); if (_ = accept(result.get)) descriptor.get = _; if (_ = accept(result.set)) descriptor.set = _; if (_ = accept(result.init)) initializers.unshift(_); } else if (_ = accept(result)) { if (kind === "field") initializers.unshift(_); else descriptor[key] = _; } } if (target) Object.defineProperty(target, contextIn.name, descriptor); done = true; }; var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { var useValue = arguments.length > 2; for (var i = 0; i < initializers.length; i++) { value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); } return useValue ? value : void 0; }; import { Errno, Exception, setUVMessage, UV } from 'kerium'; import { sizeof } from 'memium'; import { $from, struct, types as t } from 'memium/decorators'; import { _throw } from 'utilium'; import { BufferView } from 'utilium/buffer'; import { Inode, InodeFlags } from '../internal/inode.js'; import { normalizePath } from '../utils.js'; import { resolveMount } from './shared.js'; /* * Flags for the fsxattr.xflags field */ var XFlag; (function (XFlag) { /** data in realtime volume */ XFlag[XFlag["RealTime"] = 1] = "RealTime"; /** preallocated file extents */ XFlag[XFlag["PreAlloc"] = 2] = "PreAlloc"; /** file cannot be modified */ XFlag[XFlag["Immutable"] = 8] = "Immutable"; /** all writes append */ XFlag[XFlag["Append"] = 16] = "Append"; /** all writes synchronous */ XFlag[XFlag["Sync"] = 32] = "Sync"; /** do not update access time */ XFlag[XFlag["NoAtime"] = 64] = "NoAtime"; /** do not include in backups */ XFlag[XFlag["NoDump"] = 128] = "NoDump"; /** create with rt bit set */ XFlag[XFlag["RtInherit"] = 256] = "RtInherit"; /** create with parents projid */ XFlag[XFlag["ProjInherit"] = 512] = "ProjInherit"; /** disallow symlink creation */ XFlag[XFlag["NoSymlinks"] = 1024] = "NoSymlinks"; /** extent size allocator hint */ XFlag[XFlag["ExtSize"] = 2048] = "ExtSize"; /** inherit inode extent size */ XFlag[XFlag["ExtSzInherit"] = 4096] = "ExtSzInherit"; /** do not defragment */ XFlag[XFlag["NoDefrag"] = 8192] = "NoDefrag"; /** use filestream allocator */ XFlag[XFlag["FileStream"] = 16384] = "FileStream"; /** use DAX for IO */ XFlag[XFlag["Dax"] = 32768] = "Dax"; /** CoW extent size allocator hint */ XFlag[XFlag["CowExtSize"] = 65536] = "CowExtSize"; /** no DIFLAG for this */ XFlag[XFlag["HasAttr"] = 2147483648] = "HasAttr"; })(XFlag || (XFlag = {})); let fsxattr = (() => { var _a, _b, _c, _d, _e; let _classDecorators = [struct()]; let _classDescriptor; let _classExtraInitializers = []; let _classThis; let _classSuper = $from(BufferView); let _xflags_decorators; let _xflags_initializers = []; let _xflags_extraInitializers = []; let _extsize_decorators; let _extsize_initializers = []; let _extsize_extraInitializers = []; let _nextents_decorators; let _nextents_initializers = []; let _nextents_extraInitializers = []; let _projid_decorators; let _projid_initializers = []; let _projid_extraInitializers = []; let _cowextsize_decorators; let _cowextsize_initializers = []; let _cowextsize_extraInitializers = []; let _pad_decorators; let _pad_initializers = []; let _pad_extraInitializers = []; var fsxattr = class extends _classSuper { static { _classThis = this; } static { const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; _xflags_decorators = [(_a = t).uint32.bind(_a)]; _extsize_decorators = [(_b = t).uint32.bind(_b)]; _nextents_decorators = [(_c = t).uint32.bind(_c)]; _projid_decorators = [(_d = t).uint32.bind(_d)]; _cowextsize_decorators = [(_e = t).uint32.bind(_e)]; _pad_decorators = [t.char(8)]; __esDecorate(this, null, _xflags_decorators, { kind: "accessor", name: "xflags", static: false, private: false, access: { has: obj => "xflags" in obj, get: obj => obj.xflags, set: (obj, value) => { obj.xflags = value; } }, metadata: _metadata }, _xflags_initializers, _xflags_extraInitializers); __esDecorate(this, null, _extsize_decorators, { kind: "accessor", name: "extsize", static: false, private: false, access: { has: obj => "extsize" in obj, get: obj => obj.extsize, set: (obj, value) => { obj.extsize = value; } }, metadata: _metadata }, _extsize_initializers, _extsize_extraInitializers); __esDecorate(this, null, _nextents_decorators, { kind: "accessor", name: "nextents", static: false, private: false, access: { has: obj => "nextents" in obj, get: obj => obj.nextents, set: (obj, value) => { obj.nextents = value; } }, metadata: _metadata }, _nextents_initializers, _nextents_extraInitializers); __esDecorate(this, null, _projid_decorators, { kind: "accessor", name: "projid", static: false, private: false, access: { has: obj => "projid" in obj, get: obj => obj.projid, set: (obj, value) => { obj.projid = value; } }, metadata: _metadata }, _projid_initializers, _projid_extraInitializers); __esDecorate(this, null, _cowextsize_decorators, { kind: "accessor", name: "cowextsize", static: false, private: false, access: { has: obj => "cowextsize" in obj, get: obj => obj.cowextsize, set: (obj, value) => { obj.cowextsize = value; } }, metadata: _metadata }, _cowextsize_initializers, _cowextsize_extraInitializers); __esDecorate(this, null, _pad_decorators, { kind: "accessor", name: "pad", static: false, private: false, access: { has: obj => "pad" in obj, get: obj => obj.pad, set: (obj, value) => { obj.pad = value; } }, metadata: _metadata }, _pad_initializers, _pad_extraInitializers); __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); fsxattr = _classThis = _classDescriptor.value; if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); } static name = 'fsxattr'; #xflags_accessor_storage = __runInitializers(this, _xflags_initializers, void 0); /** xflags field value */ get xflags() { return this.#xflags_accessor_storage; } set xflags(value) { this.#xflags_accessor_storage = value; } #extsize_accessor_storage = (__runInitializers(this, _xflags_extraInitializers), __runInitializers(this, _extsize_initializers, void 0)); /** extsize field value */ get extsize() { return this.#extsize_accessor_storage; } set extsize(value) { this.#extsize_accessor_storage = value; } #nextents_accessor_storage = (__runInitializers(this, _extsize_extraInitializers), __runInitializers(this, _nextents_initializers, void 0)); /** nextents field value */ get nextents() { return this.#nextents_accessor_storage; } set nextents(value) { this.#nextents_accessor_storage = value; } #projid_accessor_storage = (__runInitializers(this, _nextents_extraInitializers), __runInitializers(this, _projid_initializers, void 0)); /** project identifier */ get projid() { return this.#projid_accessor_storage; } set projid(value) { this.#projid_accessor_storage = value; } #cowextsize_accessor_storage = (__runInitializers(this, _projid_extraInitializers), __runInitializers(this, _cowextsize_initializers, void 0)); /** CoW extsize field value */ get cowextsize() { return this.#cowextsize_accessor_storage; } set cowextsize(value) { this.#cowextsize_accessor_storage = value; } #pad_accessor_storage = (__runInitializers(this, _cowextsize_extraInitializers), __runInitializers(this, _pad_initializers, [])); get pad() { return this.#pad_accessor_storage; } set pad(value) { this.#pad_accessor_storage = value; } constructor(inode = _throw(new Exception(Errno.EINVAL, 'fsxattr must be initialized with an inode'))) { super(new ArrayBuffer(sizeof(fsxattr))); __runInitializers(this, _pad_extraInitializers); this.extsize = inode.size; this.nextents = 1; this.projid = inode.uid; this.cowextsize = inode.size; for (const name of Object.keys(InodeFlags)) { if (!(inode.flags & InodeFlags[name])) continue; if (name in XFlag) this.xflags |= XFlag[name]; } } static { __runInitializers(_classThis, _classExtraInitializers); } }; return fsxattr = _classThis; })(); /** * Inode flags (FS_IOC_GETFLAGS / FS_IOC_SETFLAGS) * @see `FS_*_FL` in `include/uapi/linux/fs.h` (around L250) * @experimental */ var FileFlag; (function (FileFlag) { /** Secure deletion */ FileFlag[FileFlag["SecureRm"] = 1] = "SecureRm"; /** Undelete */ FileFlag[FileFlag["Undelete"] = 2] = "Undelete"; /** Compress file */ FileFlag[FileFlag["Compress"] = 4] = "Compress"; /** Synchronous updates */ FileFlag[FileFlag["Sync"] = 8] = "Sync"; /** Immutable file */ FileFlag[FileFlag["Immutable"] = 16] = "Immutable"; /** Writes to file may only append */ FileFlag[FileFlag["Append"] = 32] = "Append"; /** do not dump file */ FileFlag[FileFlag["NoDump"] = 64] = "NoDump"; /** do not update atime */ FileFlag[FileFlag["NoAtime"] = 128] = "NoAtime"; // Reserved for compression usage... FileFlag[FileFlag["Dirty"] = 256] = "Dirty"; /** One or more compressed clusters */ FileFlag[FileFlag["CompressBlk"] = 512] = "CompressBlk"; /** Don't compress */ FileFlag[FileFlag["NoCompress"] = 1024] = "NoCompress"; // End compression flags --- maybe not all used /** Encrypted file */ FileFlag[FileFlag["Encrypt"] = 2048] = "Encrypt"; /** btree format dir */ FileFlag[FileFlag["Btree"] = 4096] = "Btree"; /** hash-indexed directory */ // eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values FileFlag[FileFlag["Index"] = 4096] = "Index"; /** AFS directory */ FileFlag[FileFlag["IMagic"] = 8192] = "IMagic"; /** Reserved for ext3 */ FileFlag[FileFlag["JournalData"] = 16384] = "JournalData"; /** file tail should not be merged */ FileFlag[FileFlag["NoTail"] = 32768] = "NoTail"; /** dirsync behaviour (directories only) */ FileFlag[FileFlag["DirSync"] = 65536] = "DirSync"; /** Top of directory hierarchies*/ FileFlag[FileFlag["TopDir"] = 131072] = "TopDir"; /** Reserved for ext4 */ FileFlag[FileFlag["HugeFile"] = 262144] = "HugeFile"; /** Extents */ FileFlag[FileFlag["Extent"] = 524288] = "Extent"; /** Verity protected inode */ FileFlag[FileFlag["Verity"] = 1048576] = "Verity"; /** Inode used for large EA */ FileFlag[FileFlag["EaInode"] = 2097152] = "EaInode"; /** Reserved for ext4 */ FileFlag[FileFlag["EofBlocks"] = 4194304] = "EofBlocks"; /** Do not cow file */ FileFlag[FileFlag["NoCow"] = 8388608] = "NoCow"; /** Inode is DAX */ FileFlag[FileFlag["Dax"] = 33554432] = "Dax"; /** Reserved for ext4 */ FileFlag[FileFlag["InlineData"] = 268435456] = "InlineData"; /** Create with parents projid */ FileFlag[FileFlag["ProjInherit"] = 536870912] = "ProjInherit"; /** Folder is case insensitive */ FileFlag[FileFlag["CaseFold"] = 1073741824] = "CaseFold"; /** reserved for ext2 lib */ FileFlag[FileFlag["Reserved"] = 2147483648] = "Reserved"; })(FileFlag || (FileFlag = {})); /** * `FS_IOC_*` commands for {@link ioctl | `ioctl`} * @remarks * These are computed from a script since constant values are needed for enum member types */ export var IOC; (function (IOC) { IOC[IOC["GetFlags"] = 2148034049] = "GetFlags"; IOC[IOC["SetFlags"] = 1074292226] = "SetFlags"; IOC[IOC["GetVersion"] = 2148038145] = "GetVersion"; IOC[IOC["SetVersion"] = 1074296322] = "SetVersion"; IOC[IOC["Fiemap"] = 3223348747] = "Fiemap"; IOC[IOC["GetXattr"] = 2149341215] = "GetXattr"; IOC[IOC["SetXattr"] = 1075599392] = "SetXattr"; IOC[IOC["GetLabel"] = 2164298801] = "GetLabel"; IOC[IOC["SetLabel"] = 1090556978] = "SetLabel"; IOC[IOC["GetUUID"] = 2148603136] = "GetUUID"; IOC[IOC["GetSysfsPath"] = 2155943169] = "GetSysfsPath"; })(IOC || (IOC = {})); /** * `FS_IOC32_*` commands for {@link ioctl | `ioctl`} * @remarks * These are computed from a script since constant values are needed for enum member types */ export var IOC32; (function (IOC32) { IOC32[IOC32["GetFlags"] = 2147771905] = "GetFlags"; IOC32[IOC32["SetFlags"] = 1074030082] = "SetFlags"; IOC32[IOC32["GetVersion"] = 2147776001] = "GetVersion"; IOC32[IOC32["SetVersion"] = 1074034178] = "SetVersion"; })(IOC32 || (IOC32 = {})); /** Perform an `ioctl` on a file or file system. */ export async function ioctl( /** The path to the file or file system to perform the `ioctl` on */ path, /** The command to perform (uint32) */ command, /** The arguments to pass to the command */ ...args) { path = normalizePath(path); const { fs, path: resolved } = resolveMount(path, this); try { const inode = new Inode(await fs.stat(resolved)); switch (command) { case IOC.GetFlags: case IOC32.GetFlags: return inode.flags; case IOC.SetFlags: case IOC32.SetFlags: inode.flags = args[0]; await fs.touch(resolved, inode); return undefined; case IOC.GetVersion: case IOC32.GetVersion: return inode.version; case IOC.SetVersion: case IOC32.SetVersion: inode.version = args[0]; await fs.touch(resolved, inode); return undefined; case IOC.Fiemap: break; case IOC.GetXattr: return new fsxattr(inode); case IOC.SetXattr: break; case IOC.GetLabel: return fs.label; case IOC.SetLabel: fs.label = args[0]; return undefined; case IOC.GetUUID: return fs.uuid; case IOC.GetSysfsPath: /** * Returns the path component under /sys/fs/ that refers to this filesystem; * also /sys/kernel/debug/ for filesystems with debugfs exports * @todo Implement sysfs and have each FS implement the /sys/fs/<name> tree */ return `/sys/fs/${fs.name}/${fs.uuid}`; } } catch (e) { throw setUVMessage(Object.assign(e, { syscall: 'ioctl', path })); } throw UV('ENOTSUP', 'ioctl', path); } /** Perform an `ioctl` on a file or file system */ export function ioctlSync( /** The path to the file or file system to perform the `ioctl` on */ path, /** The command to perform (uint32) */ command, /** The arguments to pass to the command */ ...args) { path = normalizePath(path); const { fs, path: resolved } = resolveMount(path, this); try { const inode = new Inode(fs.statSync(resolved)); switch (command) { case IOC.GetFlags: case IOC32.GetFlags: return inode.flags; case IOC.SetFlags: case IOC32.SetFlags: inode.flags = args[0]; fs.touchSync(resolved, inode); return undefined; case IOC.GetVersion: case IOC32.GetVersion: return inode.version; case IOC.SetVersion: case IOC32.SetVersion: inode.version = args[0]; fs.touchSync(resolved, inode); return undefined; case IOC.Fiemap: break; case IOC.GetXattr: return new fsxattr(inode); case IOC.SetXattr: break; case IOC.GetLabel: return fs.label; case IOC.SetLabel: fs.label = args[0]; return undefined; case IOC.GetUUID: return fs.uuid; case IOC.GetSysfsPath: /** * Returns the path component under /sys/fs/ that refers to this filesystem; * also /sys/kernel/debug/ for filesystems with debugfs exports * @todo Implement sysfs and have each FS implement the /sys/fs/<name> tree */ return `/sys/fs/${fs.name}/${fs.uuid}`; } } catch (e) { throw setUVMessage(Object.assign(e, { syscall: 'ioctl', path })); } throw UV('ENOTSUP', 'ioctl', path); }