"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.File = exports.Link = exports.Node = exports.SEP = void 0; var process_1 = require("./process"); var buffer_1 = require("./internal/buffer"); var constants_1 = require("./constants"); var events_1 = require("events"); var Stats_1 = require("./Stats"); var S_IFMT = constants_1.constants.S_IFMT, S_IFDIR = constants_1.constants.S_IFDIR, S_IFREG = constants_1.constants.S_IFREG, S_IFLNK = constants_1.constants.S_IFLNK, O_APPEND = constants_1.constants.O_APPEND; exports.SEP = '/'; /** * Node in a file system (like i-node, v-node). */ var Node = /** @class */ (function (_super) { __extends(Node, _super); function Node(ino, perm) { if (perm === void 0) { perm = 438; } var _this = _super.call(this) || this; // User ID and group ID. _this.uid = process_1.default.getuid(); _this.gid = process_1.default.getgid(); _this.atime = new Date(); _this.mtime = new Date(); _this.ctime = new Date(); _this.perm = 438; // Permissions `chmod`, `fchmod` _this.mode = S_IFREG; // S_IFDIR, S_IFREG, etc.. (file by default?) // Number of hard links pointing at this Node. _this.nlink = 1; _this.perm = perm; _this.mode |= perm; _this.ino = ino; return _this; } Node.prototype.getString = function (encoding) { if (encoding === void 0) { encoding = 'utf8'; } return this.getBuffer().toString(encoding); }; Node.prototype.setString = function (str) { // this.setBuffer(bufferFrom(str, 'utf8')); this.buf = (0, buffer_1.bufferFrom)(str, 'utf8'); this.touch(); }; Node.prototype.getBuffer = function () { if (!this.buf) this.setBuffer((0, buffer_1.bufferAllocUnsafe)(0)); return (0, buffer_1.bufferFrom)(this.buf); // Return a copy. }; Node.prototype.setBuffer = function (buf) { this.buf = (0, buffer_1.bufferFrom)(buf); // Creates a copy of data. this.touch(); }; Node.prototype.getSize = function () { return this.buf ? this.buf.length : 0; }; Node.prototype.setModeProperty = function (property) { this.mode = (this.mode & ~S_IFMT) | property; }; Node.prototype.setIsFile = function () { this.setModeProperty(S_IFREG); }; Node.prototype.setIsDirectory = function () { this.setModeProperty(S_IFDIR); }; Node.prototype.setIsSymlink = function () { this.setModeProperty(S_IFLNK); }; Node.prototype.isFile = function () { return (this.mode & S_IFMT) === S_IFREG; }; Node.prototype.isDirectory = function () { return (this.mode & S_IFMT) === S_IFDIR; }; Node.prototype.isSymlink = function () { // return !!this.symlink; return (this.mode & S_IFMT) === S_IFLNK; }; Node.prototype.makeSymlink = function (steps) { this.symlink = steps; this.setIsSymlink(); }; Node.prototype.write = function (buf, off, len, pos) { if (off === void 0) { off = 0; } if (len === void 0) { len = buf.length; } if (pos === void 0) { pos = 0; } if (!this.buf) this.buf = (0, buffer_1.bufferAllocUnsafe)(0); if (pos + len > this.buf.length) { var newBuf = (0, buffer_1.bufferAllocUnsafe)(pos + len); this.buf.copy(newBuf, 0, 0, this.buf.length); this.buf = newBuf; } buf.copy(this.buf, pos, off, off + len); this.touch(); return len; }; // Returns the number of bytes read. Node.prototype.read = function (buf, off, len, pos) { if (off === void 0) { off = 0; } if (len === void 0) { len = buf.byteLength; } if (pos === void 0) { pos = 0; } if (!this.buf) this.buf = (0, buffer_1.bufferAllocUnsafe)(0); var actualLen = len; if (actualLen > buf.byteLength) { actualLen = buf.byteLength; } if (actualLen + pos > this.buf.length) { actualLen = this.buf.length - pos; } this.buf.copy(buf, off, pos, pos + actualLen); return actualLen; }; Node.prototype.truncate = function (len) { if (len === void 0) { len = 0; } if (!len) this.buf = (0, buffer_1.bufferAllocUnsafe)(0); else { if (!this.buf) this.buf = (0, buffer_1.bufferAllocUnsafe)(0); if (len <= this.buf.length) { this.buf = this.buf.slice(0, len); } else { var buf = (0, buffer_1.bufferAllocUnsafe)(0); this.buf.copy(buf); buf.fill(0, len); } } this.touch(); }; Node.prototype.chmod = function (perm) { this.perm = perm; this.mode = (this.mode & ~511) | perm; this.touch(); }; Node.prototype.chown = function (uid, gid) { this.uid = uid; this.gid = gid; this.touch(); }; Node.prototype.touch = function () { this.mtime = new Date(); this.emit('change', this); }; Node.prototype.canRead = function (uid, gid) { if (uid === void 0) { uid = process_1.default.getuid(); } if (gid === void 0) { gid = process_1.default.getgid(); } if (this.perm & 4 /* IROTH */) { return true; } if (gid === this.gid) { if (this.perm & 32 /* IRGRP */) { return true; } } if (uid === this.uid) { if (this.perm & 256 /* IRUSR */) { return true; } } return false; }; Node.prototype.canWrite = function (uid, gid) { if (uid === void 0) { uid = process_1.default.getuid(); } if (gid === void 0) { gid = process_1.default.getgid(); } if (this.perm & 2 /* IWOTH */) { return true; } if (gid === this.gid) { if (this.perm & 16 /* IWGRP */) { return true; } } if (uid === this.uid) { if (this.perm & 128 /* IWUSR */) { return true; } } return false; }; Node.prototype.del = function () { this.emit('delete', this); }; Node.prototype.toJSON = function () { return { ino: this.ino, uid: this.uid, gid: this.gid, atime: this.atime.getTime(), mtime: this.mtime.getTime(), ctime: this.ctime.getTime(), perm: this.perm, mode: this.mode, nlink: this.nlink, symlink: this.symlink, data: this.getString(), }; }; return Node; }(events_1.EventEmitter)); exports.Node = Node; /** * Represents a hard link that points to an i-node `node`. */ var Link = /** @class */ (function (_super) { __extends(Link, _super); function Link(vol, parent, name) { var _this = _super.call(this) || this; _this.children = {}; // Path to this node as Array: ['usr', 'bin', 'node']. _this._steps = []; // "i-node" number of the node. _this.ino = 0; // Number of children. _this.length = 0; _this.vol = vol; _this.parent = parent; _this.name = name; _this.syncSteps(); return _this; } Object.defineProperty(Link.prototype, "steps", { get: function () { return this._steps; }, // Recursively sync children steps, e.g. in case of dir rename set: function (val) { this._steps = val; for (var _i = 0, _a = Object.values(this.children); _i < _a.length; _i++) { var child = _a[_i]; child === null || child === void 0 ? void 0 : child.syncSteps(); } }, enumerable: false, configurable: true }); Link.prototype.setNode = function (node) { this.node = node; this.ino = node.ino; }; Link.prototype.getNode = function () { return this.node; }; Link.prototype.createChild = function (name, node) { if (node === void 0) { node = this.vol.createNode(); } var link = new Link(this.vol, this, name); link.setNode(node); if (node.isDirectory()) { // link.setChild('.', link); // link.getNode().nlink++; // link.setChild('..', this); // this.getNode().nlink++; } this.setChild(name, link); return link; }; Link.prototype.setChild = function (name, link) { if (link === void 0) { link = new Link(this.vol, this, name); } this.children[name] = link; link.parent = this; this.length++; this.emit('child:add', link, this); return link; }; Link.prototype.deleteChild = function (link) { delete this.children[link.getName()]; this.length--; this.emit('child:delete', link, this); }; Link.prototype.getChild = function (name) { if (Object.hasOwnProperty.call(this.children, name)) { return this.children[name]; } }; Link.prototype.getPath = function () { return this.steps.join(exports.SEP); }; Link.prototype.getName = function () { return this.steps[this.steps.length - 1]; }; // del() { // const parent = this.parent; // if(parent) { // parent.deleteChild(link); // } // this.parent = null; // this.vol = null; // } /** * Walk the tree path and return the `Link` at that location, if any. * @param steps {string[]} Desired location. * @param stop {number} Max steps to go into. * @param i {number} Current step in the `steps` array. * * @return {Link|null} */ Link.prototype.walk = function (steps, stop, i) { if (stop === void 0) { stop = steps.length; } if (i === void 0) { i = 0; } if (i >= steps.length) return this; if (i >= stop) return this; var step = steps[i]; var link = this.getChild(step); if (!link) return null; return link.walk(steps, stop, i + 1); }; Link.prototype.toJSON = function () { return { steps: this.steps, ino: this.ino, children: Object.keys(this.children), }; }; Link.prototype.syncSteps = function () { this.steps = this.parent ? this.parent.steps.concat([this.name]) : [this.name]; }; return Link; }(events_1.EventEmitter)); exports.Link = Link; /** * Represents an open file (file descriptor) that points to a `Link` (Hard-link) and a `Node`. */ var File = /** @class */ (function () { /** * Open a Link-Node pair. `node` is provided separately as that might be a different node * rather the one `link` points to, because it might be a symlink. * @param link * @param node * @param flags * @param fd */ function File(link, node, flags, fd) { /** * A cursor/offset position in a file, where data will be written on write. * User can "seek" this position. */ this.position = 0; this.link = link; this.node = node; this.flags = flags; this.fd = fd; } File.prototype.getString = function (encoding) { if (encoding === void 0) { encoding = 'utf8'; } return this.node.getString(); }; File.prototype.setString = function (str) { this.node.setString(str); }; File.prototype.getBuffer = function () { return this.node.getBuffer(); }; File.prototype.setBuffer = function (buf) { this.node.setBuffer(buf); }; File.prototype.getSize = function () { return this.node.getSize(); }; File.prototype.truncate = function (len) { this.node.truncate(len); }; File.prototype.seekTo = function (position) { this.position = position; }; File.prototype.stats = function () { return Stats_1.default.build(this.node); }; File.prototype.write = function (buf, offset, length, position) { if (offset === void 0) { offset = 0; } if (length === void 0) { length = buf.length; } if (typeof position !== 'number') position = this.position; if (this.flags & O_APPEND) position = this.getSize(); var bytes = this.node.write(buf, offset, length, position); this.position = position + bytes; return bytes; }; File.prototype.read = function (buf, offset, length, position) { if (offset === void 0) { offset = 0; } if (length === void 0) { length = buf.byteLength; } if (typeof position !== 'number') position = this.position; var bytes = this.node.read(buf, offset, length, position); this.position = position + bytes; return bytes; }; File.prototype.chmod = function (perm) { this.node.chmod(perm); }; File.prototype.chown = function (uid, gid) { this.node.chown(uid, gid); }; return File; }()); exports.File = File;