source: frontend/node_modules/memfs/lib/volume.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 13 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 90.2 KB
Line 
1"use strict";
2var __extends = (this && this.__extends) || (function () {
3 var extendStatics = function (d, b) {
4 extendStatics = Object.setPrototypeOf ||
5 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6 function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7 return extendStatics(d, b);
8 };
9 return function (d, b) {
10 if (typeof b !== "function" && b !== null)
11 throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12 extendStatics(d, b);
13 function __() { this.constructor = d; }
14 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15 };
16})();
17var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
18 if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
19 if (ar || !(i in from)) {
20 if (!ar) ar = Array.prototype.slice.call(from, 0, i);
21 ar[i] = from[i];
22 }
23 }
24 return to.concat(ar || Array.prototype.slice.call(from));
25};
26Object.defineProperty(exports, "__esModule", { value: true });
27exports.FSWatcher = exports.StatWatcher = exports.Volume = exports.toUnixTimestamp = exports.bufferToEncoding = exports.dataToBuffer = exports.dataToStr = exports.pathToSteps = exports.filenameToSteps = exports.pathToFilename = exports.flagsToNumber = exports.FLAGS = void 0;
28var pathModule = require("path");
29var node_1 = require("./node");
30var Stats_1 = require("./Stats");
31var Dirent_1 = require("./Dirent");
32var buffer_1 = require("./internal/buffer");
33var setImmediate_1 = require("./setImmediate");
34var process_1 = require("./process");
35var setTimeoutUnref_1 = require("./setTimeoutUnref");
36var stream_1 = require("stream");
37var constants_1 = require("./constants");
38var events_1 = require("events");
39var encoding_1 = require("./encoding");
40var errors = require("./internal/errors");
41var util = require("util");
42var promises_1 = require("./promises");
43var resolveCrossPlatform = pathModule.resolve;
44var O_RDONLY = constants_1.constants.O_RDONLY, O_WRONLY = constants_1.constants.O_WRONLY, O_RDWR = constants_1.constants.O_RDWR, O_CREAT = constants_1.constants.O_CREAT, O_EXCL = constants_1.constants.O_EXCL, O_TRUNC = constants_1.constants.O_TRUNC, O_APPEND = constants_1.constants.O_APPEND, O_SYNC = constants_1.constants.O_SYNC, O_DIRECTORY = constants_1.constants.O_DIRECTORY, F_OK = constants_1.constants.F_OK, COPYFILE_EXCL = constants_1.constants.COPYFILE_EXCL, COPYFILE_FICLONE_FORCE = constants_1.constants.COPYFILE_FICLONE_FORCE;
45var _a = pathModule.posix ? pathModule.posix : pathModule, sep = _a.sep, relative = _a.relative, join = _a.join, dirname = _a.dirname;
46var isWin = process_1.default.platform === 'win32';
47var kMinPoolSpace = 128;
48// const kMaxLength = require('buffer').kMaxLength;
49// ---------------------------------------- Error messages
50// TODO: Use `internal/errors.js` in the future.
51var ERRSTR = {
52 PATH_STR: 'path must be a string or Buffer',
53 // FD: 'file descriptor must be a unsigned 32-bit integer',
54 FD: 'fd must be a file descriptor',
55 MODE_INT: 'mode must be an int',
56 CB: 'callback must be a function',
57 UID: 'uid must be an unsigned int',
58 GID: 'gid must be an unsigned int',
59 LEN: 'len must be an integer',
60 ATIME: 'atime must be an integer',
61 MTIME: 'mtime must be an integer',
62 PREFIX: 'filename prefix is required',
63 BUFFER: 'buffer must be an instance of Buffer or StaticBuffer',
64 OFFSET: 'offset must be an integer',
65 LENGTH: 'length must be an integer',
66 POSITION: 'position must be an integer',
67};
68var ERRSTR_OPTS = function (tipeof) { return "Expected options to be either an object or a string, but got ".concat(tipeof, " instead"); };
69// const ERRSTR_FLAG = flag => `Unknown file open flag: ${flag}`;
70var ENOENT = 'ENOENT';
71var EBADF = 'EBADF';
72var EINVAL = 'EINVAL';
73var EPERM = 'EPERM';
74var EPROTO = 'EPROTO';
75var EEXIST = 'EEXIST';
76var ENOTDIR = 'ENOTDIR';
77var EMFILE = 'EMFILE';
78var EACCES = 'EACCES';
79var EISDIR = 'EISDIR';
80var ENOTEMPTY = 'ENOTEMPTY';
81var ENOSYS = 'ENOSYS';
82var ERR_FS_EISDIR = 'ERR_FS_EISDIR';
83function formatError(errorCode, func, path, path2) {
84 if (func === void 0) { func = ''; }
85 if (path === void 0) { path = ''; }
86 if (path2 === void 0) { path2 = ''; }
87 var pathFormatted = '';
88 if (path)
89 pathFormatted = " '".concat(path, "'");
90 if (path2)
91 pathFormatted += " -> '".concat(path2, "'");
92 switch (errorCode) {
93 case ENOENT:
94 return "ENOENT: no such file or directory, ".concat(func).concat(pathFormatted);
95 case EBADF:
96 return "EBADF: bad file descriptor, ".concat(func).concat(pathFormatted);
97 case EINVAL:
98 return "EINVAL: invalid argument, ".concat(func).concat(pathFormatted);
99 case EPERM:
100 return "EPERM: operation not permitted, ".concat(func).concat(pathFormatted);
101 case EPROTO:
102 return "EPROTO: protocol error, ".concat(func).concat(pathFormatted);
103 case EEXIST:
104 return "EEXIST: file already exists, ".concat(func).concat(pathFormatted);
105 case ENOTDIR:
106 return "ENOTDIR: not a directory, ".concat(func).concat(pathFormatted);
107 case EISDIR:
108 return "EISDIR: illegal operation on a directory, ".concat(func).concat(pathFormatted);
109 case EACCES:
110 return "EACCES: permission denied, ".concat(func).concat(pathFormatted);
111 case ENOTEMPTY:
112 return "ENOTEMPTY: directory not empty, ".concat(func).concat(pathFormatted);
113 case EMFILE:
114 return "EMFILE: too many open files, ".concat(func).concat(pathFormatted);
115 case ENOSYS:
116 return "ENOSYS: function not implemented, ".concat(func).concat(pathFormatted);
117 case ERR_FS_EISDIR:
118 return "[ERR_FS_EISDIR]: Path is a directory: ".concat(func, " returned EISDIR (is a directory) ").concat(path);
119 default:
120 return "".concat(errorCode, ": error occurred, ").concat(func).concat(pathFormatted);
121 }
122}
123function createError(errorCode, func, path, path2, Constructor) {
124 if (func === void 0) { func = ''; }
125 if (path === void 0) { path = ''; }
126 if (path2 === void 0) { path2 = ''; }
127 if (Constructor === void 0) { Constructor = Error; }
128 var error = new Constructor(formatError(errorCode, func, path, path2));
129 error.code = errorCode;
130 if (path) {
131 error.path = path;
132 }
133 return error;
134}
135// ---------------------------------------- Flags
136// List of file `flags` as defined by Node.
137var FLAGS;
138(function (FLAGS) {
139 // Open file for reading. An exception occurs if the file does not exist.
140 FLAGS[FLAGS["r"] = O_RDONLY] = "r";
141 // Open file for reading and writing. An exception occurs if the file does not exist.
142 FLAGS[FLAGS["r+"] = O_RDWR] = "r+";
143 // Open file for reading in synchronous mode. Instructs the operating system to bypass the local file system cache.
144 FLAGS[FLAGS["rs"] = O_RDONLY | O_SYNC] = "rs";
145 FLAGS[FLAGS["sr"] = FLAGS.rs] = "sr";
146 // Open file for reading and writing, telling the OS to open it synchronously. See notes for 'rs' about using this with caution.
147 FLAGS[FLAGS["rs+"] = O_RDWR | O_SYNC] = "rs+";
148 FLAGS[FLAGS["sr+"] = FLAGS['rs+']] = "sr+";
149 // Open file for writing. The file is created (if it does not exist) or truncated (if it exists).
150 FLAGS[FLAGS["w"] = O_WRONLY | O_CREAT | O_TRUNC] = "w";
151 // Like 'w' but fails if path exists.
152 FLAGS[FLAGS["wx"] = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL] = "wx";
153 FLAGS[FLAGS["xw"] = FLAGS.wx] = "xw";
154 // Open file for reading and writing. The file is created (if it does not exist) or truncated (if it exists).
155 FLAGS[FLAGS["w+"] = O_RDWR | O_CREAT | O_TRUNC] = "w+";
156 // Like 'w+' but fails if path exists.
157 FLAGS[FLAGS["wx+"] = O_RDWR | O_CREAT | O_TRUNC | O_EXCL] = "wx+";
158 FLAGS[FLAGS["xw+"] = FLAGS['wx+']] = "xw+";
159 // Open file for appending. The file is created if it does not exist.
160 FLAGS[FLAGS["a"] = O_WRONLY | O_APPEND | O_CREAT] = "a";
161 // Like 'a' but fails if path exists.
162 FLAGS[FLAGS["ax"] = O_WRONLY | O_APPEND | O_CREAT | O_EXCL] = "ax";
163 FLAGS[FLAGS["xa"] = FLAGS.ax] = "xa";
164 // Open file for reading and appending. The file is created if it does not exist.
165 FLAGS[FLAGS["a+"] = O_RDWR | O_APPEND | O_CREAT] = "a+";
166 // Like 'a+' but fails if path exists.
167 FLAGS[FLAGS["ax+"] = O_RDWR | O_APPEND | O_CREAT | O_EXCL] = "ax+";
168 FLAGS[FLAGS["xa+"] = FLAGS['ax+']] = "xa+";
169})(FLAGS = exports.FLAGS || (exports.FLAGS = {}));
170function flagsToNumber(flags) {
171 if (typeof flags === 'number')
172 return flags;
173 if (typeof flags === 'string') {
174 var flagsNum = FLAGS[flags];
175 if (typeof flagsNum !== 'undefined')
176 return flagsNum;
177 }
178 // throw new TypeError(formatError(ERRSTR_FLAG(flags)));
179 throw new errors.TypeError('ERR_INVALID_OPT_VALUE', 'flags', flags);
180}
181exports.flagsToNumber = flagsToNumber;
182// ---------------------------------------- Options
183function getOptions(defaults, options) {
184 var opts;
185 if (!options)
186 return defaults;
187 else {
188 var tipeof = typeof options;
189 switch (tipeof) {
190 case 'string':
191 opts = Object.assign({}, defaults, { encoding: options });
192 break;
193 case 'object':
194 opts = Object.assign({}, defaults, options);
195 break;
196 default:
197 throw TypeError(ERRSTR_OPTS(tipeof));
198 }
199 }
200 if (opts.encoding !== 'buffer')
201 (0, encoding_1.assertEncoding)(opts.encoding);
202 return opts;
203}
204function optsGenerator(defaults) {
205 return function (options) { return getOptions(defaults, options); };
206}
207function validateCallback(callback) {
208 if (typeof callback !== 'function')
209 throw TypeError(ERRSTR.CB);
210 return callback;
211}
212function optsAndCbGenerator(getOpts) {
213 return function (options, callback) {
214 return typeof options === 'function' ? [getOpts(), options] : [getOpts(options), validateCallback(callback)];
215 };
216}
217var optsDefaults = {
218 encoding: 'utf8',
219};
220var getDefaultOpts = optsGenerator(optsDefaults);
221var getDefaultOptsAndCb = optsAndCbGenerator(getDefaultOpts);
222var readFileOptsDefaults = {
223 flag: 'r',
224};
225var getReadFileOptions = optsGenerator(readFileOptsDefaults);
226var writeFileDefaults = {
227 encoding: 'utf8',
228 mode: 438 /* MODE.DEFAULT */,
229 flag: FLAGS[FLAGS.w],
230};
231var getWriteFileOptions = optsGenerator(writeFileDefaults);
232var appendFileDefaults = {
233 encoding: 'utf8',
234 mode: 438 /* MODE.DEFAULT */,
235 flag: FLAGS[FLAGS.a],
236};
237var getAppendFileOpts = optsGenerator(appendFileDefaults);
238var getAppendFileOptsAndCb = optsAndCbGenerator(getAppendFileOpts);
239var realpathDefaults = optsDefaults;
240var getRealpathOptions = optsGenerator(realpathDefaults);
241var getRealpathOptsAndCb = optsAndCbGenerator(getRealpathOptions);
242var mkdirDefaults = {
243 mode: 511 /* MODE.DIR */,
244 recursive: false,
245};
246var getMkdirOptions = function (options) {
247 if (typeof options === 'number')
248 return Object.assign({}, mkdirDefaults, { mode: options });
249 return Object.assign({}, mkdirDefaults, options);
250};
251var rmdirDefaults = {
252 recursive: false,
253};
254var getRmdirOptions = function (options) {
255 return Object.assign({}, rmdirDefaults, options);
256};
257var getRmOpts = optsGenerator(optsDefaults);
258var getRmOptsAndCb = optsAndCbGenerator(getRmOpts);
259var readdirDefaults = {
260 encoding: 'utf8',
261 withFileTypes: false,
262};
263var getReaddirOptions = optsGenerator(readdirDefaults);
264var getReaddirOptsAndCb = optsAndCbGenerator(getReaddirOptions);
265var statDefaults = {
266 bigint: false,
267};
268var getStatOptions = function (options) {
269 if (options === void 0) { options = {}; }
270 return Object.assign({}, statDefaults, options);
271};
272var getStatOptsAndCb = function (options, callback) {
273 return typeof options === 'function' ? [getStatOptions(), options] : [getStatOptions(options), validateCallback(callback)];
274};
275// ---------------------------------------- Utility functions
276function getPathFromURLPosix(url) {
277 if (url.hostname !== '') {
278 throw new errors.TypeError('ERR_INVALID_FILE_URL_HOST', process_1.default.platform);
279 }
280 var pathname = url.pathname;
281 for (var n = 0; n < pathname.length; n++) {
282 if (pathname[n] === '%') {
283 var third = pathname.codePointAt(n + 2) | 0x20;
284 if (pathname[n + 1] === '2' && third === 102) {
285 throw new errors.TypeError('ERR_INVALID_FILE_URL_PATH', 'must not include encoded / characters');
286 }
287 }
288 }
289 return decodeURIComponent(pathname);
290}
291function pathToFilename(path) {
292 if (typeof path !== 'string' && !buffer_1.Buffer.isBuffer(path)) {
293 try {
294 if (!(path instanceof require('url').URL))
295 throw new TypeError(ERRSTR.PATH_STR);
296 }
297 catch (err) {
298 throw new TypeError(ERRSTR.PATH_STR);
299 }
300 path = getPathFromURLPosix(path);
301 }
302 var pathString = String(path);
303 nullCheck(pathString);
304 // return slash(pathString);
305 return pathString;
306}
307exports.pathToFilename = pathToFilename;
308var resolve = function (filename, base) {
309 if (base === void 0) { base = process_1.default.cwd(); }
310 return resolveCrossPlatform(base, filename);
311};
312if (isWin) {
313 var _resolve_1 = resolve;
314 var unixify_1 = require('fs-monkey/lib/correctPath').unixify;
315 resolve = function (filename, base) { return unixify_1(_resolve_1(filename, base)); };
316}
317function filenameToSteps(filename, base) {
318 var fullPath = resolve(filename, base);
319 var fullPathSansSlash = fullPath.substring(1);
320 if (!fullPathSansSlash)
321 return [];
322 return fullPathSansSlash.split(sep);
323}
324exports.filenameToSteps = filenameToSteps;
325function pathToSteps(path) {
326 return filenameToSteps(pathToFilename(path));
327}
328exports.pathToSteps = pathToSteps;
329function dataToStr(data, encoding) {
330 if (encoding === void 0) { encoding = encoding_1.ENCODING_UTF8; }
331 if (buffer_1.Buffer.isBuffer(data))
332 return data.toString(encoding);
333 else if (data instanceof Uint8Array)
334 return (0, buffer_1.bufferFrom)(data).toString(encoding);
335 else
336 return String(data);
337}
338exports.dataToStr = dataToStr;
339function dataToBuffer(data, encoding) {
340 if (encoding === void 0) { encoding = encoding_1.ENCODING_UTF8; }
341 if (buffer_1.Buffer.isBuffer(data))
342 return data;
343 else if (data instanceof Uint8Array)
344 return (0, buffer_1.bufferFrom)(data);
345 else
346 return (0, buffer_1.bufferFrom)(String(data), encoding);
347}
348exports.dataToBuffer = dataToBuffer;
349function bufferToEncoding(buffer, encoding) {
350 if (!encoding || encoding === 'buffer')
351 return buffer;
352 else
353 return buffer.toString(encoding);
354}
355exports.bufferToEncoding = bufferToEncoding;
356function nullCheck(path, callback) {
357 if (('' + path).indexOf('\u0000') !== -1) {
358 var er = new Error('Path must be a string without null bytes');
359 er.code = ENOENT;
360 if (typeof callback !== 'function')
361 throw er;
362 process_1.default.nextTick(callback, er);
363 return false;
364 }
365 return true;
366}
367function _modeToNumber(mode, def) {
368 if (typeof mode === 'number')
369 return mode;
370 if (typeof mode === 'string')
371 return parseInt(mode, 8);
372 if (def)
373 return modeToNumber(def);
374 return undefined;
375}
376function modeToNumber(mode, def) {
377 var result = _modeToNumber(mode, def);
378 if (typeof result !== 'number' || isNaN(result))
379 throw new TypeError(ERRSTR.MODE_INT);
380 return result;
381}
382function isFd(path) {
383 return path >>> 0 === path;
384}
385function validateFd(fd) {
386 if (!isFd(fd))
387 throw TypeError(ERRSTR.FD);
388}
389// converts Date or number to a fractional UNIX timestamp
390function toUnixTimestamp(time) {
391 // tslint:disable-next-line triple-equals
392 if (typeof time === 'string' && +time == time) {
393 return +time;
394 }
395 if (time instanceof Date) {
396 return time.getTime() / 1000;
397 }
398 if (isFinite(time)) {
399 if (time < 0) {
400 return Date.now() / 1000;
401 }
402 return time;
403 }
404 throw new Error('Cannot parse time: ' + time);
405}
406exports.toUnixTimestamp = toUnixTimestamp;
407function validateUid(uid) {
408 if (typeof uid !== 'number')
409 throw TypeError(ERRSTR.UID);
410}
411function validateGid(gid) {
412 if (typeof gid !== 'number')
413 throw TypeError(ERRSTR.GID);
414}
415function flattenJSON(nestedJSON) {
416 var flatJSON = {};
417 function flatten(pathPrefix, node) {
418 for (var path in node) {
419 var contentOrNode = node[path];
420 var joinedPath = join(pathPrefix, path);
421 if (typeof contentOrNode === 'string') {
422 flatJSON[joinedPath] = contentOrNode;
423 }
424 else if (typeof contentOrNode === 'object' && contentOrNode !== null && Object.keys(contentOrNode).length > 0) {
425 // empty directories need an explicit entry and therefore get handled in `else`, non-empty ones are implicitly considered
426 flatten(joinedPath, contentOrNode);
427 }
428 else {
429 // without this branch null, empty-object or non-object entries would not be handled in the same way
430 // by both fromJSON() and fromNestedJSON()
431 flatJSON[joinedPath] = null;
432 }
433 }
434 }
435 flatten('', nestedJSON);
436 return flatJSON;
437}
438/**
439 * `Volume` represents a file system.
440 */
441var Volume = /** @class */ (function () {
442 function Volume(props) {
443 if (props === void 0) { props = {}; }
444 // I-node number counter.
445 this.ino = 0;
446 // A mapping for i-node numbers to i-nodes (`Node`);
447 this.inodes = {};
448 // List of released i-node numbers, for reuse.
449 this.releasedInos = [];
450 // A mapping for file descriptors to `File`s.
451 this.fds = {};
452 // A list of reusable (opened and closed) file descriptors, that should be
453 // used first before creating a new file descriptor.
454 this.releasedFds = [];
455 // Max number of open files.
456 this.maxFiles = 10000;
457 // Current number of open files.
458 this.openFiles = 0;
459 this.promisesApi = (0, promises_1.default)(this);
460 this.statWatchers = {};
461 this.props = Object.assign({ Node: node_1.Node, Link: node_1.Link, File: node_1.File }, props);
462 var root = this.createLink();
463 root.setNode(this.createNode(true));
464 var self = this; // tslint:disable-line no-this-assignment
465 this.StatWatcher = /** @class */ (function (_super) {
466 __extends(StatWatcher, _super);
467 function StatWatcher() {
468 return _super.call(this, self) || this;
469 }
470 return StatWatcher;
471 }(StatWatcher));
472 var _ReadStream = FsReadStream;
473 this.ReadStream = /** @class */ (function (_super) {
474 __extends(class_1, _super);
475 function class_1() {
476 var args = [];
477 for (var _i = 0; _i < arguments.length; _i++) {
478 args[_i] = arguments[_i];
479 }
480 return _super.apply(this, __spreadArray([self], args, false)) || this;
481 }
482 return class_1;
483 }(_ReadStream));
484 var _WriteStream = FsWriteStream;
485 this.WriteStream = /** @class */ (function (_super) {
486 __extends(class_2, _super);
487 function class_2() {
488 var args = [];
489 for (var _i = 0; _i < arguments.length; _i++) {
490 args[_i] = arguments[_i];
491 }
492 return _super.apply(this, __spreadArray([self], args, false)) || this;
493 }
494 return class_2;
495 }(_WriteStream));
496 this.FSWatcher = /** @class */ (function (_super) {
497 __extends(FSWatcher, _super);
498 function FSWatcher() {
499 return _super.call(this, self) || this;
500 }
501 return FSWatcher;
502 }(FSWatcher));
503 root.setChild('.', root);
504 root.getNode().nlink++;
505 root.setChild('..', root);
506 root.getNode().nlink++;
507 this.root = root;
508 }
509 Volume.fromJSON = function (json, cwd) {
510 var vol = new Volume();
511 vol.fromJSON(json, cwd);
512 return vol;
513 };
514 Volume.fromNestedJSON = function (json, cwd) {
515 var vol = new Volume();
516 vol.fromNestedJSON(json, cwd);
517 return vol;
518 };
519 Object.defineProperty(Volume.prototype, "promises", {
520 get: function () {
521 if (this.promisesApi === null)
522 throw new Error('Promise is not supported in this environment.');
523 return this.promisesApi;
524 },
525 enumerable: false,
526 configurable: true
527 });
528 Volume.prototype.createLink = function (parent, name, isDirectory, perm) {
529 if (isDirectory === void 0) { isDirectory = false; }
530 if (!parent) {
531 return new this.props.Link(this, null, '');
532 }
533 if (!name) {
534 throw new Error('createLink: name cannot be empty');
535 }
536 return parent.createChild(name, this.createNode(isDirectory, perm));
537 };
538 Volume.prototype.deleteLink = function (link) {
539 var parent = link.parent;
540 if (parent) {
541 parent.deleteChild(link);
542 return true;
543 }
544 return false;
545 };
546 Volume.prototype.newInoNumber = function () {
547 var releasedFd = this.releasedInos.pop();
548 if (releasedFd)
549 return releasedFd;
550 else {
551 this.ino = (this.ino + 1) % 0xffffffff;
552 return this.ino;
553 }
554 };
555 Volume.prototype.newFdNumber = function () {
556 var releasedFd = this.releasedFds.pop();
557 return typeof releasedFd === 'number' ? releasedFd : Volume.fd--;
558 };
559 Volume.prototype.createNode = function (isDirectory, perm) {
560 if (isDirectory === void 0) { isDirectory = false; }
561 var node = new this.props.Node(this.newInoNumber(), perm);
562 if (isDirectory)
563 node.setIsDirectory();
564 this.inodes[node.ino] = node;
565 return node;
566 };
567 Volume.prototype.getNode = function (ino) {
568 return this.inodes[ino];
569 };
570 Volume.prototype.deleteNode = function (node) {
571 node.del();
572 delete this.inodes[node.ino];
573 this.releasedInos.push(node.ino);
574 };
575 // Generates 6 character long random string, used by `mkdtemp`.
576 Volume.prototype.genRndStr = function () {
577 var str = (Math.random() + 1).toString(36).substring(2, 8);
578 if (str.length === 6)
579 return str;
580 else
581 return this.genRndStr();
582 };
583 // Returns a `Link` (hard link) referenced by path "split" into steps.
584 Volume.prototype.getLink = function (steps) {
585 return this.root.walk(steps);
586 };
587 // Just link `getLink`, but throws a correct user error, if link to found.
588 Volume.prototype.getLinkOrThrow = function (filename, funcName) {
589 var steps = filenameToSteps(filename);
590 var link = this.getLink(steps);
591 if (!link)
592 throw createError(ENOENT, funcName, filename);
593 return link;
594 };
595 // Just like `getLink`, but also dereference/resolves symbolic links.
596 Volume.prototype.getResolvedLink = function (filenameOrSteps) {
597 var steps = typeof filenameOrSteps === 'string' ? filenameToSteps(filenameOrSteps) : filenameOrSteps;
598 var link = this.root;
599 var i = 0;
600 while (i < steps.length) {
601 var step = steps[i];
602 link = link.getChild(step);
603 if (!link)
604 return null;
605 var node = link.getNode();
606 if (node.isSymlink()) {
607 steps = node.symlink.concat(steps.slice(i + 1));
608 link = this.root;
609 i = 0;
610 continue;
611 }
612 i++;
613 }
614 return link;
615 };
616 // Just like `getLinkOrThrow`, but also dereference/resolves symbolic links.
617 Volume.prototype.getResolvedLinkOrThrow = function (filename, funcName) {
618 var link = this.getResolvedLink(filename);
619 if (!link)
620 throw createError(ENOENT, funcName, filename);
621 return link;
622 };
623 Volume.prototype.resolveSymlinks = function (link) {
624 // let node: Node = link.getNode();
625 // while(link && node.isSymlink()) {
626 // link = this.getLink(node.symlink);
627 // if(!link) return null;
628 // node = link.getNode();
629 // }
630 // return link;
631 return this.getResolvedLink(link.steps.slice(1));
632 };
633 // Just like `getLinkOrThrow`, but also verifies that the link is a directory.
634 Volume.prototype.getLinkAsDirOrThrow = function (filename, funcName) {
635 var link = this.getLinkOrThrow(filename, funcName);
636 if (!link.getNode().isDirectory())
637 throw createError(ENOTDIR, funcName, filename);
638 return link;
639 };
640 // Get the immediate parent directory of the link.
641 Volume.prototype.getLinkParent = function (steps) {
642 return this.root.walk(steps, steps.length - 1);
643 };
644 Volume.prototype.getLinkParentAsDirOrThrow = function (filenameOrSteps, funcName) {
645 var steps = filenameOrSteps instanceof Array ? filenameOrSteps : filenameToSteps(filenameOrSteps);
646 var link = this.getLinkParent(steps);
647 if (!link)
648 throw createError(ENOENT, funcName, sep + steps.join(sep));
649 if (!link.getNode().isDirectory())
650 throw createError(ENOTDIR, funcName, sep + steps.join(sep));
651 return link;
652 };
653 Volume.prototype.getFileByFd = function (fd) {
654 return this.fds[String(fd)];
655 };
656 Volume.prototype.getFileByFdOrThrow = function (fd, funcName) {
657 if (!isFd(fd))
658 throw TypeError(ERRSTR.FD);
659 var file = this.getFileByFd(fd);
660 if (!file)
661 throw createError(EBADF, funcName);
662 return file;
663 };
664 /**
665 * @todo This is not used anymore. Remove.
666 */
667 /*
668 private getNodeByIdOrCreate(id: TFileId, flags: number, perm: number): Node {
669 if (typeof id === 'number') {
670 const file = this.getFileByFd(id);
671 if (!file) throw Error('File nto found');
672 return file.node;
673 } else {
674 const steps = pathToSteps(id as PathLike);
675 let link = this.getLink(steps);
676 if (link) return link.getNode();
677
678 // Try creating a node if not found.
679 if (flags & O_CREAT) {
680 const dirLink = this.getLinkParent(steps);
681 if (dirLink) {
682 const name = steps[steps.length - 1];
683 link = this.createLink(dirLink, name, false, perm);
684 return link.getNode();
685 }
686 }
687
688 throw createError(ENOENT, 'getNodeByIdOrCreate', pathToFilename(id));
689 }
690 }
691 */
692 Volume.prototype.wrapAsync = function (method, args, callback) {
693 var _this = this;
694 validateCallback(callback);
695 (0, setImmediate_1.default)(function () {
696 var result;
697 try {
698 result = method.apply(_this, args);
699 }
700 catch (err) {
701 callback(err);
702 return;
703 }
704 callback(null, result);
705 });
706 };
707 Volume.prototype._toJSON = function (link, json, path) {
708 var _a;
709 if (link === void 0) { link = this.root; }
710 if (json === void 0) { json = {}; }
711 var isEmpty = true;
712 var children = link.children;
713 if (link.getNode().isFile()) {
714 children = (_a = {}, _a[link.getName()] = link.parent.getChild(link.getName()), _a);
715 link = link.parent;
716 }
717 for (var name_1 in children) {
718 if (name_1 === '.' || name_1 === '..') {
719 continue;
720 }
721 isEmpty = false;
722 var child = link.getChild(name_1);
723 if (!child) {
724 throw new Error('_toJSON: unexpected undefined');
725 }
726 var node = child.getNode();
727 if (node.isFile()) {
728 var filename = child.getPath();
729 if (path)
730 filename = relative(path, filename);
731 json[filename] = node.getString();
732 }
733 else if (node.isDirectory()) {
734 this._toJSON(child, json, path);
735 }
736 }
737 var dirPath = link.getPath();
738 if (path)
739 dirPath = relative(path, dirPath);
740 if (dirPath && isEmpty) {
741 json[dirPath] = null;
742 }
743 return json;
744 };
745 Volume.prototype.toJSON = function (paths, json, isRelative) {
746 if (json === void 0) { json = {}; }
747 if (isRelative === void 0) { isRelative = false; }
748 var links = [];
749 if (paths) {
750 if (!(paths instanceof Array))
751 paths = [paths];
752 for (var _i = 0, paths_1 = paths; _i < paths_1.length; _i++) {
753 var path = paths_1[_i];
754 var filename = pathToFilename(path);
755 var link = this.getResolvedLink(filename);
756 if (!link)
757 continue;
758 links.push(link);
759 }
760 }
761 else {
762 links.push(this.root);
763 }
764 if (!links.length)
765 return json;
766 for (var _a = 0, links_1 = links; _a < links_1.length; _a++) {
767 var link = links_1[_a];
768 this._toJSON(link, json, isRelative ? link.getPath() : '');
769 }
770 return json;
771 };
772 Volume.prototype.fromJSON = function (json, cwd) {
773 if (cwd === void 0) { cwd = process_1.default.cwd(); }
774 for (var filename in json) {
775 var data = json[filename];
776 filename = resolve(filename, cwd);
777 if (typeof data === 'string') {
778 var dir = dirname(filename);
779 this.mkdirpBase(dir, 511 /* MODE.DIR */);
780 this.writeFileSync(filename, data);
781 }
782 else {
783 this.mkdirpBase(filename, 511 /* MODE.DIR */);
784 }
785 }
786 };
787 Volume.prototype.fromNestedJSON = function (json, cwd) {
788 this.fromJSON(flattenJSON(json), cwd);
789 };
790 Volume.prototype.reset = function () {
791 this.ino = 0;
792 this.inodes = {};
793 this.releasedInos = [];
794 this.fds = {};
795 this.releasedFds = [];
796 this.openFiles = 0;
797 this.root = this.createLink();
798 this.root.setNode(this.createNode(true));
799 };
800 // Legacy interface
801 Volume.prototype.mountSync = function (mountpoint, json) {
802 this.fromJSON(json, mountpoint);
803 };
804 Volume.prototype.openLink = function (link, flagsNum, resolveSymlinks) {
805 if (resolveSymlinks === void 0) { resolveSymlinks = true; }
806 if (this.openFiles >= this.maxFiles) {
807 // Too many open files.
808 throw createError(EMFILE, 'open', link.getPath());
809 }
810 // Resolve symlinks.
811 var realLink = link;
812 if (resolveSymlinks)
813 realLink = this.resolveSymlinks(link);
814 if (!realLink)
815 throw createError(ENOENT, 'open', link.getPath());
816 var node = realLink.getNode();
817 // Check whether node is a directory
818 if (node.isDirectory()) {
819 if ((flagsNum & (O_RDONLY | O_RDWR | O_WRONLY)) !== O_RDONLY)
820 throw createError(EISDIR, 'open', link.getPath());
821 }
822 else {
823 if (flagsNum & O_DIRECTORY)
824 throw createError(ENOTDIR, 'open', link.getPath());
825 }
826 // Check node permissions
827 if (!(flagsNum & O_WRONLY)) {
828 if (!node.canRead()) {
829 throw createError(EACCES, 'open', link.getPath());
830 }
831 }
832 if (flagsNum & O_RDWR) {
833 }
834 var file = new this.props.File(link, node, flagsNum, this.newFdNumber());
835 this.fds[file.fd] = file;
836 this.openFiles++;
837 if (flagsNum & O_TRUNC)
838 file.truncate();
839 return file;
840 };
841 Volume.prototype.openFile = function (filename, flagsNum, modeNum, resolveSymlinks) {
842 if (resolveSymlinks === void 0) { resolveSymlinks = true; }
843 var steps = filenameToSteps(filename);
844 var link = resolveSymlinks ? this.getResolvedLink(steps) : this.getLink(steps);
845 if (link && flagsNum & O_EXCL)
846 throw createError(EEXIST, 'open', filename);
847 // Try creating a new file, if it does not exist.
848 if (!link && flagsNum & O_CREAT) {
849 // const dirLink: Link = this.getLinkParent(steps);
850 var dirLink = this.getResolvedLink(steps.slice(0, steps.length - 1));
851 // if(!dirLink) throw createError(ENOENT, 'open', filename);
852 if (!dirLink)
853 throw createError(ENOENT, 'open', sep + steps.join(sep));
854 if (flagsNum & O_CREAT && typeof modeNum === 'number') {
855 link = this.createLink(dirLink, steps[steps.length - 1], false, modeNum);
856 }
857 }
858 if (link)
859 return this.openLink(link, flagsNum, resolveSymlinks);
860 throw createError(ENOENT, 'open', filename);
861 };
862 Volume.prototype.openBase = function (filename, flagsNum, modeNum, resolveSymlinks) {
863 if (resolveSymlinks === void 0) { resolveSymlinks = true; }
864 var file = this.openFile(filename, flagsNum, modeNum, resolveSymlinks);
865 if (!file)
866 throw createError(ENOENT, 'open', filename);
867 return file.fd;
868 };
869 Volume.prototype.openSync = function (path, flags, mode) {
870 if (mode === void 0) { mode = 438 /* MODE.DEFAULT */; }
871 // Validate (1) mode; (2) path; (3) flags - in that order.
872 var modeNum = modeToNumber(mode);
873 var fileName = pathToFilename(path);
874 var flagsNum = flagsToNumber(flags);
875 return this.openBase(fileName, flagsNum, modeNum);
876 };
877 Volume.prototype.open = function (path, flags, a, b) {
878 var mode = a;
879 var callback = b;
880 if (typeof a === 'function') {
881 mode = 438 /* MODE.DEFAULT */;
882 callback = a;
883 }
884 mode = mode || 438 /* MODE.DEFAULT */;
885 var modeNum = modeToNumber(mode);
886 var fileName = pathToFilename(path);
887 var flagsNum = flagsToNumber(flags);
888 this.wrapAsync(this.openBase, [fileName, flagsNum, modeNum], callback);
889 };
890 Volume.prototype.closeFile = function (file) {
891 if (!this.fds[file.fd])
892 return;
893 this.openFiles--;
894 delete this.fds[file.fd];
895 this.releasedFds.push(file.fd);
896 };
897 Volume.prototype.closeSync = function (fd) {
898 validateFd(fd);
899 var file = this.getFileByFdOrThrow(fd, 'close');
900 this.closeFile(file);
901 };
902 Volume.prototype.close = function (fd, callback) {
903 validateFd(fd);
904 this.wrapAsync(this.closeSync, [fd], callback);
905 };
906 Volume.prototype.openFileOrGetById = function (id, flagsNum, modeNum) {
907 if (typeof id === 'number') {
908 var file = this.fds[id];
909 if (!file)
910 throw createError(ENOENT);
911 return file;
912 }
913 else {
914 return this.openFile(pathToFilename(id), flagsNum, modeNum);
915 }
916 };
917 Volume.prototype.readBase = function (fd, buffer, offset, length, position) {
918 var file = this.getFileByFdOrThrow(fd);
919 return file.read(buffer, Number(offset), Number(length), position);
920 };
921 Volume.prototype.readSync = function (fd, buffer, offset, length, position) {
922 validateFd(fd);
923 return this.readBase(fd, buffer, offset, length, position);
924 };
925 Volume.prototype.read = function (fd, buffer, offset, length, position, callback) {
926 var _this = this;
927 validateCallback(callback);
928 // This `if` branch is from Node.js
929 if (length === 0) {
930 return process_1.default.nextTick(function () {
931 if (callback)
932 callback(null, 0, buffer);
933 });
934 }
935 (0, setImmediate_1.default)(function () {
936 try {
937 var bytes = _this.readBase(fd, buffer, offset, length, position);
938 callback(null, bytes, buffer);
939 }
940 catch (err) {
941 callback(err);
942 }
943 });
944 };
945 Volume.prototype.readFileBase = function (id, flagsNum, encoding) {
946 var result;
947 var isUserFd = typeof id === 'number';
948 var userOwnsFd = isUserFd && isFd(id);
949 var fd;
950 if (userOwnsFd)
951 fd = id;
952 else {
953 var filename = pathToFilename(id);
954 var steps = filenameToSteps(filename);
955 var link = this.getResolvedLink(steps);
956 if (link) {
957 var node = link.getNode();
958 if (node.isDirectory())
959 throw createError(EISDIR, 'open', link.getPath());
960 }
961 fd = this.openSync(id, flagsNum);
962 }
963 try {
964 result = bufferToEncoding(this.getFileByFdOrThrow(fd).getBuffer(), encoding);
965 }
966 finally {
967 if (!userOwnsFd) {
968 this.closeSync(fd);
969 }
970 }
971 return result;
972 };
973 Volume.prototype.readFileSync = function (file, options) {
974 var opts = getReadFileOptions(options);
975 var flagsNum = flagsToNumber(opts.flag);
976 return this.readFileBase(file, flagsNum, opts.encoding);
977 };
978 Volume.prototype.readFile = function (id, a, b) {
979 var _a = optsAndCbGenerator(getReadFileOptions)(a, b), opts = _a[0], callback = _a[1];
980 var flagsNum = flagsToNumber(opts.flag);
981 this.wrapAsync(this.readFileBase, [id, flagsNum, opts.encoding], callback);
982 };
983 Volume.prototype.writeBase = function (fd, buf, offset, length, position) {
984 var file = this.getFileByFdOrThrow(fd, 'write');
985 return file.write(buf, offset, length, position);
986 };
987 Volume.prototype.writeSync = function (fd, a, b, c, d) {
988 validateFd(fd);
989 var encoding;
990 var offset;
991 var length;
992 var position;
993 var isBuffer = typeof a !== 'string';
994 if (isBuffer) {
995 offset = (b || 0) | 0;
996 length = c;
997 position = d;
998 }
999 else {
1000 position = b;
1001 encoding = c;
1002 }
1003 var buf = dataToBuffer(a, encoding);
1004 if (isBuffer) {
1005 if (typeof length === 'undefined') {
1006 length = buf.length;
1007 }
1008 }
1009 else {
1010 offset = 0;
1011 length = buf.length;
1012 }
1013 return this.writeBase(fd, buf, offset, length, position);
1014 };
1015 Volume.prototype.write = function (fd, a, b, c, d, e) {
1016 var _this = this;
1017 validateFd(fd);
1018 var offset;
1019 var length;
1020 var position;
1021 var encoding;
1022 var callback;
1023 var tipa = typeof a;
1024 var tipb = typeof b;
1025 var tipc = typeof c;
1026 var tipd = typeof d;
1027 if (tipa !== 'string') {
1028 if (tipb === 'function') {
1029 callback = b;
1030 }
1031 else if (tipc === 'function') {
1032 offset = b | 0;
1033 callback = c;
1034 }
1035 else if (tipd === 'function') {
1036 offset = b | 0;
1037 length = c;
1038 callback = d;
1039 }
1040 else {
1041 offset = b | 0;
1042 length = c;
1043 position = d;
1044 callback = e;
1045 }
1046 }
1047 else {
1048 if (tipb === 'function') {
1049 callback = b;
1050 }
1051 else if (tipc === 'function') {
1052 position = b;
1053 callback = c;
1054 }
1055 else if (tipd === 'function') {
1056 position = b;
1057 encoding = c;
1058 callback = d;
1059 }
1060 }
1061 var buf = dataToBuffer(a, encoding);
1062 if (tipa !== 'string') {
1063 if (typeof length === 'undefined')
1064 length = buf.length;
1065 }
1066 else {
1067 offset = 0;
1068 length = buf.length;
1069 }
1070 var cb = validateCallback(callback);
1071 (0, setImmediate_1.default)(function () {
1072 try {
1073 var bytes = _this.writeBase(fd, buf, offset, length, position);
1074 if (tipa !== 'string') {
1075 cb(null, bytes, buf);
1076 }
1077 else {
1078 cb(null, bytes, a);
1079 }
1080 }
1081 catch (err) {
1082 cb(err);
1083 }
1084 });
1085 };
1086 Volume.prototype.writeFileBase = function (id, buf, flagsNum, modeNum) {
1087 // console.log('writeFileBase', id, buf, flagsNum, modeNum);
1088 // const node = this.getNodeByIdOrCreate(id, flagsNum, modeNum);
1089 // node.setBuffer(buf);
1090 var isUserFd = typeof id === 'number';
1091 var fd;
1092 if (isUserFd)
1093 fd = id;
1094 else {
1095 fd = this.openBase(pathToFilename(id), flagsNum, modeNum);
1096 // fd = this.openSync(id as PathLike, flagsNum, modeNum);
1097 }
1098 var offset = 0;
1099 var length = buf.length;
1100 var position = flagsNum & O_APPEND ? undefined : 0;
1101 try {
1102 while (length > 0) {
1103 var written = this.writeSync(fd, buf, offset, length, position);
1104 offset += written;
1105 length -= written;
1106 if (position !== undefined)
1107 position += written;
1108 }
1109 }
1110 finally {
1111 if (!isUserFd)
1112 this.closeSync(fd);
1113 }
1114 };
1115 Volume.prototype.writeFileSync = function (id, data, options) {
1116 var opts = getWriteFileOptions(options);
1117 var flagsNum = flagsToNumber(opts.flag);
1118 var modeNum = modeToNumber(opts.mode);
1119 var buf = dataToBuffer(data, opts.encoding);
1120 this.writeFileBase(id, buf, flagsNum, modeNum);
1121 };
1122 Volume.prototype.writeFile = function (id, data, a, b) {
1123 var options = a;
1124 var callback = b;
1125 if (typeof a === 'function') {
1126 options = writeFileDefaults;
1127 callback = a;
1128 }
1129 var cb = validateCallback(callback);
1130 var opts = getWriteFileOptions(options);
1131 var flagsNum = flagsToNumber(opts.flag);
1132 var modeNum = modeToNumber(opts.mode);
1133 var buf = dataToBuffer(data, opts.encoding);
1134 this.wrapAsync(this.writeFileBase, [id, buf, flagsNum, modeNum], cb);
1135 };
1136 Volume.prototype.linkBase = function (filename1, filename2) {
1137 var steps1 = filenameToSteps(filename1);
1138 var link1 = this.getLink(steps1);
1139 if (!link1)
1140 throw createError(ENOENT, 'link', filename1, filename2);
1141 var steps2 = filenameToSteps(filename2);
1142 // Check new link directory exists.
1143 var dir2 = this.getLinkParent(steps2);
1144 if (!dir2)
1145 throw createError(ENOENT, 'link', filename1, filename2);
1146 var name = steps2[steps2.length - 1];
1147 // Check if new file already exists.
1148 if (dir2.getChild(name))
1149 throw createError(EEXIST, 'link', filename1, filename2);
1150 var node = link1.getNode();
1151 node.nlink++;
1152 dir2.createChild(name, node);
1153 };
1154 Volume.prototype.copyFileBase = function (src, dest, flags) {
1155 var buf = this.readFileSync(src);
1156 if (flags & COPYFILE_EXCL) {
1157 if (this.existsSync(dest)) {
1158 throw createError(EEXIST, 'copyFile', src, dest);
1159 }
1160 }
1161 if (flags & COPYFILE_FICLONE_FORCE) {
1162 throw createError(ENOSYS, 'copyFile', src, dest);
1163 }
1164 this.writeFileBase(dest, buf, FLAGS.w, 438 /* MODE.DEFAULT */);
1165 };
1166 Volume.prototype.copyFileSync = function (src, dest, flags) {
1167 var srcFilename = pathToFilename(src);
1168 var destFilename = pathToFilename(dest);
1169 return this.copyFileBase(srcFilename, destFilename, (flags || 0) | 0);
1170 };
1171 Volume.prototype.copyFile = function (src, dest, a, b) {
1172 var srcFilename = pathToFilename(src);
1173 var destFilename = pathToFilename(dest);
1174 var flags;
1175 var callback;
1176 if (typeof a === 'function') {
1177 flags = 0;
1178 callback = a;
1179 }
1180 else {
1181 flags = a;
1182 callback = b;
1183 }
1184 validateCallback(callback);
1185 this.wrapAsync(this.copyFileBase, [srcFilename, destFilename, flags], callback);
1186 };
1187 Volume.prototype.linkSync = function (existingPath, newPath) {
1188 var existingPathFilename = pathToFilename(existingPath);
1189 var newPathFilename = pathToFilename(newPath);
1190 this.linkBase(existingPathFilename, newPathFilename);
1191 };
1192 Volume.prototype.link = function (existingPath, newPath, callback) {
1193 var existingPathFilename = pathToFilename(existingPath);
1194 var newPathFilename = pathToFilename(newPath);
1195 this.wrapAsync(this.linkBase, [existingPathFilename, newPathFilename], callback);
1196 };
1197 Volume.prototype.unlinkBase = function (filename) {
1198 var steps = filenameToSteps(filename);
1199 var link = this.getLink(steps);
1200 if (!link)
1201 throw createError(ENOENT, 'unlink', filename);
1202 // TODO: Check if it is file, dir, other...
1203 if (link.length)
1204 throw Error('Dir not empty...');
1205 this.deleteLink(link);
1206 var node = link.getNode();
1207 node.nlink--;
1208 // When all hard links to i-node are deleted, remove the i-node, too.
1209 if (node.nlink <= 0) {
1210 this.deleteNode(node);
1211 }
1212 };
1213 Volume.prototype.unlinkSync = function (path) {
1214 var filename = pathToFilename(path);
1215 this.unlinkBase(filename);
1216 };
1217 Volume.prototype.unlink = function (path, callback) {
1218 var filename = pathToFilename(path);
1219 this.wrapAsync(this.unlinkBase, [filename], callback);
1220 };
1221 Volume.prototype.symlinkBase = function (targetFilename, pathFilename) {
1222 var pathSteps = filenameToSteps(pathFilename);
1223 // Check if directory exists, where we about to create a symlink.
1224 var dirLink = this.getLinkParent(pathSteps);
1225 if (!dirLink)
1226 throw createError(ENOENT, 'symlink', targetFilename, pathFilename);
1227 var name = pathSteps[pathSteps.length - 1];
1228 // Check if new file already exists.
1229 if (dirLink.getChild(name))
1230 throw createError(EEXIST, 'symlink', targetFilename, pathFilename);
1231 // Create symlink.
1232 var symlink = dirLink.createChild(name);
1233 symlink.getNode().makeSymlink(filenameToSteps(targetFilename));
1234 return symlink;
1235 };
1236 // `type` argument works only on Windows.
1237 Volume.prototype.symlinkSync = function (target, path, type) {
1238 var targetFilename = pathToFilename(target);
1239 var pathFilename = pathToFilename(path);
1240 this.symlinkBase(targetFilename, pathFilename);
1241 };
1242 Volume.prototype.symlink = function (target, path, a, b) {
1243 var callback = validateCallback(typeof a === 'function' ? a : b);
1244 var targetFilename = pathToFilename(target);
1245 var pathFilename = pathToFilename(path);
1246 this.wrapAsync(this.symlinkBase, [targetFilename, pathFilename], callback);
1247 };
1248 Volume.prototype.realpathBase = function (filename, encoding) {
1249 var steps = filenameToSteps(filename);
1250 var realLink = this.getResolvedLink(steps);
1251 if (!realLink)
1252 throw createError(ENOENT, 'realpath', filename);
1253 return (0, encoding_1.strToEncoding)(realLink.getPath() || '/', encoding);
1254 };
1255 Volume.prototype.realpathSync = function (path, options) {
1256 return this.realpathBase(pathToFilename(path), getRealpathOptions(options).encoding);
1257 };
1258 Volume.prototype.realpath = function (path, a, b) {
1259 var _a = getRealpathOptsAndCb(a, b), opts = _a[0], callback = _a[1];
1260 var pathFilename = pathToFilename(path);
1261 this.wrapAsync(this.realpathBase, [pathFilename, opts.encoding], callback);
1262 };
1263 Volume.prototype.lstatBase = function (filename, bigint, throwIfNoEntry) {
1264 if (bigint === void 0) { bigint = false; }
1265 if (throwIfNoEntry === void 0) { throwIfNoEntry = false; }
1266 var link = this.getLink(filenameToSteps(filename));
1267 if (link) {
1268 return Stats_1.default.build(link.getNode(), bigint);
1269 }
1270 else if (!throwIfNoEntry) {
1271 return undefined;
1272 }
1273 else {
1274 throw createError(ENOENT, 'lstat', filename);
1275 }
1276 };
1277 Volume.prototype.lstatSync = function (path, options) {
1278 var _a = getStatOptions(options), _b = _a.throwIfNoEntry, throwIfNoEntry = _b === void 0 ? true : _b, _c = _a.bigint, bigint = _c === void 0 ? false : _c;
1279 return this.lstatBase(pathToFilename(path), bigint, throwIfNoEntry);
1280 };
1281 Volume.prototype.lstat = function (path, a, b) {
1282 var _a = getStatOptsAndCb(a, b), _b = _a[0], _c = _b.throwIfNoEntry, throwIfNoEntry = _c === void 0 ? true : _c, _d = _b.bigint, bigint = _d === void 0 ? false : _d, callback = _a[1];
1283 this.wrapAsync(this.lstatBase, [pathToFilename(path), bigint, throwIfNoEntry], callback);
1284 };
1285 Volume.prototype.statBase = function (filename, bigint, throwIfNoEntry) {
1286 if (bigint === void 0) { bigint = false; }
1287 if (throwIfNoEntry === void 0) { throwIfNoEntry = true; }
1288 var link = this.getResolvedLink(filenameToSteps(filename));
1289 if (link) {
1290 return Stats_1.default.build(link.getNode(), bigint);
1291 }
1292 else if (!throwIfNoEntry) {
1293 return undefined;
1294 }
1295 else {
1296 throw createError(ENOENT, 'stat', filename);
1297 }
1298 };
1299 Volume.prototype.statSync = function (path, options) {
1300 var _a = getStatOptions(options), _b = _a.bigint, bigint = _b === void 0 ? true : _b, _c = _a.throwIfNoEntry, throwIfNoEntry = _c === void 0 ? true : _c;
1301 return this.statBase(pathToFilename(path), bigint, throwIfNoEntry);
1302 };
1303 Volume.prototype.stat = function (path, a, b) {
1304 var _a = getStatOptsAndCb(a, b), _b = _a[0], _c = _b.bigint, bigint = _c === void 0 ? false : _c, _d = _b.throwIfNoEntry, throwIfNoEntry = _d === void 0 ? true : _d, callback = _a[1];
1305 this.wrapAsync(this.statBase, [pathToFilename(path), bigint, throwIfNoEntry], callback);
1306 };
1307 Volume.prototype.fstatBase = function (fd, bigint) {
1308 if (bigint === void 0) { bigint = false; }
1309 var file = this.getFileByFd(fd);
1310 if (!file)
1311 throw createError(EBADF, 'fstat');
1312 return Stats_1.default.build(file.node, bigint);
1313 };
1314 Volume.prototype.fstatSync = function (fd, options) {
1315 return this.fstatBase(fd, getStatOptions(options).bigint);
1316 };
1317 Volume.prototype.fstat = function (fd, a, b) {
1318 var _a = getStatOptsAndCb(a, b), opts = _a[0], callback = _a[1];
1319 this.wrapAsync(this.fstatBase, [fd, opts.bigint], callback);
1320 };
1321 Volume.prototype.renameBase = function (oldPathFilename, newPathFilename) {
1322 var link = this.getLink(filenameToSteps(oldPathFilename));
1323 if (!link)
1324 throw createError(ENOENT, 'rename', oldPathFilename, newPathFilename);
1325 // TODO: Check if it is directory, if non-empty, we cannot move it, right?
1326 var newPathSteps = filenameToSteps(newPathFilename);
1327 // Check directory exists for the new location.
1328 var newPathDirLink = this.getLinkParent(newPathSteps);
1329 if (!newPathDirLink)
1330 throw createError(ENOENT, 'rename', oldPathFilename, newPathFilename);
1331 // TODO: Also treat cases with directories and symbolic links.
1332 // TODO: See: http://man7.org/linux/man-pages/man2/rename.2.html
1333 // Remove hard link from old folder.
1334 var oldLinkParent = link.parent;
1335 if (oldLinkParent) {
1336 oldLinkParent.deleteChild(link);
1337 }
1338 // Rename should overwrite the new path, if that exists.
1339 var name = newPathSteps[newPathSteps.length - 1];
1340 link.name = name;
1341 link.steps = __spreadArray(__spreadArray([], newPathDirLink.steps, true), [name], false);
1342 newPathDirLink.setChild(link.getName(), link);
1343 };
1344 Volume.prototype.renameSync = function (oldPath, newPath) {
1345 var oldPathFilename = pathToFilename(oldPath);
1346 var newPathFilename = pathToFilename(newPath);
1347 this.renameBase(oldPathFilename, newPathFilename);
1348 };
1349 Volume.prototype.rename = function (oldPath, newPath, callback) {
1350 var oldPathFilename = pathToFilename(oldPath);
1351 var newPathFilename = pathToFilename(newPath);
1352 this.wrapAsync(this.renameBase, [oldPathFilename, newPathFilename], callback);
1353 };
1354 Volume.prototype.existsBase = function (filename) {
1355 return !!this.statBase(filename);
1356 };
1357 Volume.prototype.existsSync = function (path) {
1358 try {
1359 return this.existsBase(pathToFilename(path));
1360 }
1361 catch (err) {
1362 return false;
1363 }
1364 };
1365 Volume.prototype.exists = function (path, callback) {
1366 var _this = this;
1367 var filename = pathToFilename(path);
1368 if (typeof callback !== 'function')
1369 throw Error(ERRSTR.CB);
1370 (0, setImmediate_1.default)(function () {
1371 try {
1372 callback(_this.existsBase(filename));
1373 }
1374 catch (err) {
1375 callback(false);
1376 }
1377 });
1378 };
1379 Volume.prototype.accessBase = function (filename, mode) {
1380 var link = this.getLinkOrThrow(filename, 'access');
1381 // TODO: Verify permissions
1382 };
1383 Volume.prototype.accessSync = function (path, mode) {
1384 if (mode === void 0) { mode = F_OK; }
1385 var filename = pathToFilename(path);
1386 mode = mode | 0;
1387 this.accessBase(filename, mode);
1388 };
1389 Volume.prototype.access = function (path, a, b) {
1390 var mode = F_OK;
1391 var callback;
1392 if (typeof a !== 'function') {
1393 mode = a | 0; // cast to number
1394 callback = validateCallback(b);
1395 }
1396 else {
1397 callback = a;
1398 }
1399 var filename = pathToFilename(path);
1400 this.wrapAsync(this.accessBase, [filename, mode], callback);
1401 };
1402 Volume.prototype.appendFileSync = function (id, data, options) {
1403 if (options === void 0) { options = appendFileDefaults; }
1404 var opts = getAppendFileOpts(options);
1405 // force append behavior when using a supplied file descriptor
1406 if (!opts.flag || isFd(id))
1407 opts.flag = 'a';
1408 this.writeFileSync(id, data, opts);
1409 };
1410 Volume.prototype.appendFile = function (id, data, a, b) {
1411 var _a = getAppendFileOptsAndCb(a, b), opts = _a[0], callback = _a[1];
1412 // force append behavior when using a supplied file descriptor
1413 if (!opts.flag || isFd(id))
1414 opts.flag = 'a';
1415 this.writeFile(id, data, opts, callback);
1416 };
1417 Volume.prototype.readdirBase = function (filename, options) {
1418 var steps = filenameToSteps(filename);
1419 var link = this.getResolvedLink(steps);
1420 if (!link)
1421 throw createError(ENOENT, 'readdir', filename);
1422 var node = link.getNode();
1423 if (!node.isDirectory())
1424 throw createError(ENOTDIR, 'scandir', filename);
1425 if (options.withFileTypes) {
1426 var list_1 = [];
1427 for (var name_2 in link.children) {
1428 var child = link.getChild(name_2);
1429 if (!child || name_2 === '.' || name_2 === '..') {
1430 continue;
1431 }
1432 list_1.push(Dirent_1.default.build(child, options.encoding));
1433 }
1434 if (!isWin && options.encoding !== 'buffer')
1435 list_1.sort(function (a, b) {
1436 if (a.name < b.name)
1437 return -1;
1438 if (a.name > b.name)
1439 return 1;
1440 return 0;
1441 });
1442 return list_1;
1443 }
1444 var list = [];
1445 for (var name_3 in link.children) {
1446 if (name_3 === '.' || name_3 === '..') {
1447 continue;
1448 }
1449 list.push((0, encoding_1.strToEncoding)(name_3, options.encoding));
1450 }
1451 if (!isWin && options.encoding !== 'buffer')
1452 list.sort();
1453 return list;
1454 };
1455 Volume.prototype.readdirSync = function (path, options) {
1456 var opts = getReaddirOptions(options);
1457 var filename = pathToFilename(path);
1458 return this.readdirBase(filename, opts);
1459 };
1460 Volume.prototype.readdir = function (path, a, b) {
1461 var _a = getReaddirOptsAndCb(a, b), options = _a[0], callback = _a[1];
1462 var filename = pathToFilename(path);
1463 this.wrapAsync(this.readdirBase, [filename, options], callback);
1464 };
1465 Volume.prototype.readlinkBase = function (filename, encoding) {
1466 var link = this.getLinkOrThrow(filename, 'readlink');
1467 var node = link.getNode();
1468 if (!node.isSymlink())
1469 throw createError(EINVAL, 'readlink', filename);
1470 var str = sep + node.symlink.join(sep);
1471 return (0, encoding_1.strToEncoding)(str, encoding);
1472 };
1473 Volume.prototype.readlinkSync = function (path, options) {
1474 var opts = getDefaultOpts(options);
1475 var filename = pathToFilename(path);
1476 return this.readlinkBase(filename, opts.encoding);
1477 };
1478 Volume.prototype.readlink = function (path, a, b) {
1479 var _a = getDefaultOptsAndCb(a, b), opts = _a[0], callback = _a[1];
1480 var filename = pathToFilename(path);
1481 this.wrapAsync(this.readlinkBase, [filename, opts.encoding], callback);
1482 };
1483 Volume.prototype.fsyncBase = function (fd) {
1484 this.getFileByFdOrThrow(fd, 'fsync');
1485 };
1486 Volume.prototype.fsyncSync = function (fd) {
1487 this.fsyncBase(fd);
1488 };
1489 Volume.prototype.fsync = function (fd, callback) {
1490 this.wrapAsync(this.fsyncBase, [fd], callback);
1491 };
1492 Volume.prototype.fdatasyncBase = function (fd) {
1493 this.getFileByFdOrThrow(fd, 'fdatasync');
1494 };
1495 Volume.prototype.fdatasyncSync = function (fd) {
1496 this.fdatasyncBase(fd);
1497 };
1498 Volume.prototype.fdatasync = function (fd, callback) {
1499 this.wrapAsync(this.fdatasyncBase, [fd], callback);
1500 };
1501 Volume.prototype.ftruncateBase = function (fd, len) {
1502 var file = this.getFileByFdOrThrow(fd, 'ftruncate');
1503 file.truncate(len);
1504 };
1505 Volume.prototype.ftruncateSync = function (fd, len) {
1506 this.ftruncateBase(fd, len);
1507 };
1508 Volume.prototype.ftruncate = function (fd, a, b) {
1509 var len = typeof a === 'number' ? a : 0;
1510 var callback = validateCallback(typeof a === 'number' ? b : a);
1511 this.wrapAsync(this.ftruncateBase, [fd, len], callback);
1512 };
1513 Volume.prototype.truncateBase = function (path, len) {
1514 var fd = this.openSync(path, 'r+');
1515 try {
1516 this.ftruncateSync(fd, len);
1517 }
1518 finally {
1519 this.closeSync(fd);
1520 }
1521 };
1522 Volume.prototype.truncateSync = function (id, len) {
1523 if (isFd(id))
1524 return this.ftruncateSync(id, len);
1525 this.truncateBase(id, len);
1526 };
1527 Volume.prototype.truncate = function (id, a, b) {
1528 var len = typeof a === 'number' ? a : 0;
1529 var callback = validateCallback(typeof a === 'number' ? b : a);
1530 if (isFd(id))
1531 return this.ftruncate(id, len, callback);
1532 this.wrapAsync(this.truncateBase, [id, len], callback);
1533 };
1534 Volume.prototype.futimesBase = function (fd, atime, mtime) {
1535 var file = this.getFileByFdOrThrow(fd, 'futimes');
1536 var node = file.node;
1537 node.atime = new Date(atime * 1000);
1538 node.mtime = new Date(mtime * 1000);
1539 };
1540 Volume.prototype.futimesSync = function (fd, atime, mtime) {
1541 this.futimesBase(fd, toUnixTimestamp(atime), toUnixTimestamp(mtime));
1542 };
1543 Volume.prototype.futimes = function (fd, atime, mtime, callback) {
1544 this.wrapAsync(this.futimesBase, [fd, toUnixTimestamp(atime), toUnixTimestamp(mtime)], callback);
1545 };
1546 Volume.prototype.utimesBase = function (filename, atime, mtime) {
1547 var fd = this.openSync(filename, 'r');
1548 try {
1549 this.futimesBase(fd, atime, mtime);
1550 }
1551 finally {
1552 this.closeSync(fd);
1553 }
1554 };
1555 Volume.prototype.utimesSync = function (path, atime, mtime) {
1556 this.utimesBase(pathToFilename(path), toUnixTimestamp(atime), toUnixTimestamp(mtime));
1557 };
1558 Volume.prototype.utimes = function (path, atime, mtime, callback) {
1559 this.wrapAsync(this.utimesBase, [pathToFilename(path), toUnixTimestamp(atime), toUnixTimestamp(mtime)], callback);
1560 };
1561 Volume.prototype.mkdirBase = function (filename, modeNum) {
1562 var steps = filenameToSteps(filename);
1563 // This will throw if user tries to create root dir `fs.mkdirSync('/')`.
1564 if (!steps.length) {
1565 throw createError(EEXIST, 'mkdir', filename);
1566 }
1567 var dir = this.getLinkParentAsDirOrThrow(filename, 'mkdir');
1568 // Check path already exists.
1569 var name = steps[steps.length - 1];
1570 if (dir.getChild(name))
1571 throw createError(EEXIST, 'mkdir', filename);
1572 dir.createChild(name, this.createNode(true, modeNum));
1573 };
1574 /**
1575 * Creates directory tree recursively.
1576 * @param filename
1577 * @param modeNum
1578 */
1579 Volume.prototype.mkdirpBase = function (filename, modeNum) {
1580 var fullPath = resolve(filename);
1581 var fullPathSansSlash = fullPath.substring(1);
1582 var steps = !fullPathSansSlash ? [] : fullPathSansSlash.split(sep);
1583 var link = this.root;
1584 var created = false;
1585 for (var i = 0; i < steps.length; i++) {
1586 var step = steps[i];
1587 if (!link.getNode().isDirectory())
1588 throw createError(ENOTDIR, 'mkdir', link.getPath());
1589 var child = link.getChild(step);
1590 if (child) {
1591 if (child.getNode().isDirectory())
1592 link = child;
1593 else
1594 throw createError(ENOTDIR, 'mkdir', child.getPath());
1595 }
1596 else {
1597 link = link.createChild(step, this.createNode(true, modeNum));
1598 created = true;
1599 }
1600 }
1601 return created ? fullPath : undefined;
1602 };
1603 Volume.prototype.mkdirSync = function (path, options) {
1604 var opts = getMkdirOptions(options);
1605 var modeNum = modeToNumber(opts.mode, 511);
1606 var filename = pathToFilename(path);
1607 if (opts.recursive)
1608 return this.mkdirpBase(filename, modeNum);
1609 this.mkdirBase(filename, modeNum);
1610 };
1611 Volume.prototype.mkdir = function (path, a, b) {
1612 var opts = getMkdirOptions(a);
1613 var callback = validateCallback(typeof a === 'function' ? a : b);
1614 var modeNum = modeToNumber(opts.mode, 511);
1615 var filename = pathToFilename(path);
1616 if (opts.recursive)
1617 this.wrapAsync(this.mkdirpBase, [filename, modeNum], callback);
1618 else
1619 this.wrapAsync(this.mkdirBase, [filename, modeNum], callback);
1620 };
1621 // legacy interface
1622 Volume.prototype.mkdirpSync = function (path, mode) {
1623 return this.mkdirSync(path, { mode: mode, recursive: true });
1624 };
1625 Volume.prototype.mkdirp = function (path, a, b) {
1626 var mode = typeof a === 'function' ? undefined : a;
1627 var callback = validateCallback(typeof a === 'function' ? a : b);
1628 this.mkdir(path, { mode: mode, recursive: true }, callback);
1629 };
1630 Volume.prototype.mkdtempBase = function (prefix, encoding, retry) {
1631 if (retry === void 0) { retry = 5; }
1632 var filename = prefix + this.genRndStr();
1633 try {
1634 this.mkdirBase(filename, 511 /* MODE.DIR */);
1635 return (0, encoding_1.strToEncoding)(filename, encoding);
1636 }
1637 catch (err) {
1638 if (err.code === EEXIST) {
1639 if (retry > 1)
1640 return this.mkdtempBase(prefix, encoding, retry - 1);
1641 else
1642 throw Error('Could not create temp dir.');
1643 }
1644 else
1645 throw err;
1646 }
1647 };
1648 Volume.prototype.mkdtempSync = function (prefix, options) {
1649 var encoding = getDefaultOpts(options).encoding;
1650 if (!prefix || typeof prefix !== 'string')
1651 throw new TypeError('filename prefix is required');
1652 nullCheck(prefix);
1653 return this.mkdtempBase(prefix, encoding);
1654 };
1655 Volume.prototype.mkdtemp = function (prefix, a, b) {
1656 var _a = getDefaultOptsAndCb(a, b), encoding = _a[0].encoding, callback = _a[1];
1657 if (!prefix || typeof prefix !== 'string')
1658 throw new TypeError('filename prefix is required');
1659 if (!nullCheck(prefix))
1660 return;
1661 this.wrapAsync(this.mkdtempBase, [prefix, encoding], callback);
1662 };
1663 Volume.prototype.rmdirBase = function (filename, options) {
1664 var opts = getRmdirOptions(options);
1665 var link = this.getLinkAsDirOrThrow(filename, 'rmdir');
1666 // Check directory is empty.
1667 if (link.length && !opts.recursive)
1668 throw createError(ENOTEMPTY, 'rmdir', filename);
1669 this.deleteLink(link);
1670 };
1671 Volume.prototype.rmdirSync = function (path, options) {
1672 this.rmdirBase(pathToFilename(path), options);
1673 };
1674 Volume.prototype.rmdir = function (path, a, b) {
1675 var opts = getRmdirOptions(a);
1676 var callback = validateCallback(typeof a === 'function' ? a : b);
1677 this.wrapAsync(this.rmdirBase, [pathToFilename(path), opts], callback);
1678 };
1679 Volume.prototype.rmBase = function (filename, options) {
1680 if (options === void 0) { options = {}; }
1681 var link = this.getResolvedLink(filename);
1682 if (!link) {
1683 // "stat" is used to match Node's native error message.
1684 if (!options.force)
1685 throw createError(ENOENT, 'stat', filename);
1686 return;
1687 }
1688 if (link.getNode().isDirectory()) {
1689 if (!options.recursive) {
1690 throw createError(ERR_FS_EISDIR, 'rm', filename);
1691 }
1692 }
1693 this.deleteLink(link);
1694 };
1695 Volume.prototype.rmSync = function (path, options) {
1696 this.rmBase(pathToFilename(path), options);
1697 };
1698 Volume.prototype.rm = function (path, a, b) {
1699 var _a = getRmOptsAndCb(a, b), opts = _a[0], callback = _a[1];
1700 this.wrapAsync(this.rmBase, [pathToFilename(path), opts], callback);
1701 };
1702 Volume.prototype.fchmodBase = function (fd, modeNum) {
1703 var file = this.getFileByFdOrThrow(fd, 'fchmod');
1704 file.chmod(modeNum);
1705 };
1706 Volume.prototype.fchmodSync = function (fd, mode) {
1707 this.fchmodBase(fd, modeToNumber(mode));
1708 };
1709 Volume.prototype.fchmod = function (fd, mode, callback) {
1710 this.wrapAsync(this.fchmodBase, [fd, modeToNumber(mode)], callback);
1711 };
1712 Volume.prototype.chmodBase = function (filename, modeNum) {
1713 var fd = this.openSync(filename, 'r');
1714 try {
1715 this.fchmodBase(fd, modeNum);
1716 }
1717 finally {
1718 this.closeSync(fd);
1719 }
1720 };
1721 Volume.prototype.chmodSync = function (path, mode) {
1722 var modeNum = modeToNumber(mode);
1723 var filename = pathToFilename(path);
1724 this.chmodBase(filename, modeNum);
1725 };
1726 Volume.prototype.chmod = function (path, mode, callback) {
1727 var modeNum = modeToNumber(mode);
1728 var filename = pathToFilename(path);
1729 this.wrapAsync(this.chmodBase, [filename, modeNum], callback);
1730 };
1731 Volume.prototype.lchmodBase = function (filename, modeNum) {
1732 var fd = this.openBase(filename, O_RDWR, 0, false);
1733 try {
1734 this.fchmodBase(fd, modeNum);
1735 }
1736 finally {
1737 this.closeSync(fd);
1738 }
1739 };
1740 Volume.prototype.lchmodSync = function (path, mode) {
1741 var modeNum = modeToNumber(mode);
1742 var filename = pathToFilename(path);
1743 this.lchmodBase(filename, modeNum);
1744 };
1745 Volume.prototype.lchmod = function (path, mode, callback) {
1746 var modeNum = modeToNumber(mode);
1747 var filename = pathToFilename(path);
1748 this.wrapAsync(this.lchmodBase, [filename, modeNum], callback);
1749 };
1750 Volume.prototype.fchownBase = function (fd, uid, gid) {
1751 this.getFileByFdOrThrow(fd, 'fchown').chown(uid, gid);
1752 };
1753 Volume.prototype.fchownSync = function (fd, uid, gid) {
1754 validateUid(uid);
1755 validateGid(gid);
1756 this.fchownBase(fd, uid, gid);
1757 };
1758 Volume.prototype.fchown = function (fd, uid, gid, callback) {
1759 validateUid(uid);
1760 validateGid(gid);
1761 this.wrapAsync(this.fchownBase, [fd, uid, gid], callback);
1762 };
1763 Volume.prototype.chownBase = function (filename, uid, gid) {
1764 var link = this.getResolvedLinkOrThrow(filename, 'chown');
1765 var node = link.getNode();
1766 node.chown(uid, gid);
1767 // if(node.isFile() || node.isSymlink()) {
1768 //
1769 // } else if(node.isDirectory()) {
1770 //
1771 // } else {
1772 // TODO: What do we do here?
1773 // }
1774 };
1775 Volume.prototype.chownSync = function (path, uid, gid) {
1776 validateUid(uid);
1777 validateGid(gid);
1778 this.chownBase(pathToFilename(path), uid, gid);
1779 };
1780 Volume.prototype.chown = function (path, uid, gid, callback) {
1781 validateUid(uid);
1782 validateGid(gid);
1783 this.wrapAsync(this.chownBase, [pathToFilename(path), uid, gid], callback);
1784 };
1785 Volume.prototype.lchownBase = function (filename, uid, gid) {
1786 this.getLinkOrThrow(filename, 'lchown').getNode().chown(uid, gid);
1787 };
1788 Volume.prototype.lchownSync = function (path, uid, gid) {
1789 validateUid(uid);
1790 validateGid(gid);
1791 this.lchownBase(pathToFilename(path), uid, gid);
1792 };
1793 Volume.prototype.lchown = function (path, uid, gid, callback) {
1794 validateUid(uid);
1795 validateGid(gid);
1796 this.wrapAsync(this.lchownBase, [pathToFilename(path), uid, gid], callback);
1797 };
1798 Volume.prototype.watchFile = function (path, a, b) {
1799 var filename = pathToFilename(path);
1800 var options = a;
1801 var listener = b;
1802 if (typeof options === 'function') {
1803 listener = a;
1804 options = null;
1805 }
1806 if (typeof listener !== 'function') {
1807 throw Error('"watchFile()" requires a listener function');
1808 }
1809 var interval = 5007;
1810 var persistent = true;
1811 if (options && typeof options === 'object') {
1812 if (typeof options.interval === 'number')
1813 interval = options.interval;
1814 if (typeof options.persistent === 'boolean')
1815 persistent = options.persistent;
1816 }
1817 var watcher = this.statWatchers[filename];
1818 if (!watcher) {
1819 watcher = new this.StatWatcher();
1820 watcher.start(filename, persistent, interval);
1821 this.statWatchers[filename] = watcher;
1822 }
1823 watcher.addListener('change', listener);
1824 return watcher;
1825 };
1826 Volume.prototype.unwatchFile = function (path, listener) {
1827 var filename = pathToFilename(path);
1828 var watcher = this.statWatchers[filename];
1829 if (!watcher)
1830 return;
1831 if (typeof listener === 'function') {
1832 watcher.removeListener('change', listener);
1833 }
1834 else {
1835 watcher.removeAllListeners('change');
1836 }
1837 if (watcher.listenerCount('change') === 0) {
1838 watcher.stop();
1839 delete this.statWatchers[filename];
1840 }
1841 };
1842 Volume.prototype.createReadStream = function (path, options) {
1843 return new this.ReadStream(path, options);
1844 };
1845 Volume.prototype.createWriteStream = function (path, options) {
1846 return new this.WriteStream(path, options);
1847 };
1848 // watch(path: PathLike): FSWatcher;
1849 // watch(path: PathLike, options?: IWatchOptions | string): FSWatcher;
1850 Volume.prototype.watch = function (path, options, listener) {
1851 var filename = pathToFilename(path);
1852 var givenOptions = options;
1853 if (typeof options === 'function') {
1854 listener = options;
1855 givenOptions = null;
1856 }
1857 // tslint:disable-next-line prefer-const
1858 var _a = getDefaultOpts(givenOptions), persistent = _a.persistent, recursive = _a.recursive, encoding = _a.encoding;
1859 if (persistent === undefined)
1860 persistent = true;
1861 if (recursive === undefined)
1862 recursive = false;
1863 var watcher = new this.FSWatcher();
1864 watcher.start(filename, persistent, recursive, encoding);
1865 if (listener) {
1866 watcher.addListener('change', listener);
1867 }
1868 return watcher;
1869 };
1870 /**
1871 * Global file descriptor counter. UNIX file descriptors start from 0 and go sequentially
1872 * up, so here, in order not to conflict with them, we choose some big number and descrease
1873 * the file descriptor of every new opened file.
1874 * @type {number}
1875 * @todo This should not be static, right?
1876 */
1877 Volume.fd = 0x7fffffff;
1878 return Volume;
1879}());
1880exports.Volume = Volume;
1881function emitStop(self) {
1882 self.emit('stop');
1883}
1884var StatWatcher = /** @class */ (function (_super) {
1885 __extends(StatWatcher, _super);
1886 function StatWatcher(vol) {
1887 var _this = _super.call(this) || this;
1888 _this.onInterval = function () {
1889 try {
1890 var stats = _this.vol.statSync(_this.filename);
1891 if (_this.hasChanged(stats)) {
1892 _this.emit('change', stats, _this.prev);
1893 _this.prev = stats;
1894 }
1895 }
1896 finally {
1897 _this.loop();
1898 }
1899 };
1900 _this.vol = vol;
1901 return _this;
1902 }
1903 StatWatcher.prototype.loop = function () {
1904 this.timeoutRef = this.setTimeout(this.onInterval, this.interval);
1905 };
1906 StatWatcher.prototype.hasChanged = function (stats) {
1907 // if(!this.prev) return false;
1908 if (stats.mtimeMs > this.prev.mtimeMs)
1909 return true;
1910 if (stats.nlink !== this.prev.nlink)
1911 return true;
1912 return false;
1913 };
1914 StatWatcher.prototype.start = function (path, persistent, interval) {
1915 if (persistent === void 0) { persistent = true; }
1916 if (interval === void 0) { interval = 5007; }
1917 this.filename = pathToFilename(path);
1918 this.setTimeout = persistent
1919 ? setTimeout.bind(typeof globalThis !== 'undefined' ? globalThis : global)
1920 : setTimeoutUnref_1.default;
1921 this.interval = interval;
1922 this.prev = this.vol.statSync(this.filename);
1923 this.loop();
1924 };
1925 StatWatcher.prototype.stop = function () {
1926 clearTimeout(this.timeoutRef);
1927 process_1.default.nextTick(emitStop, this);
1928 };
1929 return StatWatcher;
1930}(events_1.EventEmitter));
1931exports.StatWatcher = StatWatcher;
1932var pool;
1933function allocNewPool(poolSize) {
1934 pool = (0, buffer_1.bufferAllocUnsafe)(poolSize);
1935 pool.used = 0;
1936}
1937util.inherits(FsReadStream, stream_1.Readable);
1938exports.ReadStream = FsReadStream;
1939function FsReadStream(vol, path, options) {
1940 if (!(this instanceof FsReadStream))
1941 return new FsReadStream(vol, path, options);
1942 this._vol = vol;
1943 // a little bit bigger buffer and water marks by default
1944 options = Object.assign({}, getOptions(options, {}));
1945 if (options.highWaterMark === undefined)
1946 options.highWaterMark = 64 * 1024;
1947 stream_1.Readable.call(this, options);
1948 this.path = pathToFilename(path);
1949 this.fd = options.fd === undefined ? null : options.fd;
1950 this.flags = options.flags === undefined ? 'r' : options.flags;
1951 this.mode = options.mode === undefined ? 438 : options.mode;
1952 this.start = options.start;
1953 this.end = options.end;
1954 this.autoClose = options.autoClose === undefined ? true : options.autoClose;
1955 this.pos = undefined;
1956 this.bytesRead = 0;
1957 if (this.start !== undefined) {
1958 if (typeof this.start !== 'number') {
1959 throw new TypeError('"start" option must be a Number');
1960 }
1961 if (this.end === undefined) {
1962 this.end = Infinity;
1963 }
1964 else if (typeof this.end !== 'number') {
1965 throw new TypeError('"end" option must be a Number');
1966 }
1967 if (this.start > this.end) {
1968 throw new Error('"start" option must be <= "end" option');
1969 }
1970 this.pos = this.start;
1971 }
1972 if (typeof this.fd !== 'number')
1973 this.open();
1974 this.on('end', function () {
1975 if (this.autoClose) {
1976 if (this.destroy)
1977 this.destroy();
1978 }
1979 });
1980}
1981FsReadStream.prototype.open = function () {
1982 var self = this; // tslint:disable-line no-this-assignment
1983 this._vol.open(this.path, this.flags, this.mode, function (er, fd) {
1984 if (er) {
1985 if (self.autoClose) {
1986 if (self.destroy)
1987 self.destroy();
1988 }
1989 self.emit('error', er);
1990 return;
1991 }
1992 self.fd = fd;
1993 self.emit('open', fd);
1994 // start the flow of data.
1995 self.read();
1996 });
1997};
1998FsReadStream.prototype._read = function (n) {
1999 if (typeof this.fd !== 'number') {
2000 return this.once('open', function () {
2001 this._read(n);
2002 });
2003 }
2004 if (this.destroyed)
2005 return;
2006 if (!pool || pool.length - pool.used < kMinPoolSpace) {
2007 // discard the old pool.
2008 allocNewPool(this._readableState.highWaterMark);
2009 }
2010 // Grab another reference to the pool in the case that while we're
2011 // in the thread pool another read() finishes up the pool, and
2012 // allocates a new one.
2013 var thisPool = pool;
2014 var toRead = Math.min(pool.length - pool.used, n);
2015 var start = pool.used;
2016 if (this.pos !== undefined)
2017 toRead = Math.min(this.end - this.pos + 1, toRead);
2018 // already read everything we were supposed to read!
2019 // treat as EOF.
2020 if (toRead <= 0)
2021 return this.push(null);
2022 // the actual read.
2023 var self = this; // tslint:disable-line no-this-assignment
2024 this._vol.read(this.fd, pool, pool.used, toRead, this.pos, onread);
2025 // move the pool positions, and internal position for reading.
2026 if (this.pos !== undefined)
2027 this.pos += toRead;
2028 pool.used += toRead;
2029 function onread(er, bytesRead) {
2030 if (er) {
2031 if (self.autoClose && self.destroy) {
2032 self.destroy();
2033 }
2034 self.emit('error', er);
2035 }
2036 else {
2037 var b = null;
2038 if (bytesRead > 0) {
2039 self.bytesRead += bytesRead;
2040 b = thisPool.slice(start, start + bytesRead);
2041 }
2042 self.push(b);
2043 }
2044 }
2045};
2046FsReadStream.prototype._destroy = function (err, cb) {
2047 this.close(function (err2) {
2048 cb(err || err2);
2049 });
2050};
2051FsReadStream.prototype.close = function (cb) {
2052 var _this = this;
2053 var _a;
2054 if (cb)
2055 this.once('close', cb);
2056 if (this.closed || typeof this.fd !== 'number') {
2057 if (typeof this.fd !== 'number') {
2058 this.once('open', closeOnOpen);
2059 return;
2060 }
2061 return process_1.default.nextTick(function () { return _this.emit('close'); });
2062 }
2063 // Since Node 18, there is only a getter for '.closed'.
2064 // The first branch mimics other setters from Readable.
2065 // See https://github.com/nodejs/node/blob/v18.0.0/lib/internal/streams/readable.js#L1243
2066 if (typeof ((_a = this._readableState) === null || _a === void 0 ? void 0 : _a.closed) === 'boolean') {
2067 this._readableState.closed = true;
2068 }
2069 else {
2070 this.closed = true;
2071 }
2072 this._vol.close(this.fd, function (er) {
2073 if (er)
2074 _this.emit('error', er);
2075 else
2076 _this.emit('close');
2077 });
2078 this.fd = null;
2079};
2080// needed because as it will be called with arguments
2081// that does not match this.close() signature
2082function closeOnOpen(fd) {
2083 this.close();
2084}
2085util.inherits(FsWriteStream, stream_1.Writable);
2086exports.WriteStream = FsWriteStream;
2087function FsWriteStream(vol, path, options) {
2088 if (!(this instanceof FsWriteStream))
2089 return new FsWriteStream(vol, path, options);
2090 this._vol = vol;
2091 options = Object.assign({}, getOptions(options, {}));
2092 stream_1.Writable.call(this, options);
2093 this.path = pathToFilename(path);
2094 this.fd = options.fd === undefined ? null : options.fd;
2095 this.flags = options.flags === undefined ? 'w' : options.flags;
2096 this.mode = options.mode === undefined ? 438 : options.mode;
2097 this.start = options.start;
2098 this.autoClose = options.autoClose === undefined ? true : !!options.autoClose;
2099 this.pos = undefined;
2100 this.bytesWritten = 0;
2101 if (this.start !== undefined) {
2102 if (typeof this.start !== 'number') {
2103 throw new TypeError('"start" option must be a Number');
2104 }
2105 if (this.start < 0) {
2106 throw new Error('"start" must be >= zero');
2107 }
2108 this.pos = this.start;
2109 }
2110 if (options.encoding)
2111 this.setDefaultEncoding(options.encoding);
2112 if (typeof this.fd !== 'number')
2113 this.open();
2114 // dispose on finish.
2115 this.once('finish', function () {
2116 if (this.autoClose) {
2117 this.close();
2118 }
2119 });
2120}
2121FsWriteStream.prototype.open = function () {
2122 this._vol.open(this.path, this.flags, this.mode, function (er, fd) {
2123 if (er) {
2124 if (this.autoClose && this.destroy) {
2125 this.destroy();
2126 }
2127 this.emit('error', er);
2128 return;
2129 }
2130 this.fd = fd;
2131 this.emit('open', fd);
2132 }.bind(this));
2133};
2134FsWriteStream.prototype._write = function (data, encoding, cb) {
2135 if (!(data instanceof buffer_1.Buffer || data instanceof Uint8Array))
2136 return this.emit('error', new Error('Invalid data'));
2137 if (typeof this.fd !== 'number') {
2138 return this.once('open', function () {
2139 this._write(data, encoding, cb);
2140 });
2141 }
2142 var self = this; // tslint:disable-line no-this-assignment
2143 this._vol.write(this.fd, data, 0, data.length, this.pos, function (er, bytes) {
2144 if (er) {
2145 if (self.autoClose && self.destroy) {
2146 self.destroy();
2147 }
2148 return cb(er);
2149 }
2150 self.bytesWritten += bytes;
2151 cb();
2152 });
2153 if (this.pos !== undefined)
2154 this.pos += data.length;
2155};
2156FsWriteStream.prototype._writev = function (data, cb) {
2157 if (typeof this.fd !== 'number') {
2158 return this.once('open', function () {
2159 this._writev(data, cb);
2160 });
2161 }
2162 var self = this; // tslint:disable-line no-this-assignment
2163 var len = data.length;
2164 var chunks = new Array(len);
2165 var size = 0;
2166 for (var i = 0; i < len; i++) {
2167 var chunk = data[i].chunk;
2168 chunks[i] = chunk;
2169 size += chunk.length;
2170 }
2171 var buf = buffer_1.Buffer.concat(chunks);
2172 this._vol.write(this.fd, buf, 0, buf.length, this.pos, function (er, bytes) {
2173 if (er) {
2174 if (self.destroy)
2175 self.destroy();
2176 return cb(er);
2177 }
2178 self.bytesWritten += bytes;
2179 cb();
2180 });
2181 if (this.pos !== undefined)
2182 this.pos += size;
2183};
2184FsWriteStream.prototype.close = function (cb) {
2185 var _this = this;
2186 var _a;
2187 if (cb)
2188 this.once('close', cb);
2189 if (this.closed || typeof this.fd !== 'number') {
2190 if (typeof this.fd !== 'number') {
2191 this.once('open', closeOnOpen);
2192 return;
2193 }
2194 return process_1.default.nextTick(function () { return _this.emit('close'); });
2195 }
2196 // Since Node 18, there is only a getter for '.closed'.
2197 // The first branch mimics other setters from Writable.
2198 // See https://github.com/nodejs/node/blob/v18.0.0/lib/internal/streams/writable.js#L766
2199 if (typeof ((_a = this._writableState) === null || _a === void 0 ? void 0 : _a.closed) === 'boolean') {
2200 this._writableState.closed = true;
2201 }
2202 else {
2203 this.closed = true;
2204 }
2205 this._vol.close(this.fd, function (er) {
2206 if (er)
2207 _this.emit('error', er);
2208 else
2209 _this.emit('close');
2210 });
2211 this.fd = null;
2212};
2213FsWriteStream.prototype._destroy = FsReadStream.prototype._destroy;
2214// There is no shutdown() for files.
2215FsWriteStream.prototype.destroySoon = FsWriteStream.prototype.end;
2216// ---------------------------------------- FSWatcher
2217var FSWatcher = /** @class */ (function (_super) {
2218 __extends(FSWatcher, _super);
2219 function FSWatcher(vol) {
2220 var _this = _super.call(this) || this;
2221 _this._filename = '';
2222 _this._filenameEncoded = '';
2223 // _persistent: boolean = true;
2224 _this._recursive = false;
2225 _this._encoding = encoding_1.ENCODING_UTF8;
2226 // inode -> removers
2227 _this._listenerRemovers = new Map();
2228 _this._onParentChild = function (link) {
2229 if (link.getName() === _this._getName()) {
2230 _this._emit('rename');
2231 }
2232 };
2233 _this._emit = function (type) {
2234 _this.emit('change', type, _this._filenameEncoded);
2235 };
2236 _this._persist = function () {
2237 _this._timer = setTimeout(_this._persist, 1e6);
2238 };
2239 _this._vol = vol;
2240 return _this;
2241 // TODO: Emit "error" messages when watching.
2242 // this._handle.onchange = function(status, eventType, filename) {
2243 // if (status < 0) {
2244 // self._handle.close();
2245 // const error = !filename ?
2246 // errnoException(status, 'Error watching file for changes:') :
2247 // errnoException(status, `Error watching file ${filename} for changes:`);
2248 // error.filename = filename;
2249 // self.emit('error', error);
2250 // } else {
2251 // self.emit('change', eventType, filename);
2252 // }
2253 // };
2254 }
2255 FSWatcher.prototype._getName = function () {
2256 return this._steps[this._steps.length - 1];
2257 };
2258 FSWatcher.prototype.start = function (path, persistent, recursive, encoding) {
2259 var _this = this;
2260 if (persistent === void 0) { persistent = true; }
2261 if (recursive === void 0) { recursive = false; }
2262 if (encoding === void 0) { encoding = encoding_1.ENCODING_UTF8; }
2263 this._filename = pathToFilename(path);
2264 this._steps = filenameToSteps(this._filename);
2265 this._filenameEncoded = (0, encoding_1.strToEncoding)(this._filename);
2266 // this._persistent = persistent;
2267 this._recursive = recursive;
2268 this._encoding = encoding;
2269 try {
2270 this._link = this._vol.getLinkOrThrow(this._filename, 'FSWatcher');
2271 }
2272 catch (err) {
2273 var error = new Error("watch ".concat(this._filename, " ").concat(err.code));
2274 error.code = err.code;
2275 error.errno = err.code;
2276 throw error;
2277 }
2278 var watchLinkNodeChanged = function (link) {
2279 var _a;
2280 var filepath = link.getPath();
2281 var node = link.getNode();
2282 var onNodeChange = function () {
2283 var filename = relative(_this._filename, filepath);
2284 if (!filename) {
2285 filename = _this._getName();
2286 }
2287 return _this.emit('change', 'change', filename);
2288 };
2289 node.on('change', onNodeChange);
2290 var removers = (_a = _this._listenerRemovers.get(node.ino)) !== null && _a !== void 0 ? _a : [];
2291 removers.push(function () { return node.removeListener('change', onNodeChange); });
2292 _this._listenerRemovers.set(node.ino, removers);
2293 };
2294 var watchLinkChildrenChanged = function (link) {
2295 var _a;
2296 var node = link.getNode();
2297 // when a new link added
2298 var onLinkChildAdd = function (l) {
2299 _this.emit('change', 'rename', relative(_this._filename, l.getPath()));
2300 setTimeout(function () {
2301 // 1. watch changes of the new link-node
2302 watchLinkNodeChanged(l);
2303 // 2. watch changes of the new link-node's children
2304 watchLinkChildrenChanged(l);
2305 });
2306 };
2307 // when a new link deleted
2308 var onLinkChildDelete = function (l) {
2309 // remove the listeners of the children nodes
2310 var removeLinkNodeListeners = function (curLink) {
2311 var ino = curLink.getNode().ino;
2312 var removers = _this._listenerRemovers.get(ino);
2313 if (removers) {
2314 removers.forEach(function (r) { return r(); });
2315 _this._listenerRemovers.delete(ino);
2316 }
2317 Object.values(curLink.children).forEach(function (childLink) {
2318 if (childLink) {
2319 removeLinkNodeListeners(childLink);
2320 }
2321 });
2322 };
2323 removeLinkNodeListeners(l);
2324 _this.emit('change', 'rename', relative(_this._filename, l.getPath()));
2325 };
2326 // children nodes changed
2327 Object.entries(link.children).forEach(function (_a) {
2328 var name = _a[0], childLink = _a[1];
2329 if (childLink && name !== '.' && name !== '..') {
2330 watchLinkNodeChanged(childLink);
2331 }
2332 });
2333 // link children add/remove
2334 link.on('child:add', onLinkChildAdd);
2335 link.on('child:delete', onLinkChildDelete);
2336 var removers = (_a = _this._listenerRemovers.get(node.ino)) !== null && _a !== void 0 ? _a : [];
2337 removers.push(function () {
2338 link.removeListener('child:add', onLinkChildAdd);
2339 link.removeListener('child:delete', onLinkChildDelete);
2340 });
2341 if (recursive) {
2342 Object.entries(link.children).forEach(function (_a) {
2343 var name = _a[0], childLink = _a[1];
2344 if (childLink && name !== '.' && name !== '..') {
2345 watchLinkChildrenChanged(childLink);
2346 }
2347 });
2348 }
2349 };
2350 watchLinkNodeChanged(this._link);
2351 watchLinkChildrenChanged(this._link);
2352 var parent = this._link.parent;
2353 if (parent) {
2354 // parent.on('child:add', this._onParentChild);
2355 parent.setMaxListeners(parent.getMaxListeners() + 1);
2356 parent.on('child:delete', this._onParentChild);
2357 }
2358 if (persistent)
2359 this._persist();
2360 };
2361 FSWatcher.prototype.close = function () {
2362 clearTimeout(this._timer);
2363 this._listenerRemovers.forEach(function (removers) {
2364 removers.forEach(function (r) { return r(); });
2365 });
2366 this._listenerRemovers.clear();
2367 var parent = this._link.parent;
2368 if (parent) {
2369 // parent.removeListener('child:add', this._onParentChild);
2370 parent.removeListener('child:delete', this._onParentChild);
2371 }
2372 };
2373 return FSWatcher;
2374}(events_1.EventEmitter));
2375exports.FSWatcher = FSWatcher;
Note: See TracBrowser for help on using the repository browser.