blob: b0dc0d30d0f96020dc1298f3bb0d75121af8e7da [file] [log] [blame]
// Generated by //js/private/node-patches:compile
"use strict";
/**
* @license
* Copyright 2019 The Bazel Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __asyncValues = (this && this.__asyncValues) || function (o) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var m = o[Symbol.asyncIterator], i;
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var g = generator.apply(thisArg, _arguments || []), i, q = [];
return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
function fulfill(value) { resume("next", value); }
function reject(value) { resume("throw", value); }
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.patcher = patcher;
exports.isSubPath = isSubPath;
exports.escapeFunction = escapeFunction;
const path = require("path");
const util = require("util");
// using require here on purpose so we can override methods with any
// also even though imports are mutable in typescript the cognitive dissonance is too high because
// es modules
const fs = require('node:fs');
const url = require('node:url');
const esmModule = require('node:module');
const HOP_NON_LINK = Symbol.for('HOP NON LINK');
const HOP_NOT_FOUND = Symbol.for('HOP NOT FOUND');
const PATCHED_FS_METHODS = [
'lstat',
'lstatSync',
'realpath',
'realpathSync',
'readlink',
'readlinkSync',
'readdir',
'readdirSync',
'opendir',
];
/**
* Function that patches the `fs` module to not escape the given roots.
* @returns a function to undo the patches.
*/
function patcher(roots) {
if (fs._unpatched) {
throw new Error('FS is already patched.');
}
// Make the original version of the library available for when access to the
// unguarded file system is necessary, such as the esbuild plugin that
// protects against sandbox escaping that occurs through module resolution
// in the Go binary. See
// https://github.com/aspect-build/rules_esbuild/issues/58.
fs._unpatched = PATCHED_FS_METHODS.reduce((obj, method) => {
obj[method] = fs[method];
return obj;
}, {});
roots = roots || [];
roots = roots.filter((root) => fs.existsSync(root));
if (!roots.length) {
if (process.env.VERBOSE_LOGS) {
console.error('fs patcher called without any valid root paths ' + __filename);
}
return function () { };
}
const origLstat = fs.lstat.bind(fs);
const origLstatSync = fs.lstatSync.bind(fs);
const origReaddir = fs.readdir.bind(fs);
const origReaddirSync = fs.readdirSync.bind(fs);
const origReadlink = fs.readlink.bind(fs);
const origReadlinkSync = fs.readlinkSync.bind(fs);
const origRealpath = fs.realpath.bind(fs);
const origRealpathNative = fs.realpath
.native;
const origRealpathSync = fs.realpathSync.bind(fs);
const origRealpathSyncNative = fs.realpathSync
.native;
const { canEscape, isEscape } = escapeFunction(roots);
// =========================================================================
// fs.lstat
// =========================================================================
fs.lstat = function lstat(...args) {
// preserve error when calling function without required callback
if (typeof args[args.length - 1] !== 'function') {
return origLstat(...args);
}
const cb = once(args[args.length - 1]);
// override the callback
args[args.length - 1] = function lstatCb(err, stats) {
if (err)
return cb(err);
if (!stats.isSymbolicLink()) {
// the file is not a symbolic link so there is nothing more to do
return cb(null, stats);
}
args[0] = resolvePathLike(args[0]);
if (!canEscape(args[0])) {
// the file can not escaped the sandbox so there is nothing more to do
return cb(null, stats);
}
return guardedReadLink(args[0], guardedReadLinkCb);
function guardedReadLinkCb(str) {
if (str != args[0]) {
// there are one or more hops within the guards so there is nothing more to do
return cb(null, stats);
}
// there are no hops so lets report the stats of the real file;
// we can't use origRealPath here since that function calls lstat internally
// which can result in an infinite loop
return unguardedRealPath(args[0], unguardedRealPathCb);
function unguardedRealPathCb(err, str) {
if (err) {
if (err.code === 'ENOENT') {
// broken link so there is nothing more to do
return cb(null, stats);
}
return cb(err);
}
return origLstat(str, cb);
}
}
};
origLstat(...args);
};
fs.lstatSync = function lstatSync(...args) {
const stats = origLstatSync(...args);
if (!(stats === null || stats === void 0 ? void 0 : stats.isSymbolicLink())) {
// the file is not a symbolic link so there is nothing more to do
return stats;
}
args[0] = resolvePathLike(args[0]);
if (!canEscape(args[0])) {
// the file can not escaped the sandbox so there is nothing more to do
return stats;
}
const guardedReadLink = guardedReadLinkSync(args[0]);
if (guardedReadLink != args[0]) {
// there are one or more hops within the guards so there is nothing more to do
return stats;
}
try {
args[0] = unguardedRealPathSync(args[0]);
// there are no hops so lets report the stats of the real file;
// we can't use origRealPathSync here since that function calls lstat internally
// which can result in an infinite loop
return origLstatSync(...args);
}
catch (err) {
if (err.code === 'ENOENT') {
// broken link so there is nothing more to do
return stats;
}
throw err;
}
};
// =========================================================================
// fs.realpath
// =========================================================================
fs.realpath = function realpath(...args) {
// preserve error when calling function without required callback
if (typeof args[args.length - 1] !== 'function') {
return origRealpath(...args);
}
const cb = once(args[args.length - 1]);
args[args.length - 1] = function realpathCb(err, str) {
if (err)
return cb(err);
const escapedRoot = isEscape(args[0], str);
if (escapedRoot) {
return guardedRealPath(args[0], cb, escapedRoot);
}
else {
return cb(null, str);
}
};
origRealpath(...args);
};
fs.realpath.native = function realpath_native(...args) {
// preserve error when calling function without required callback
if (typeof args[args.length - 1] !== 'function') {
return origRealpathNative(...args);
}
const cb = once(args[args.length - 1]);
args[args.length - 1] = function nativeCb(err, str) {
if (err)
return cb(err);
const escapedRoot = isEscape(args[0], str);
if (escapedRoot) {
return guardedRealPath(args[0], cb, escapedRoot);
}
else {
return cb(null, str);
}
};
origRealpathNative(...args);
};
fs.realpathSync = function realpathSync(...args) {
const str = origRealpathSync(...args);
const escapedRoot = isEscape(args[0], str);
if (escapedRoot) {
return guardedRealPathSync(args[0], escapedRoot);
}
return str;
};
fs.realpathSync.native = function native_realpathSync(...args) {
const str = origRealpathSyncNative(...args);
const escapedRoot = isEscape(args[0], str);
if (escapedRoot) {
return guardedRealPathSync(args[0], escapedRoot);
}
return str;
};
// =========================================================================
// fs.readlink
// =========================================================================
fs.readlink = function readlink(...args) {
// preserve error when calling function without required callback
if (typeof args[args.length - 1] !== 'function') {
return origReadlink(...args);
}
const cb = once(args[args.length - 1]);
args[args.length - 1] = function readlinkCb(err, p) {
if (err)
return cb(err);
const resolved = resolvePathLike(args[0]);
const str = path.resolve(path.dirname(resolved), p);
const escapedRoot = isEscape(resolved, str);
if (escapedRoot) {
return nextHop(str, readlinkNextHopCb);
function readlinkNextHopCb(next) {
if (!next) {
if (next == undefined) {
// The escape from the root is not mappable back into the root; throw EINVAL
return cb(enoent('readlink', args[0]));
}
else {
// The escape from the root is not mappable back into the root; throw EINVAL
return cb(einval('readlink', args[0]));
}
}
const r = path.resolve(path.dirname(resolved), path.relative(path.dirname(str), next));
if (r != resolved &&
!isEscape(resolved, r, [escapedRoot])) {
return cb(null, r);
}
// The escape from the root is not mappable back into the root; throw EINVAL
return cb(einval('readlink', args[0]));
}
}
else {
return cb(null, str);
}
};
origReadlink(...args);
};
fs.readlinkSync = function readlinkSync(...args) {
const resolved = resolvePathLike(args[0]);
const str = path.resolve(path.dirname(resolved), origReadlinkSync(...args));
const escapedRoot = isEscape(resolved, str);
if (escapedRoot) {
const next = nextHopSync(str);
if (!next) {
if (next == undefined) {
// The escape from the root is not mappable back into the root; throw EINVAL
throw enoent('readlink', args[0]);
}
else {
// The escape from the root is not mappable back into the root; throw EINVAL
throw einval('readlink', args[0]);
}
}
const r = path.resolve(path.dirname(resolved), path.relative(path.dirname(str), next));
if (r != resolved && !isEscape(resolved, r, [escapedRoot])) {
return r;
}
// The escape from the root is not mappable back into the root; throw EINVAL
throw einval('readlink', args[0]);
}
return str;
};
// =========================================================================
// fs.readdir
// =========================================================================
fs.readdir = function readdir(...args) {
// preserve error when calling function without required callback
if (typeof args[args.length - 1] !== 'function') {
return origReaddir(...args);
}
const cb = once(args[args.length - 1]);
const p = resolvePathLike(args[0]);
args[args.length - 1] = function readdirCb(err, result) {
if (err)
return cb(err);
// user requested withFileTypes
if (result[0] && result[0].isSymbolicLink) {
Promise.all(result.map((v) => handleDirent(p, v)))
.then(() => {
cb(null, result);
})
.catch((err) => {
cb(err);
});
}
else {
// string array return for readdir.
cb(null, result);
}
};
origReaddir(...args);
};
fs.readdirSync = function readdirSync(...args) {
const res = origReaddirSync(...args);
const p = resolvePathLike(args[0]);
res.forEach((v) => {
handleDirentSync(p, v);
});
return res;
};
// =========================================================================
// fs.opendir
// =========================================================================
if (fs.opendir) {
const origOpendir = fs.opendir.bind(fs);
fs.opendir = function opendir(...args) {
// if this is not a function opendir should throw an error.
// we call it so we don't have to throw a mock
if (typeof args[args.length - 1] === 'function') {
const cb = once(args[args.length - 1]);
args[args.length - 1] = async function opendirCb(err, dir) {
try {
cb(err, err ? undefined : handleDir(dir));
}
catch (err) {
cb(err);
}
};
origOpendir(...args);
}
else {
return origOpendir(...args).then(handleDir);
}
};
}
if (fs.opendirSync) {
const origOpendirSync = fs.opendirSync.bind(fs);
fs.opendirSync = function opendirSync(...args) {
const dir = origOpendirSync(...args);
return handleDir(dir);
};
}
// =========================================================================
// fs.promises
// =========================================================================
/**
* patch fs.promises here.
*
* this requires a light touch because if we trigger the getter on older nodejs versions
* it will log an experimental warning to stderr
*
* `(node:62945) ExperimentalWarning: The fs.promises API is experimental`
*
* this api is available as experimental without a flag so users can access it at any time.
*/
const promisePropertyDescriptor = Object.getOwnPropertyDescriptor(fs, 'promises');
let unpatchPromises;
if (promisePropertyDescriptor) {
const promises = {};
promises.lstat = util.promisify(fs.lstat);
// NOTE: node core uses the newer realpath function fs.promises.native instead of fs.realPath
promises.realpath = util.promisify(fs.realpath.native);
promises.readlink = util.promisify(fs.readlink);
promises.readdir = util.promisify(fs.readdir);
if (fs.opendir)
promises.opendir = util.promisify(fs.opendir);
// handle experimental api warnings.
// only applies to version of node where promises is a getter property.
if (promisePropertyDescriptor.get) {
const oldGetter = promisePropertyDescriptor.get.bind(fs);
const cachedPromises = {};
function promisePropertyGetter() {
const _promises = oldGetter();
Object.assign(cachedPromises, _promises, promises);
return cachedPromises;
}
Object.defineProperty(fs, 'promises', Object.assign(Object.create(promisePropertyDescriptor), {
get: promisePropertyGetter,
}));
unpatchPromises = function unpatchFsPromises() {
Object.defineProperty(fs, 'promises', promisePropertyDescriptor);
};
}
else {
const unpatchedPromises = Object.keys(promises).reduce((obj, method) => {
obj[method] = fs.promises[method];
return obj;
}, Object.create(fs.promises));
// api can be patched directly
Object.assign(fs.promises, promises);
unpatchPromises = function unpatchFsPromises() {
Object.assign(fs.promises, unpatchedPromises);
};
}
}
// =========================================================================
// helper functions for dirs
// =========================================================================
function handleDir(dir) {
const p = path.resolve(dir.path);
const origIterator = dir[Symbol.asyncIterator].bind(dir);
dir[Symbol.asyncIterator] = function () {
return __asyncGenerator(this, arguments, function* () {
var _a, e_1, _b, _c;
try {
for (var _d = true, _f = __asyncValues(origIterator()), _g; _g = yield __await(_f.next()), _a = _g.done, !_a; _d = true) {
_c = _g.value;
_d = false;
const entry = _c;
yield __await(handleDirent(p, entry));
yield yield __await(entry);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (!_d && !_a && (_b = _f.return)) yield __await(_b.call(_f));
}
finally { if (e_1) throw e_1.error; }
}
});
};
const origRead = dir.read.bind(dir);
dir.read = function readWrapper() {
if (typeof arguments[0] === 'function') {
return handleDirReadCallback(arguments[0]);
}
else {
return handleDirReadPromise();
}
};
// read(cb: (err: NodeJS.ErrnoException | null, dirEnt: Dirent | null) => void): void;
function handleDirReadCallback(cb) {
origRead(function handleDirReadCb(err, entry) {
if (err)
return cb(err, null);
handleDirent(p, entry).then(() => {
cb(null, entry);
}, (err) => cb(err, null));
});
}
// read(): Promise<Dirent | null>;
async function handleDirReadPromise() {
const entry = await origRead();
if (entry) {
await handleDirent(p, entry);
}
return entry;
}
const origReadSync = dir.readSync.bind(dir);
dir.readSync = function handleDirReadSync() {
return handleDirentSync(p, origReadSync());
};
return dir;
}
async function handleDirent(p, v) {
if (!v.isSymbolicLink()) {
return v;
}
const f = path.resolve(p, v.name);
return new Promise(function handleDirentExecutor(resolve, reject) {
return guardedReadLink(f, handleDirentReadLinkCb);
function handleDirentReadLinkCb(str) {
if (f != str) {
return resolve(v);
}
// There are no hops so we should hide the fact that the file is a symlink
v.isSymbolicLink = () => false;
origRealpath(f, function handleDirentRealpathCb(err, str) {
if (err) {
return reject(err);
}
fs.stat(str, function handleDirentStatCb(err, stat) {
if (err) {
return reject(err);
}
patchDirent(v, stat);
resolve(v);
});
});
}
});
}
function handleDirentSync(p, v) {
if (v && v.isSymbolicLink) {
if (v.isSymbolicLink()) {
const f = path.resolve(p, v.name);
if (f == guardedReadLinkSync(f)) {
// There are no hops so we should hide the fact that the file is a symlink
v.isSymbolicLink = () => false;
const stat = fs.statSync(origRealpathSync(f));
patchDirent(v, stat);
}
}
}
return v;
}
function nextHop(loc, cb) {
let nested = '';
let maybe = loc;
let escapedHop = false;
readHopLink(maybe, function readNextHop(link) {
if (link === HOP_NOT_FOUND) {
return cb(undefined);
}
if (link !== HOP_NON_LINK) {
if (nested) {
link = link + path.sep + nested;
}
if (!isEscape(loc, link)) {
return cb(link);
}
if (!escapedHop) {
escapedHop = link;
}
}
const dirname = path.dirname(maybe);
if (!dirname ||
dirname == maybe ||
dirname == '.' ||
dirname == '/') {
// not a link
return cb(escapedHop);
}
nested = path.basename(maybe) + (nested ? path.sep + nested : '');
maybe = dirname;
readHopLink(maybe, readNextHop);
});
}
const symlinkNoThrow = Object.freeze({
throwIfNoEntry: false,
});
const hopLinkCache = Object.create(null);
function readHopLinkSync(p) {
if (hopLinkCache[p]) {
return hopLinkCache[p];
}
let link;
const pStats = origLstatSync(p, symlinkNoThrow);
if (!pStats) {
link = HOP_NOT_FOUND;
}
else if (pStats.isSymbolicLink()) {
link = origReadlinkSync(p);
if (link) {
if (!path.isAbsolute(link)) {
link = path.resolve(path.dirname(p), link);
}
}
else {
link = HOP_NON_LINK;
}
}
else {
link = HOP_NON_LINK;
}
hopLinkCache[p] = link;
return link;
}
function readHopLink(p, cb) {
if (hopLinkCache[p]) {
return cb(hopLinkCache[p]);
}
origReadlink(p, function readHopLinkCb(err, link) {
if (err) {
let result;
if (err.code === 'ENOENT') {
// file does not exist
result = HOP_NOT_FOUND;
}
else {
result = HOP_NON_LINK;
}
hopLinkCache[p] = result;
return cb(result);
}
if (link === undefined) {
hopLinkCache[p] = HOP_NON_LINK;
return cb(HOP_NON_LINK);
}
if (!path.isAbsolute(link)) {
link = path.resolve(path.dirname(p), link);
}
hopLinkCache[p] = link;
cb(link);
});
}
function nextHopSync(loc) {
let nested = '';
let maybe = loc;
let escapedHop = false;
for (;;) {
let link = readHopLinkSync(maybe);
if (link === HOP_NOT_FOUND) {
return false;
}
if (link !== HOP_NON_LINK) {
if (nested) {
link = link + path.sep + nested;
}
if (!isEscape(loc, link)) {
return link;
}
if (!escapedHop) {
escapedHop = link;
}
}
const dirname = path.dirname(maybe);
if (!dirname ||
dirname == maybe ||
dirname == '.' ||
dirname == '/') {
// not a link
return escapedHop;
}
nested = path.basename(maybe) + (nested ? path.sep + nested : '');
maybe = dirname;
}
}
function guardedReadLink(loc, cb) {
nextHop(loc, guardedReadLinkHopCb);
function guardedReadLinkHopCb(next) {
if (!next) {
// we're no longer hopping but we haven't escaped;
// something funky happened in the filesystem
return cb(loc);
}
if (isEscape(loc, next)) {
// this hop takes us out of the guard
return cb(loc);
}
return cb(next);
}
}
function guardedReadLinkSync(loc) {
const next = nextHopSync(loc);
if (!next) {
// we're no longer hopping but we haven't escaped;
// something funky happened in the filesystem
return loc;
}
if (isEscape(loc, next)) {
// this hop takes us out of the guard
return loc;
}
return next;
}
function unguardedRealPath(start, cb) {
// stringifyPathLike() to handle the "undefined" case (matches behavior as fs.realpath)
oneHop(stringifyPathLike(start), cb);
function oneHop(loc, cb) {
nextHop(loc, function oneHopeNextCb(next) {
if (next == undefined) {
// file does not exist (broken link)
return cb(enoent('realpath', start), undefined);
}
else if (!next) {
// we've hit a real file
return cb(null, loc);
}
oneHop(next, cb);
});
}
}
function guardedRealPath(start, cb, escapedRoot) {
// stringifyPathLike() to handle the "undefined" case (matches behavior as fs.realpath)
oneHop(stringifyPathLike(start), cb);
function oneHop(loc, cb) {
nextHop(loc, function guardedRealPathHopCb(next) {
if (!next) {
return cb(enoent('realpath', start), undefined);
}
if (escapedRoot
? isEscape(loc, next, [escapedRoot])
: isEscape(loc, next)) {
// this hop takes us out of the guard
return cb(null, loc);
}
oneHop(next, cb);
});
}
}
function unguardedRealPathSync(start) {
// stringifyPathLike() to handle the "undefined" case (matches behavior as fs.realpathSync)
for (let loc = stringifyPathLike(start), next;; loc = next) {
next = nextHopSync(loc);
if (next == undefined) {
// file does not exist (broken link)
throw enoent('realpath', start);
}
else if (!next) {
// we've hit a real file
return loc;
}
}
}
function guardedRealPathSync(start, escapedRoot) {
// stringifyPathLike() to handle the "undefined" case (matches behavior as fs.realpathSync)
for (let loc = stringifyPathLike(start), next;; loc = next) {
next = nextHopSync(loc);
if (!next) {
// we're no longer hopping but we haven't escaped
if (fs.existsSync(loc)) {
// we hit a real file within the guard and can go no further
return loc;
}
else {
// something funky happened in the filesystem; throw ENOENT
throw enoent('realpath', start);
}
}
if (escapedRoot
? isEscape(loc, next, [escapedRoot])
: isEscape(loc, next)) {
// this hop takes us out of the guard
return loc;
}
}
}
// Sync the esm modules to use the now patched fs cjs module.
// See: https://nodejs.org/api/esm.html#builtin-modules
esmModule.syncBuiltinESMExports();
return function revertPatch() {
Object.assign(fs, fs._unpatched);
delete fs._unpatched;
if (unpatchPromises) {
unpatchPromises();
}
// Re-sync the esm modules to revert to the unpatched module.
esmModule.syncBuiltinESMExports();
};
}
// =========================================================================
// generic helper functions
// =========================================================================
function isSubPath(parent, child) {
return (parent === child ||
(child[parent.length] === path.sep && child.startsWith(parent)));
}
function stringifyPathLike(p) {
if (p instanceof URL) {
return url.fileURLToPath(p);
}
else {
return String(p);
}
}
function resolvePathLike(p) {
return path.resolve(stringifyPathLike(p));
}
function normalizePathLike(p) {
const s = stringifyPathLike(p);
// TODO: are URLs always absolute?
if (!path.isAbsolute(s)) {
return path.resolve(s);
}
else {
return path.normalize(s);
}
}
function escapeFunction(_roots) {
// Ensure roots are always absolute.
// Sort to ensure escaping multiple roots chooses the longest one.
const defaultRoots = _roots
.map((root) => path.resolve(root))
.sort((a, b) => b.length - a.length);
function fs_isEscape(linkPath, linkTarget, roots = defaultRoots) {
// linkPath is the path of the symlink file itself
// linkTarget is a path that the symlink points to one or more hops away
// linkTarget must already be normalized
linkPath = normalizePathLike(linkPath);
for (const root of roots) {
// If the link is in the root check if the realPath has escaped
if (isSubPath(root, linkPath) && !isSubPath(root, linkTarget)) {
return root;
}
}
return false;
}
function fs_canEscape(maybeLinkPath, roots = defaultRoots) {
// maybeLinkPath is the path which may be a symlink
// maybeLinkPath must already be normalized
for (const root of roots) {
// If the link is in the root check if the realPath has escaped
if (isSubPath(root, maybeLinkPath)) {
return true;
}
}
return false;
}
return {
isEscape: fs_isEscape,
canEscape: fs_canEscape,
};
}
function once(fn) {
let called = false;
return function callOnce(...args) {
if (called)
return;
called = true;
let err = false;
try {
fn(...args);
}
catch (_e) {
err = _e;
}
// blow the stack to make sure this doesn't fall into any unresolved promise contexts
if (err) {
setImmediate(() => {
throw err;
});
}
};
}
function patchDirent(dirent, stat) {
// add all stat is methods to Dirent instances with their result.
for (const i in stat) {
if (i.startsWith('is') && typeof stat[i] === 'function') {
//
const result = stat[i]();
if (result)
dirent[i] = () => true;
else
dirent[i] = () => false;
}
}
}
function enoent(s, p) {
let err = new Error(`ENOENT: no such file or directory, ${s} '${p}'`);
err.errno = -2;
err.syscall = s;
err.code = 'ENOENT';
err.path = p;
return err;
}
function einval(s, p) {
let err = new Error(`EINVAL: invalid argument, ${s} '${p}'`);
err.errno = -22;
err.syscall = s;
err.code = 'EINVAL';
err.path = p;
return err;
}