UNPKG

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