mirror of
https://github.com/tiennm99/FBcount.git
synced 2026-05-14 16:58:10 +00:00
1578 lines
48 KiB
JavaScript
1578 lines
48 KiB
JavaScript
/* eslint-disable curly */
|
|
/* eslint-disable new-cap */
|
|
/* eslint-disable no-buffer-constructor */
|
|
/* eslint-disable no-multi-spaces */
|
|
/* eslint-disable no-underscore-dangle */
|
|
/* eslint-disable prefer-rest-params */
|
|
/* eslint-disable prefer-spread */
|
|
|
|
/* global EXECPATH_FD */
|
|
/* global PAYLOAD_POSITION */
|
|
/* global PAYLOAD_SIZE */
|
|
/* global REQUIRE_COMMON */
|
|
/* global VIRTUAL_FILESYSTEM */
|
|
/* global DEFAULT_ENTRYPOINT */
|
|
|
|
'use strict';
|
|
|
|
var common = {};
|
|
REQUIRE_COMMON(common);
|
|
|
|
var STORE_BLOB = common.STORE_BLOB;
|
|
var STORE_CONTENT = common.STORE_CONTENT;
|
|
var STORE_LINKS = common.STORE_LINKS;
|
|
var STORE_STAT = common.STORE_STAT;
|
|
|
|
var normalizePath = common.normalizePath;
|
|
var insideSnapshot = common.insideSnapshot;
|
|
var stripSnapshot = common.stripSnapshot;
|
|
var removeUplevels = common.removeUplevels;
|
|
|
|
var FLAG_ENABLE_PROJECT = false;
|
|
var NODE_VERSION_MAJOR = process.version.match(/^v(\d+)/)[1] | 0;
|
|
|
|
// /////////////////////////////////////////////////////////////////
|
|
// ENTRYPOINT //////////////////////////////////////////////////////
|
|
// /////////////////////////////////////////////////////////////////
|
|
|
|
// set ENTRYPOINT and ARGV0 here because
|
|
// they can be altered during process run
|
|
var ARGV0 = process.argv[0];
|
|
var EXECPATH = process.execPath;
|
|
var ENTRYPOINT = process.argv[1];
|
|
|
|
if (process.env.PKG_EXECPATH === 'PKG_INVOKE_NODEJS') {
|
|
return { undoPatch: true };
|
|
}
|
|
|
|
if (NODE_VERSION_MAJOR < 12 || require('worker_threads').isMainThread) {
|
|
if (process.argv[1] !== 'PKG_DUMMY_ENTRYPOINT') {
|
|
// expand once patchless is introduced, that
|
|
// will obviously lack any work in node_main.cc
|
|
throw new Error('PKG_DUMMY_ENTRYPOINT EXPECTED');
|
|
}
|
|
}
|
|
|
|
if (process.env.PKG_EXECPATH === EXECPATH) {
|
|
process.argv.splice(1, 1);
|
|
|
|
if (process.argv[1] && process.argv[1] !== '-') {
|
|
// https://github.com/nodejs/node/blob/1a96d83a223ff9f05f7d942fb84440d323f7b596/lib/internal/bootstrap/node.js#L269
|
|
process.argv[1] = require('path').resolve(process.argv[1]);
|
|
}
|
|
} else {
|
|
process.argv[1] = DEFAULT_ENTRYPOINT;
|
|
}
|
|
|
|
ENTRYPOINT = process.argv[1];
|
|
delete process.env.PKG_EXECPATH;
|
|
|
|
// /////////////////////////////////////////////////////////////////
|
|
// EXECSTAT ////////////////////////////////////////////////////////
|
|
// /////////////////////////////////////////////////////////////////
|
|
|
|
var EXECSTAT = require('fs').statSync(EXECPATH);
|
|
EXECSTAT.atimeMs = EXECSTAT.atime.getTime();
|
|
EXECSTAT.mtimeMs = EXECSTAT.mtime.getTime();
|
|
EXECSTAT.ctimeMs = EXECSTAT.ctime.getTime();
|
|
EXECSTAT.birthtimeMs = EXECSTAT.birthtime.getTime();
|
|
|
|
// /////////////////////////////////////////////////////////////////
|
|
// MOUNTPOINTS /////////////////////////////////////////////////////
|
|
// /////////////////////////////////////////////////////////////////
|
|
|
|
var mountpoints = [];
|
|
|
|
function insideMountpoint (f) {
|
|
if (!insideSnapshot(f)) return null;
|
|
var file = normalizePath(f);
|
|
var found = mountpoints.map(function (mountpoint) {
|
|
var interior = mountpoint.interior;
|
|
var exterior = mountpoint.exterior;
|
|
if (interior === file) return exterior;
|
|
var left = interior + require('path').sep;
|
|
if (file.slice(0, left.length) !== left) return null;
|
|
return exterior + file.slice(left.length - 1);
|
|
}).filter(function (result) {
|
|
return result;
|
|
});
|
|
if (found.length >= 2) throw new Error('UNEXPECTED-00');
|
|
if (found.length === 0) return null;
|
|
return found[0];
|
|
}
|
|
|
|
function readdirMountpoints (path) {
|
|
return mountpoints.map(function (mountpoint) {
|
|
return mountpoint.interior;
|
|
}).filter(function (interior) {
|
|
return require('path').dirname(interior) === path;
|
|
}).map(function (interior) {
|
|
return require('path').basename(interior);
|
|
});
|
|
}
|
|
|
|
function translate (f) {
|
|
var result = insideMountpoint(f);
|
|
if (!result) throw new Error('UNEXPECTED-05');
|
|
return result;
|
|
}
|
|
|
|
function cloneArgs (args_) {
|
|
return Array.prototype.slice.call(args_);
|
|
}
|
|
|
|
function translateNth (args_, index, f) {
|
|
var args = cloneArgs(args_);
|
|
args[index] = translate(f);
|
|
return args;
|
|
}
|
|
|
|
function createMountpoint (interior, exterior) {
|
|
// TODO validate
|
|
mountpoints.push({ interior: interior, exterior: exterior });
|
|
}
|
|
|
|
/*
|
|
|
|
// TODO move to some test
|
|
|
|
createMountpoint("d:\\snapshot\\countly\\plugins-ext", "d:\\deploy\\countly\\v16.02\\plugins-ext");
|
|
|
|
console.log(insideMountpoint("d:\\snapshot"));
|
|
console.log(insideMountpoint("d:\\snapshot\\"));
|
|
console.log(insideMountpoint("d:\\snapshot\\countly"));
|
|
console.log(insideMountpoint("d:\\snapshot\\countly\\"));
|
|
console.log(insideMountpoint("d:\\snapshot\\countly\\plugins-ext"));
|
|
console.log(insideMountpoint("d:\\snapshot\\countly\\plugins-ext\\"));
|
|
console.log(insideMountpoint("d:\\snapshot\\countly\\plugins-ext\\1234"));
|
|
|
|
console.log(translate("d:\\snapshot\\countly\\plugins-ext"));
|
|
console.log(translate("d:\\snapshot\\countly\\plugins-ext\\"));
|
|
console.log(translate("d:\\snapshot\\countly\\plugins-ext\\1234"));
|
|
|
|
console.log(translateNth([], 0, "d:\\snapshot\\countly\\plugins-ext"));
|
|
console.log(translateNth([], 0, "d:\\snapshot\\countly\\plugins-ext\\"));
|
|
console.log(translateNth([], 0, "d:\\snapshot\\countly\\plugins-ext\\1234"));
|
|
|
|
console.log(translateNth(["", "r+"], 0, "d:\\snapshot\\countly\\plugins-ext"));
|
|
console.log(translateNth(["", "rw"], 0, "d:\\snapshot\\countly\\plugins-ext\\"));
|
|
console.log(translateNth(["", "a+"], 0, "d:\\snapshot\\countly\\plugins-ext\\1234"));
|
|
*/
|
|
|
|
// /////////////////////////////////////////////////////////////////
|
|
// PROJECT /////////////////////////////////////////////////////////
|
|
// /////////////////////////////////////////////////////////////////
|
|
|
|
function isRootPath (p) {
|
|
if (p === '.') p = require('path').resolve(p);
|
|
return require('path').dirname(p) === p;
|
|
}
|
|
|
|
function projectToFilesystem (f) {
|
|
var xpdn = require('path').dirname(
|
|
EXECPATH
|
|
);
|
|
|
|
var relatives = [];
|
|
relatives.push(
|
|
removeUplevels(
|
|
require('path').relative(
|
|
require('path').dirname(
|
|
DEFAULT_ENTRYPOINT
|
|
), f
|
|
)
|
|
)
|
|
);
|
|
|
|
if (relatives[0].slice(0, 'node_modules'.length) === 'node_modules') {
|
|
// one more relative without starting 'node_modules'
|
|
relatives.push(relatives[0].slice('node_modules'.length + 1));
|
|
}
|
|
|
|
var uplevels = [];
|
|
var maxUplevels = xpdn.split(require('path').sep).length;
|
|
for (var i = 0, u = ''; i < maxUplevels; i += 1) {
|
|
uplevels.push(u);
|
|
u += '/..';
|
|
}
|
|
|
|
var results = [];
|
|
uplevels.forEach(function (uplevel) {
|
|
relatives.forEach(function (relative) {
|
|
results.push(require('path').join(
|
|
xpdn,
|
|
uplevel,
|
|
relative
|
|
));
|
|
});
|
|
});
|
|
return results;
|
|
}
|
|
|
|
function projectToNearby (f) {
|
|
return require('path').join(
|
|
require('path').dirname(
|
|
EXECPATH
|
|
),
|
|
require('path').basename(
|
|
f
|
|
)
|
|
);
|
|
}
|
|
|
|
function findNativeAddonSyncFreeFromRequire (path) {
|
|
if (!insideSnapshot(path)) throw new Error('UNEXPECTED-10');
|
|
if (path.slice(-5) !== '.node') return null; // leveldown.node.js
|
|
// check mearby first to prevent .node tampering
|
|
var projector = projectToNearby(path);
|
|
if (require('fs').existsSync(projector)) return projector;
|
|
var projectors = projectToFilesystem(path);
|
|
for (var i = 0; i < projectors.length; i += 1) {
|
|
if (require('fs').existsSync(projectors[i])) return projectors[i];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function findNativeAddonSyncUnderRequire (path) {
|
|
if (!FLAG_ENABLE_PROJECT) return null;
|
|
return findNativeAddonSyncFreeFromRequire(path);
|
|
}
|
|
|
|
// /////////////////////////////////////////////////////////////////
|
|
// FLOW UTILS //////////////////////////////////////////////////////
|
|
// /////////////////////////////////////////////////////////////////
|
|
|
|
function asap (cb) {
|
|
process.nextTick(cb);
|
|
}
|
|
|
|
function dezalgo (cb) {
|
|
if (!cb) return cb;
|
|
|
|
var sync = true;
|
|
asap(function () {
|
|
sync = false;
|
|
});
|
|
|
|
return function zalgoSafe () {
|
|
var args = arguments;
|
|
if (sync) {
|
|
asap(function () {
|
|
cb.apply(undefined, args);
|
|
});
|
|
} else {
|
|
cb.apply(undefined, args);
|
|
}
|
|
};
|
|
}
|
|
|
|
function rethrow (error, arg) {
|
|
if (error) throw error;
|
|
return arg;
|
|
}
|
|
|
|
// /////////////////////////////////////////////////////////////////
|
|
// PAYLOAD /////////////////////////////////////////////////////////
|
|
// /////////////////////////////////////////////////////////////////
|
|
|
|
if (typeof PAYLOAD_POSITION !== 'number' ||
|
|
typeof PAYLOAD_SIZE !== 'number') {
|
|
throw new Error('MUST HAVE PAYLOAD');
|
|
}
|
|
|
|
var readPayload = function (buffer, offset, length, position, callback) {
|
|
require('fs').read(EXECPATH_FD,
|
|
buffer, offset, length, PAYLOAD_POSITION + position, callback);
|
|
};
|
|
|
|
var readPayloadSync = function (buffer, offset, length, position) {
|
|
return require('fs').readSync(EXECPATH_FD,
|
|
buffer, offset, length, PAYLOAD_POSITION + position);
|
|
};
|
|
|
|
function payloadCopyUni (source, target, targetStart, sourceStart, sourceEnd, cb) {
|
|
var cb2 = cb || rethrow;
|
|
if (sourceStart >= source[1]) return cb2(null, 0);
|
|
if (sourceEnd >= source[1]) sourceEnd = source[1];
|
|
var payloadPos = source[0] + sourceStart;
|
|
var targetPos = targetStart;
|
|
var targetEnd = targetStart + sourceEnd - sourceStart;
|
|
if (cb) {
|
|
readPayload(target, targetPos, targetEnd - targetPos, payloadPos, cb);
|
|
} else {
|
|
return readPayloadSync(target, targetPos, targetEnd - targetPos, payloadPos);
|
|
}
|
|
}
|
|
|
|
function payloadCopyMany (source, target, targetStart, sourceStart, cb) {
|
|
var payloadPos = source[0] + sourceStart;
|
|
var targetPos = targetStart;
|
|
var targetEnd = targetStart + source[1] - sourceStart;
|
|
readPayload(target, targetPos, targetEnd - targetPos, payloadPos, function (error, chunkSize) {
|
|
if (error) return cb(error);
|
|
sourceStart += chunkSize;
|
|
targetPos += chunkSize;
|
|
if (chunkSize !== 0 && targetPos < targetEnd) {
|
|
payloadCopyMany(source, target, targetPos, sourceStart, cb);
|
|
} else {
|
|
return cb();
|
|
}
|
|
});
|
|
}
|
|
|
|
function payloadCopyManySync (source, target, targetStart, sourceStart) {
|
|
var payloadPos = source[0] + sourceStart;
|
|
var targetPos = targetStart;
|
|
var targetEnd = targetStart + source[1] - sourceStart;
|
|
var chunkSize;
|
|
while (true) {
|
|
chunkSize = readPayloadSync(target, targetPos, targetEnd - targetPos, payloadPos);
|
|
payloadPos += chunkSize;
|
|
targetPos += chunkSize;
|
|
if (!(chunkSize !== 0 && targetPos < targetEnd)) break;
|
|
}
|
|
}
|
|
|
|
function payloadFile (pointer, cb) {
|
|
var target = Buffer.alloc(pointer[1]);
|
|
payloadCopyMany(pointer, target, 0, 0, function (error) {
|
|
if (error) return cb(error);
|
|
cb(null, target);
|
|
});
|
|
}
|
|
|
|
function payloadFileSync (pointer) {
|
|
var target = Buffer.alloc(pointer[1]);
|
|
payloadCopyManySync(pointer, target, 0, 0);
|
|
return target;
|
|
}
|
|
|
|
// /////////////////////////////////////////////////////////////////
|
|
// SETUP PROCESS ///////////////////////////////////////////////////
|
|
// /////////////////////////////////////////////////////////////////
|
|
|
|
(function () {
|
|
process.pkg = {};
|
|
process.versions.pkg = '%VERSION%';
|
|
process.pkg.mount = createMountpoint;
|
|
process.pkg.entrypoint = ENTRYPOINT;
|
|
process.pkg.defaultEntrypoint = DEFAULT_ENTRYPOINT;
|
|
}());
|
|
|
|
// /////////////////////////////////////////////////////////////////
|
|
// PATH.RESOLVE REPLACEMENT ////////////////////////////////////////
|
|
// /////////////////////////////////////////////////////////////////
|
|
|
|
(function () {
|
|
var path = require('path');
|
|
|
|
process.pkg.path = {};
|
|
process.pkg.path.resolve = function () {
|
|
var args = cloneArgs(arguments);
|
|
args.unshift(path.dirname(ENTRYPOINT));
|
|
return path.resolve.apply(path, args); // eslint-disable-line prefer-spread
|
|
};
|
|
}());
|
|
|
|
// /////////////////////////////////////////////////////////////////
|
|
// PATCH FS ////////////////////////////////////////////////////////
|
|
// /////////////////////////////////////////////////////////////////
|
|
|
|
(function () {
|
|
var fs = require('fs');
|
|
var ancestor = {};
|
|
ancestor.openSync = fs.openSync;
|
|
ancestor.open = fs.open;
|
|
ancestor.readSync = fs.readSync;
|
|
ancestor.read = fs.read;
|
|
ancestor.writeSync = fs.writeSync;
|
|
ancestor.write = fs.write;
|
|
ancestor.closeSync = fs.closeSync;
|
|
ancestor.close = fs.close;
|
|
ancestor.readFileSync = fs.readFileSync;
|
|
ancestor.readFile = fs.readFile;
|
|
// ancestor.writeFileSync = fs.writeFileSync; // based on openSync/writeSync/closeSync
|
|
// ancestor.writeFile = fs.writeFile; // based on open/write/close
|
|
ancestor.readdirSync = fs.readdirSync;
|
|
ancestor.readdir = fs.readdir;
|
|
ancestor.realpathSync = fs.realpathSync;
|
|
ancestor.realpath = fs.realpath;
|
|
ancestor.statSync = fs.statSync;
|
|
ancestor.stat = fs.stat;
|
|
ancestor.lstatSync = fs.lstatSync;
|
|
ancestor.lstat = fs.lstat;
|
|
ancestor.fstatSync = fs.fstatSync;
|
|
ancestor.fstat = fs.fstat;
|
|
ancestor.existsSync = fs.existsSync;
|
|
ancestor.exists = fs.exists;
|
|
ancestor.accessSync = fs.accessSync;
|
|
ancestor.access = fs.access;
|
|
|
|
var windows = process.platform === 'win32';
|
|
|
|
var docks = {};
|
|
var ENOTDIR = windows ? 4052 : 20;
|
|
var ENOENT = windows ? 4058 : 2;
|
|
var EISDIR = windows ? 4068 : 21;
|
|
|
|
function assertEncoding (encoding) {
|
|
if (encoding && !Buffer.isEncoding(encoding)) {
|
|
throw new Error('Unknown encoding: ' + encoding);
|
|
}
|
|
}
|
|
|
|
function maybeCallback (args) {
|
|
var cb = args[args.length - 1];
|
|
return typeof cb === 'function' ? cb : rethrow;
|
|
}
|
|
|
|
function error_ENOENT (fileOrDirectory, path) { // eslint-disable-line camelcase
|
|
var error = new Error(
|
|
fileOrDirectory + ' \'' + stripSnapshot(path) + '\' ' +
|
|
'was not included into executable at compilation stage. ' +
|
|
'Please recompile adding it as asset or script.'
|
|
);
|
|
error.errno = -ENOENT;
|
|
error.code = 'ENOENT';
|
|
error.path = path;
|
|
error.pkg = true;
|
|
return error;
|
|
}
|
|
|
|
function error_EISDIR (path) { // eslint-disable-line camelcase
|
|
var error = new Error(
|
|
'EISDIR: illegal operation on a directory, read'
|
|
);
|
|
error.errno = -EISDIR;
|
|
error.code = 'EISDIR';
|
|
error.path = path;
|
|
error.pkg = true;
|
|
return error;
|
|
}
|
|
|
|
function error_ENOTDIR (path) { // eslint-disable-line camelcase
|
|
var error = new Error(
|
|
'ENOTDIR: not a directory, scandir \'' + path + '\''
|
|
);
|
|
error.errno = -ENOTDIR;
|
|
error.code = 'ENOTDIR';
|
|
error.path = path;
|
|
error.pkg = true;
|
|
return error;
|
|
}
|
|
|
|
// ///////////////////////////////////////////////////////////////
|
|
// open //////////////////////////////////////////////////////////
|
|
// ///////////////////////////////////////////////////////////////
|
|
|
|
function openFromSnapshot (path_, cb) {
|
|
var cb2 = cb || rethrow;
|
|
var path = normalizePath(path_);
|
|
// console.log("openFromSnapshot", path);
|
|
var entity = VIRTUAL_FILESYSTEM[path];
|
|
if (!entity) return cb2(error_ENOENT('File or directory', path));
|
|
var dock = { path: path, entity: entity, position: 0 };
|
|
var nullDevice = windows ? '\\\\.\\NUL' : '/dev/null';
|
|
if (cb) {
|
|
ancestor.open.call(fs, nullDevice, 'r', function (error, fd) {
|
|
if (error) return cb(error);
|
|
docks[fd] = dock;
|
|
cb(null, fd);
|
|
});
|
|
} else {
|
|
var fd = ancestor.openSync.call(fs, nullDevice, 'r');
|
|
docks[fd] = dock;
|
|
return fd;
|
|
}
|
|
}
|
|
|
|
fs.openSync = function (path) {
|
|
if (!insideSnapshot(path)) {
|
|
return ancestor.openSync.apply(fs, arguments);
|
|
}
|
|
if (insideMountpoint(path)) {
|
|
return ancestor.openSync.apply(fs, translateNth(arguments, 0, path));
|
|
}
|
|
|
|
return openFromSnapshot(path);
|
|
};
|
|
|
|
fs.open = function (path) {
|
|
if (!insideSnapshot(path)) {
|
|
return ancestor.open.apply(fs, arguments);
|
|
}
|
|
if (insideMountpoint(path)) {
|
|
return ancestor.open.apply(fs, translateNth(arguments, 0, path));
|
|
}
|
|
|
|
var callback = dezalgo(maybeCallback(arguments));
|
|
openFromSnapshot(path, callback);
|
|
};
|
|
|
|
// ///////////////////////////////////////////////////////////////
|
|
// read //////////////////////////////////////////////////////////
|
|
// ///////////////////////////////////////////////////////////////
|
|
|
|
function readFromSnapshotSub (entityContent, dock, buffer, offset, length, position, cb) {
|
|
var p;
|
|
if ((position !== null) && (position !== undefined)) {
|
|
p = position;
|
|
} else {
|
|
p = dock.position;
|
|
}
|
|
if (cb) {
|
|
payloadCopyUni(entityContent, buffer, offset, p, p + length, function (error, bytesRead, buffer2) {
|
|
if (error) return cb(error);
|
|
dock.position = p + bytesRead;
|
|
cb(null, bytesRead, buffer2);
|
|
});
|
|
} else {
|
|
var bytesRead = payloadCopyUni(entityContent, buffer, offset, p, p + length);
|
|
dock.position = p + bytesRead;
|
|
return bytesRead;
|
|
}
|
|
}
|
|
|
|
function readFromSnapshot (fd, buffer, offset, length, position, cb) {
|
|
var cb2 = cb || rethrow;
|
|
if ((offset < 0) && (NODE_VERSION_MAJOR >= 10)) return cb2(new Error(
|
|
'The value of "offset" is out of range. It must be >= 0 && <= ' + buffer.length.toString() + '. Received ' + offset));
|
|
if (offset < 0) return cb2(new Error('Offset is out of bounds'));
|
|
if ((offset >= buffer.length) && (NODE_VERSION_MAJOR >= 6)) return cb2(null, 0);
|
|
if (offset >= buffer.length) return cb2(new Error('Offset is out of bounds'));
|
|
if ((offset + length > buffer.length) && (NODE_VERSION_MAJOR >= 10)) return cb2(new Error(
|
|
'The value of "length" is out of range. It must be >= 0 && <= ' + (buffer.length - offset).toString() + '. Received ' + length.toString()));
|
|
if (offset + length > buffer.length) return cb2(new Error('Length extends beyond buffer'));
|
|
|
|
var dock = docks[fd];
|
|
var entity = dock.entity;
|
|
var entityLinks = entity[STORE_LINKS];
|
|
if (entityLinks) return cb2(error_EISDIR(dock.path));
|
|
var entityContent = entity[STORE_CONTENT];
|
|
if (entityContent) return readFromSnapshotSub(entityContent, dock, buffer, offset, length, position, cb);
|
|
return cb2(new Error('UNEXPECTED-15'));
|
|
}
|
|
|
|
fs.readSync = function (fd, buffer, offset, length, position) {
|
|
if (!docks[fd]) {
|
|
return ancestor.readSync.apply(fs, arguments);
|
|
}
|
|
|
|
return readFromSnapshot(fd, buffer, offset, length, position);
|
|
};
|
|
|
|
fs.read = function (fd, buffer, offset, length, position) {
|
|
if (!docks[fd]) {
|
|
return ancestor.read.apply(fs, arguments);
|
|
}
|
|
|
|
var callback = dezalgo(maybeCallback(arguments));
|
|
readFromSnapshot(fd, buffer, offset, length, position, callback);
|
|
};
|
|
|
|
// ///////////////////////////////////////////////////////////////
|
|
// write /////////////////////////////////////////////////////////
|
|
// ///////////////////////////////////////////////////////////////
|
|
|
|
function writeToSnapshot (cb) {
|
|
var cb2 = cb || rethrow;
|
|
return cb2(new Error('Cannot write to packaged file'));
|
|
}
|
|
|
|
fs.writeSync = function (fd) {
|
|
if (!docks[fd]) {
|
|
return ancestor.writeSync.apply(fs, arguments);
|
|
}
|
|
|
|
return writeToSnapshot();
|
|
};
|
|
|
|
fs.write = function (fd) {
|
|
if (!docks[fd]) {
|
|
return ancestor.write.apply(fs, arguments);
|
|
}
|
|
|
|
var callback = dezalgo(maybeCallback(arguments));
|
|
writeToSnapshot(callback);
|
|
};
|
|
|
|
// ///////////////////////////////////////////////////////////////
|
|
// close /////////////////////////////////////////////////////////
|
|
// ///////////////////////////////////////////////////////////////
|
|
|
|
function closeFromSnapshot (fd, cb) {
|
|
delete docks[fd];
|
|
if (cb) {
|
|
ancestor.close.call(fs, fd, cb);
|
|
} else {
|
|
return ancestor.closeSync.call(fs, fd);
|
|
}
|
|
}
|
|
|
|
fs.closeSync = function (fd) {
|
|
if (!docks[fd]) {
|
|
return ancestor.closeSync.apply(fs, arguments);
|
|
}
|
|
|
|
return closeFromSnapshot(fd);
|
|
};
|
|
|
|
fs.close = function (fd) {
|
|
if (!docks[fd]) {
|
|
return ancestor.close.apply(fs, arguments);
|
|
}
|
|
|
|
var callback = dezalgo(maybeCallback(arguments));
|
|
closeFromSnapshot(fd, callback);
|
|
};
|
|
|
|
// ///////////////////////////////////////////////////////////////
|
|
// readFile //////////////////////////////////////////////////////
|
|
// ///////////////////////////////////////////////////////////////
|
|
|
|
function readFileOptions (options, hasCallback) {
|
|
if (!options || (hasCallback && typeof options === 'function')) {
|
|
return { encoding: null, flag: 'r' };
|
|
} else if (typeof options === 'string') {
|
|
return { encoding: options, flag: 'r' };
|
|
} else if (typeof options === 'object') {
|
|
return options;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function readFileFromSnapshotSub (entityContent, cb) {
|
|
if (cb) {
|
|
payloadFile(entityContent, cb);
|
|
} else {
|
|
return payloadFileSync(entityContent);
|
|
}
|
|
}
|
|
|
|
function readFileFromSnapshot (path_, cb) {
|
|
var cb2 = cb || rethrow;
|
|
var path = normalizePath(path_);
|
|
// console.log("readFileFromSnapshot", path);
|
|
var entity = VIRTUAL_FILESYSTEM[path];
|
|
if (!entity) return cb2(error_ENOENT('File', path));
|
|
var entityLinks = entity[STORE_LINKS];
|
|
if (entityLinks) return cb2(error_EISDIR(path));
|
|
var entityContent = entity[STORE_CONTENT];
|
|
if (entityContent) return readFileFromSnapshotSub(entityContent, cb);
|
|
var entityBlob = entity[STORE_BLOB];
|
|
if (entityBlob) return cb2(null, Buffer.from('source-code-not-available'));
|
|
|
|
// why return empty buffer?
|
|
// otherwise this error will arise:
|
|
// Error: UNEXPECTED-20
|
|
// at readFileFromSnapshot (e:0)
|
|
// at Object.fs.readFileSync (e:0)
|
|
// at Object.Module._extensions..js (module.js:421:20)
|
|
// at Module.load (module.js:357:32)
|
|
// at Function.Module._load (module.js:314:12)
|
|
// at Function.Module.runMain (e:0)
|
|
// at startup (node.js:140:18)
|
|
// at node.js:1001:3
|
|
|
|
return cb2(new Error('UNEXPECTED-20'));
|
|
}
|
|
|
|
fs.readFileSync = function (path, options_) {
|
|
if (path === 'dirty-hack-for-testing-purposes') {
|
|
return path;
|
|
}
|
|
|
|
if (!insideSnapshot(path)) {
|
|
return ancestor.readFileSync.apply(fs, arguments);
|
|
}
|
|
if (insideMountpoint(path)) {
|
|
return ancestor.readFileSync.apply(fs, translateNth(arguments, 0, path));
|
|
}
|
|
|
|
var options = readFileOptions(options_, false);
|
|
|
|
if (!options) {
|
|
return ancestor.readFileSync.apply(fs, arguments);
|
|
}
|
|
|
|
var encoding = options.encoding;
|
|
assertEncoding(encoding);
|
|
|
|
var buffer = readFileFromSnapshot(path);
|
|
if (encoding) buffer = buffer.toString(encoding);
|
|
return buffer;
|
|
};
|
|
|
|
fs.readFile = function (path, options_) {
|
|
if (!insideSnapshot(path)) {
|
|
return ancestor.readFile.apply(fs, arguments);
|
|
}
|
|
if (insideMountpoint(path)) {
|
|
return ancestor.readFile.apply(fs, translateNth(arguments, 0, path));
|
|
}
|
|
|
|
var options = readFileOptions(options_, true);
|
|
|
|
if (!options) {
|
|
return ancestor.readFile.apply(fs, arguments);
|
|
}
|
|
|
|
var encoding = options.encoding;
|
|
assertEncoding(encoding);
|
|
|
|
var callback = dezalgo(maybeCallback(arguments));
|
|
readFileFromSnapshot(path, function (error, buffer) {
|
|
if (error) return callback(error);
|
|
if (encoding) buffer = buffer.toString(encoding);
|
|
callback(null, buffer);
|
|
});
|
|
};
|
|
|
|
// ///////////////////////////////////////////////////////////////
|
|
// writeFile /////////////////////////////////////////////////////
|
|
// ///////////////////////////////////////////////////////////////
|
|
|
|
// writeFileSync based on openSync/writeSync/closeSync
|
|
// writeFile based on open/write/close
|
|
|
|
// ///////////////////////////////////////////////////////////////
|
|
// readdir ///////////////////////////////////////////////////////
|
|
// ///////////////////////////////////////////////////////////////
|
|
|
|
function readdirOptions (options, hasCallback) {
|
|
if (!options || (hasCallback && typeof options === 'function')) {
|
|
return { encoding: null };
|
|
} else if (typeof options === 'string') {
|
|
return { encoding: options };
|
|
} else if (typeof options === 'object') {
|
|
return options;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function Dirent (name, type) {
|
|
this.name = name;
|
|
this.type = type;
|
|
}
|
|
|
|
Dirent.prototype.isDirectory = function () {
|
|
return this.type === 2;
|
|
};
|
|
|
|
Dirent.prototype.isFile = function () {
|
|
return this.type === 1;
|
|
};
|
|
|
|
Dirent.prototype.isBlockDevice =
|
|
Dirent.prototype.isCharacterDevice =
|
|
Dirent.prototype.isSymbolicLink =
|
|
Dirent.prototype.isFIFO =
|
|
Dirent.prototype.isSocket = function () {
|
|
return false;
|
|
};
|
|
|
|
function getFileTypes (path_, entries) {
|
|
return entries.map(function (entry) {
|
|
var path = require('path').join(path_, entry);
|
|
var entity = VIRTUAL_FILESYSTEM[path];
|
|
if (entity[STORE_BLOB] || entity[STORE_CONTENT]) return new Dirent(entry, 1);
|
|
if (entity[STORE_LINKS]) return new Dirent(entry, 2);
|
|
throw new Error('UNEXPECTED-24');
|
|
});
|
|
}
|
|
|
|
function readdirRoot (path, cb) {
|
|
if (cb) {
|
|
ancestor.readdir(path, function (error, entries) {
|
|
if (error) return cb(error);
|
|
entries.push('snapshot');
|
|
cb(null, entries);
|
|
});
|
|
} else {
|
|
var entries = ancestor.readdirSync(path);
|
|
entries.push('snapshot');
|
|
return entries;
|
|
}
|
|
}
|
|
|
|
function readdirFromSnapshotSub (entityLinks, path, cb) {
|
|
if (cb) {
|
|
payloadFile(entityLinks, function (error, buffer) {
|
|
if (error) return cb(error);
|
|
cb(null, JSON.parse(buffer).concat(readdirMountpoints(path)));
|
|
});
|
|
} else {
|
|
var buffer = payloadFileSync(entityLinks);
|
|
return JSON.parse(buffer).concat(readdirMountpoints(path));
|
|
}
|
|
}
|
|
|
|
function readdirFromSnapshot (path_, isRoot, cb) {
|
|
var cb2 = cb || rethrow;
|
|
if (isRoot) return readdirRoot(path_, cb);
|
|
var path = normalizePath(path_);
|
|
// console.log("readdirFromSnapshot", path);
|
|
var entity = VIRTUAL_FILESYSTEM[path];
|
|
if (!entity) return cb2(error_ENOENT('Directory', path));
|
|
var entityBlob = entity[STORE_BLOB];
|
|
if (entityBlob) return cb2(error_ENOTDIR(path));
|
|
var entityContent = entity[STORE_CONTENT];
|
|
if (entityContent) return cb2(error_ENOTDIR(path));
|
|
var entityLinks = entity[STORE_LINKS];
|
|
if (entityLinks) return readdirFromSnapshotSub(entityLinks, path, cb);
|
|
return cb2(new Error('UNEXPECTED-25'));
|
|
}
|
|
|
|
fs.readdirSync = function (path, options_) {
|
|
var isRoot = isRootPath(path);
|
|
|
|
if (!insideSnapshot(path) && !isRoot) {
|
|
return ancestor.readdirSync.apply(fs, arguments);
|
|
}
|
|
if (insideMountpoint(path)) {
|
|
return ancestor.readdirSync.apply(fs, translateNth(arguments, 0, path));
|
|
}
|
|
|
|
var options = readdirOptions(options_, false);
|
|
|
|
if (!options) {
|
|
return ancestor.readdirSync.apply(fs, arguments);
|
|
}
|
|
|
|
var entries = readdirFromSnapshot(path, isRoot);
|
|
if (options.withFileTypes) entries = getFileTypes(path, entries);
|
|
return entries;
|
|
};
|
|
|
|
fs.readdir = function (path, options_) {
|
|
var isRoot = isRootPath(path);
|
|
|
|
if (!insideSnapshot(path) && !isRoot) {
|
|
return ancestor.readdir.apply(fs, arguments);
|
|
}
|
|
if (insideMountpoint(path)) {
|
|
return ancestor.readdir.apply(fs, translateNth(arguments, 0, path));
|
|
}
|
|
|
|
var options = readdirOptions(options_, true);
|
|
|
|
if (!options) {
|
|
return ancestor.readdir.apply(fs, arguments);
|
|
}
|
|
|
|
var callback = dezalgo(maybeCallback(arguments));
|
|
readdirFromSnapshot(path, isRoot, function (error, entries) {
|
|
if (error) return callback(error);
|
|
if (options.withFileTypes) entries = getFileTypes(path, entries);
|
|
callback(null, entries);
|
|
});
|
|
};
|
|
|
|
// ///////////////////////////////////////////////////////////////
|
|
// realpath //////////////////////////////////////////////////////
|
|
// ///////////////////////////////////////////////////////////////
|
|
|
|
function realpathFromSnapshot (path_) {
|
|
var path = normalizePath(path_);
|
|
// console.log("realpathFromSnapshot", path);
|
|
return path;
|
|
}
|
|
|
|
fs.realpathSync = function (path) {
|
|
if (!insideSnapshot(path)) {
|
|
return ancestor.realpathSync.apply(fs, arguments);
|
|
}
|
|
if (insideMountpoint(path)) {
|
|
// app should not know real file name
|
|
}
|
|
|
|
return realpathFromSnapshot(path);
|
|
};
|
|
|
|
fs.realpath = function (path) {
|
|
if (!insideSnapshot(path)) {
|
|
return ancestor.realpath.apply(fs, arguments);
|
|
}
|
|
if (insideMountpoint(path)) {
|
|
// app should not know real file name
|
|
}
|
|
|
|
var callback = dezalgo(maybeCallback(arguments));
|
|
callback(null, realpathFromSnapshot(path));
|
|
};
|
|
|
|
// ///////////////////////////////////////////////////////////////
|
|
// stat //////////////////////////////////////////////////////////
|
|
// ///////////////////////////////////////////////////////////////
|
|
|
|
function restore (s) {
|
|
s.blksize = 4096;
|
|
s.blocks = 0;
|
|
s.dev = 0;
|
|
s.gid = 20;
|
|
s.ino = 0;
|
|
s.nlink = 0;
|
|
s.rdev = 0;
|
|
s.uid = 500;
|
|
|
|
s.atime = new Date(EXECSTAT.atime);
|
|
s.mtime = new Date(EXECSTAT.mtime);
|
|
s.ctime = new Date(EXECSTAT.ctime);
|
|
s.birthtime = new Date(EXECSTAT.birthtime);
|
|
|
|
s.atimeMs = EXECSTAT.atimeMs;
|
|
s.mtimeMs = EXECSTAT.mtimeMs;
|
|
s.ctimeMs = EXECSTAT.ctimeMs;
|
|
s.birthtimeMs = EXECSTAT.birthtimeMs;
|
|
|
|
var isFileValue = s.isFileValue;
|
|
var isDirectoryValue = s.isDirectoryValue;
|
|
delete s.isFileValue;
|
|
delete s.isDirectoryValue;
|
|
|
|
s.isFile = function () {
|
|
return isFileValue;
|
|
};
|
|
s.isDirectory = function () {
|
|
return isDirectoryValue;
|
|
};
|
|
s.isSymbolicLink = function () {
|
|
return false;
|
|
};
|
|
s.isFIFO = function () {
|
|
return false;
|
|
};
|
|
|
|
return s;
|
|
}
|
|
|
|
function findNativeAddonForStat (path, cb) {
|
|
var cb2 = cb || rethrow;
|
|
var foundPath = findNativeAddonSyncUnderRequire(path);
|
|
if (!foundPath) return cb2(error_ENOENT('File or directory', path));
|
|
if (cb) {
|
|
ancestor.stat.call(fs, foundPath, cb);
|
|
} else {
|
|
return ancestor.statSync.call(fs, foundPath);
|
|
}
|
|
}
|
|
|
|
function statFromSnapshotSub (entityStat, cb) {
|
|
if (cb) {
|
|
payloadFile(entityStat, function (error, buffer) {
|
|
if (error) return cb(error);
|
|
cb(null, restore(JSON.parse(buffer)));
|
|
});
|
|
} else {
|
|
var buffer = payloadFileSync(entityStat);
|
|
return restore(JSON.parse(buffer));
|
|
}
|
|
}
|
|
|
|
function statFromSnapshot (path_, cb) {
|
|
var cb2 = cb || rethrow;
|
|
var path = normalizePath(path_);
|
|
// console.log("statFromSnapshot", path);
|
|
var entity = VIRTUAL_FILESYSTEM[path];
|
|
if (!entity) return findNativeAddonForStat(path, cb);
|
|
var entityStat = entity[STORE_STAT];
|
|
if (entityStat) return statFromSnapshotSub(entityStat, cb);
|
|
return cb2(new Error('UNEXPECTED-35'));
|
|
}
|
|
|
|
fs.statSync = function (path) {
|
|
if (!insideSnapshot(path)) {
|
|
return ancestor.statSync.apply(fs, arguments);
|
|
}
|
|
if (insideMountpoint(path)) {
|
|
return ancestor.statSync.apply(fs, translateNth(arguments, 0, path));
|
|
}
|
|
|
|
return statFromSnapshot(path);
|
|
};
|
|
|
|
fs.stat = function (path) {
|
|
if (!insideSnapshot(path)) {
|
|
return ancestor.stat.apply(fs, arguments);
|
|
}
|
|
if (insideMountpoint(path)) {
|
|
return ancestor.stat.apply(fs, translateNth(arguments, 0, path));
|
|
}
|
|
|
|
var callback = dezalgo(maybeCallback(arguments));
|
|
statFromSnapshot(path, callback);
|
|
};
|
|
|
|
// ///////////////////////////////////////////////////////////////
|
|
// lstat /////////////////////////////////////////////////////////
|
|
// ///////////////////////////////////////////////////////////////
|
|
|
|
fs.lstatSync = function (path) {
|
|
if (!insideSnapshot(path)) {
|
|
return ancestor.lstatSync.apply(fs, arguments);
|
|
}
|
|
if (insideMountpoint(path)) {
|
|
return ancestor.lstatSync.apply(fs, translateNth(arguments, 0, path));
|
|
}
|
|
|
|
return statFromSnapshot(path);
|
|
};
|
|
|
|
fs.lstat = function (path) {
|
|
if (!insideSnapshot(path)) {
|
|
return ancestor.lstat.apply(fs, arguments);
|
|
}
|
|
if (insideMountpoint(path)) {
|
|
return ancestor.lstat.apply(fs, translateNth(arguments, 0, path));
|
|
}
|
|
|
|
var callback = dezalgo(maybeCallback(arguments));
|
|
statFromSnapshot(path, callback);
|
|
};
|
|
|
|
// ///////////////////////////////////////////////////////////////
|
|
// fstat /////////////////////////////////////////////////////////
|
|
// ///////////////////////////////////////////////////////////////
|
|
|
|
function fstatFromSnapshot (fd, cb) {
|
|
var cb2 = cb || rethrow;
|
|
var entity = docks[fd].entity;
|
|
var entityStat = entity[STORE_STAT];
|
|
if (entityStat) return statFromSnapshotSub(entityStat, cb);
|
|
return cb2(new Error('UNEXPECTED-40'));
|
|
}
|
|
|
|
fs.fstatSync = function (fd) {
|
|
if (!docks[fd]) {
|
|
return ancestor.fstatSync.apply(fs, arguments);
|
|
}
|
|
|
|
return fstatFromSnapshot(fd);
|
|
};
|
|
|
|
fs.fstat = function (fd) {
|
|
if (!docks[fd]) {
|
|
return ancestor.fstat.apply(fs, arguments);
|
|
}
|
|
|
|
var callback = dezalgo(maybeCallback(arguments));
|
|
fstatFromSnapshot(fd, callback);
|
|
};
|
|
|
|
// ///////////////////////////////////////////////////////////////
|
|
// exists ////////////////////////////////////////////////////////
|
|
// ///////////////////////////////////////////////////////////////
|
|
|
|
function findNativeAddonForExists (path) {
|
|
var foundPath = findNativeAddonSyncFreeFromRequire(path);
|
|
if (!foundPath) return false;
|
|
return ancestor.existsSync.call(fs, foundPath);
|
|
}
|
|
|
|
function existsFromSnapshot (path_) {
|
|
var path = normalizePath(path_);
|
|
// console.log("existsFromSnapshot", path);
|
|
var entity = VIRTUAL_FILESYSTEM[path];
|
|
if (!entity) return findNativeAddonForExists(path);
|
|
return true;
|
|
}
|
|
|
|
fs.existsSync = function (path) {
|
|
if (!insideSnapshot(path)) {
|
|
return ancestor.existsSync.apply(fs, arguments);
|
|
}
|
|
if (insideMountpoint(path)) {
|
|
return ancestor.existsSync.apply(fs, translateNth(arguments, 0, path));
|
|
}
|
|
|
|
return existsFromSnapshot(path);
|
|
};
|
|
|
|
fs.exists = function (path) {
|
|
if (!insideSnapshot(path)) {
|
|
return ancestor.exists.apply(fs, arguments);
|
|
}
|
|
if (insideMountpoint(path)) {
|
|
return ancestor.exists.apply(fs, translateNth(arguments, 0, path));
|
|
}
|
|
|
|
var callback = dezalgo(maybeCallback(arguments));
|
|
callback(existsFromSnapshot(path));
|
|
};
|
|
|
|
// ///////////////////////////////////////////////////////////////
|
|
// access ////////////////////////////////////////////////////////
|
|
// ///////////////////////////////////////////////////////////////
|
|
|
|
function accessFromSnapshot (path_, cb) {
|
|
var cb2 = cb || rethrow;
|
|
var path = normalizePath(path_);
|
|
// console.log("accessFromSnapshot", path);
|
|
var entity = VIRTUAL_FILESYSTEM[path];
|
|
if (!entity) return cb2(error_ENOENT('File or directory', path));
|
|
return cb2(null, undefined);
|
|
}
|
|
|
|
fs.accessSync = function (path) {
|
|
if (!insideSnapshot(path)) {
|
|
return ancestor.accessSync.apply(fs, arguments);
|
|
}
|
|
if (insideMountpoint(path)) {
|
|
return ancestor.accessSync.apply(fs, translateNth(arguments, 0, path));
|
|
}
|
|
|
|
return accessFromSnapshot(path);
|
|
};
|
|
|
|
fs.access = function (path) {
|
|
if (!insideSnapshot(path)) {
|
|
return ancestor.access.apply(fs, arguments);
|
|
}
|
|
if (insideMountpoint(path)) {
|
|
return ancestor.access.apply(fs, translateNth(arguments, 0, path));
|
|
}
|
|
|
|
var callback = dezalgo(maybeCallback(arguments));
|
|
accessFromSnapshot(path, callback);
|
|
};
|
|
|
|
// ///////////////////////////////////////////////////////////////
|
|
// INTERNAL //////////////////////////////////////////////////////
|
|
// ///////////////////////////////////////////////////////////////
|
|
|
|
function makeLong (f) {
|
|
return require('path')._makeLong(f);
|
|
}
|
|
|
|
function revertMakingLong (f) {
|
|
if (/^\\\\\?\\/.test(f)) return f.slice(4);
|
|
return f;
|
|
}
|
|
|
|
function findNativeAddonForInternalModuleStat (path_) {
|
|
var path = findNativeAddonSyncUnderRequire(path_);
|
|
if (!path) return -ENOENT;
|
|
return process.binding('fs').internalModuleStat(makeLong(path));
|
|
}
|
|
|
|
fs.internalModuleStat = function (long) {
|
|
// from node comments:
|
|
// Used to speed up module loading. Returns 0 if the path refers to
|
|
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT).
|
|
// The speedup comes from not creating thousands of Stat and Error objects.
|
|
|
|
var path = revertMakingLong(long);
|
|
|
|
if (!insideSnapshot(path)) {
|
|
return process.binding('fs').internalModuleStat(long);
|
|
}
|
|
if (insideMountpoint(path)) {
|
|
return process.binding('fs').internalModuleStat(makeLong(translate(path)));
|
|
}
|
|
|
|
path = normalizePath(path);
|
|
// console.log("internalModuleStat", path);
|
|
var entity = VIRTUAL_FILESYSTEM[path];
|
|
if (!entity) return findNativeAddonForInternalModuleStat(path);
|
|
var entityBlob = entity[STORE_BLOB];
|
|
if (entityBlob) return 0;
|
|
var entityContent = entity[STORE_CONTENT];
|
|
if (entityContent) return 0;
|
|
var entityLinks = entity[STORE_LINKS];
|
|
if (entityLinks) return 1;
|
|
return -ENOENT;
|
|
};
|
|
|
|
fs.internalModuleReadFile = fs.internalModuleReadJSON = function (long) {
|
|
// from node comments:
|
|
// Used to speed up module loading. Returns the contents of the file as
|
|
// a string or undefined when the file cannot be opened. The speedup
|
|
// comes from not creating Error objects on failure.
|
|
|
|
var path = revertMakingLong(long);
|
|
var bindingFs = process.binding('fs');
|
|
var readFile = (bindingFs.internalModuleReadFile ||
|
|
bindingFs.internalModuleReadJSON).bind(bindingFs);
|
|
if (!insideSnapshot(path)) {
|
|
return readFile(long);
|
|
}
|
|
if (insideMountpoint(path)) {
|
|
return readFile(makeLong(translate(path)));
|
|
}
|
|
|
|
path = normalizePath(path);
|
|
// console.log("internalModuleReadFile", path);
|
|
var entity = VIRTUAL_FILESYSTEM[path];
|
|
if (!entity) return undefined;
|
|
var entityContent = entity[STORE_CONTENT];
|
|
if (!entityContent) return undefined;
|
|
return payloadFileSync(entityContent).toString();
|
|
};
|
|
}());
|
|
|
|
// /////////////////////////////////////////////////////////////////
|
|
// PATCH MODULE ////////////////////////////////////////////////////
|
|
// /////////////////////////////////////////////////////////////////
|
|
|
|
(function () {
|
|
var Module = require('module');
|
|
var ancestor = {};
|
|
ancestor.require = Module.prototype.require;
|
|
ancestor._compile = Module.prototype._compile;
|
|
ancestor._resolveFilename = Module._resolveFilename;
|
|
ancestor.runMain = Module.runMain;
|
|
|
|
Module.prototype.require = function (path) {
|
|
try {
|
|
return ancestor.require.apply(this, arguments);
|
|
} catch (error) {
|
|
if (((error.code === 'ENOENT') ||
|
|
(error.code === 'MODULE_NOT_FOUND')) &&
|
|
(!insideSnapshot(path)) &&
|
|
(!require('path').isAbsolute(path))) {
|
|
if (!error.pkg) {
|
|
error.pkg = true;
|
|
error.message += '\n' +
|
|
'1) If you want to compile the package/file into ' +
|
|
'executable, please pay attention to compilation ' +
|
|
'warnings and specify a literal in \'require\' call. ' +
|
|
'2) If you don\'t want to compile the package/file ' +
|
|
'into executable and want to \'require\' it from ' +
|
|
'filesystem (likely plugin), specify an absolute ' +
|
|
'path in \'require\' call using process.cwd() or ' +
|
|
'process.execPath.';
|
|
}
|
|
}
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
var im, makeRequireFunction;
|
|
|
|
if (NODE_VERSION_MAJOR === 0) {
|
|
makeRequireFunction = function (self) {
|
|
function rqfn (path) {
|
|
return self.require(path);
|
|
}
|
|
rqfn.resolve = function (request) {
|
|
return Module._resolveFilename(request, self);
|
|
};
|
|
rqfn.main = process.mainModule;
|
|
rqfn.extensions = Module._extensions;
|
|
rqfn.cache = Module._cache;
|
|
return rqfn;
|
|
};
|
|
} else
|
|
if (NODE_VERSION_MAJOR <= 9) {
|
|
im = require('internal/module');
|
|
if (NODE_VERSION_MAJOR <= 7) {
|
|
makeRequireFunction = function (m) {
|
|
return im.makeRequireFunction.call(m);
|
|
};
|
|
} else {
|
|
makeRequireFunction = im.makeRequireFunction;
|
|
}
|
|
} else {
|
|
im = require('internal/modules/cjs/helpers');
|
|
makeRequireFunction = im.makeRequireFunction;
|
|
// TODO esm modules along with cjs
|
|
}
|
|
|
|
Module.prototype._compile = function (content, filename_) {
|
|
if (!insideSnapshot(filename_)) {
|
|
return ancestor._compile.apply(this, arguments);
|
|
}
|
|
if (insideMountpoint(filename_)) {
|
|
// DONT TRANSLATE! otherwise __dirname gets real name
|
|
return ancestor._compile.apply(this, arguments);
|
|
}
|
|
|
|
var filename = normalizePath(filename_);
|
|
// console.log("_compile", filename);
|
|
var entity = VIRTUAL_FILESYSTEM[filename];
|
|
|
|
if (!entity) {
|
|
// let user try to "_compile" a packaged file
|
|
return ancestor._compile.apply(this, arguments);
|
|
}
|
|
|
|
var entityBlob = entity[STORE_BLOB];
|
|
var entityContent = entity[STORE_CONTENT];
|
|
|
|
if (entityBlob) {
|
|
var options = {
|
|
filename: filename,
|
|
lineOffset: 0,
|
|
displayErrors: true,
|
|
cachedData: payloadFileSync(entityBlob),
|
|
sourceless: !entityContent
|
|
};
|
|
|
|
var Script = require('vm').Script;
|
|
var code = entityContent
|
|
? require('module').wrap(payloadFileSync(entityContent))
|
|
: undefined;
|
|
|
|
var script = new Script(code, options);
|
|
var wrapper = script.runInThisContext(options);
|
|
if (!wrapper) process.exit(4); // for example VERSION_MISMATCH
|
|
var dirname = require('path').dirname(filename);
|
|
var rqfn = makeRequireFunction(this);
|
|
var args = [ this.exports, rqfn, this, filename, dirname ];
|
|
return wrapper.apply(this.exports, args);
|
|
}
|
|
|
|
if (entityContent) {
|
|
if (entityBlob) throw new Error('UNEXPECTED-50');
|
|
// content is already in utf8 and without BOM (that is expected
|
|
// by stock _compile), but entityContent is still a Buffer
|
|
return ancestor._compile.apply(this, arguments);
|
|
}
|
|
|
|
throw new Error('UNEXPECTED-55');
|
|
};
|
|
|
|
Module._resolveFilename = function () {
|
|
var filename;
|
|
var flagWasOn = false;
|
|
|
|
try {
|
|
filename = ancestor._resolveFilename.apply(this, arguments);
|
|
} catch (error) {
|
|
if (error.code !== 'MODULE_NOT_FOUND') throw error;
|
|
|
|
FLAG_ENABLE_PROJECT = true;
|
|
var savePathCache = Module._pathCache;
|
|
Module._pathCache = Object.create(null);
|
|
try {
|
|
filename = ancestor._resolveFilename.apply(this, arguments);
|
|
flagWasOn = true;
|
|
} finally {
|
|
Module._pathCache = savePathCache;
|
|
FLAG_ENABLE_PROJECT = false;
|
|
}
|
|
}
|
|
|
|
if (!insideSnapshot(filename)) {
|
|
return filename;
|
|
}
|
|
if (insideMountpoint(filename)) {
|
|
return filename;
|
|
}
|
|
|
|
if (flagWasOn) {
|
|
FLAG_ENABLE_PROJECT = true;
|
|
try {
|
|
var found = findNativeAddonSyncUnderRequire(filename);
|
|
if (found) filename = found;
|
|
} finally {
|
|
FLAG_ENABLE_PROJECT = false;
|
|
}
|
|
}
|
|
|
|
return filename;
|
|
};
|
|
|
|
Module.runMain = function () {
|
|
Module._load(ENTRYPOINT, null, true);
|
|
process._tickCallback();
|
|
};
|
|
}());
|
|
|
|
// /////////////////////////////////////////////////////////////////
|
|
// PATCH CHILD_PROCESS /////////////////////////////////////////////
|
|
// /////////////////////////////////////////////////////////////////
|
|
|
|
(function () {
|
|
var childProcess = require('child_process');
|
|
var ancestor = {};
|
|
ancestor.spawn = childProcess.spawn;
|
|
ancestor.spawnSync = childProcess.spawnSync;
|
|
ancestor.execFile = childProcess.execFile;
|
|
ancestor.execFileSync = childProcess.execFileSync;
|
|
ancestor.exec = childProcess.exec;
|
|
ancestor.execSync = childProcess.execSync;
|
|
|
|
function setOptsEnv (args) {
|
|
var pos = args.length - 1;
|
|
if (typeof args[pos] === 'function') pos -= 1;
|
|
if (typeof args[pos] !== 'object' || Array.isArray(args[pos])) {
|
|
pos += 1;
|
|
args.splice(pos, 0, {});
|
|
}
|
|
var opts = args[pos];
|
|
if (!opts.env) opts.env = require('util')._extend({}, process.env);
|
|
if (opts.env.PKG_EXECPATH === 'PKG_INVOKE_NODEJS') return;
|
|
opts.env.PKG_EXECPATH = EXECPATH;
|
|
}
|
|
|
|
function startsWith2 (args, index, name, impostor) {
|
|
var qsName = '"' + name + ' ';
|
|
if (args[index].slice(0, qsName.length) === qsName) {
|
|
args[index] = '"' + impostor + ' ' + args[index].slice(qsName.length);
|
|
return true;
|
|
}
|
|
var sName = name + ' ';
|
|
if (args[index].slice(0, sName.length) === sName) {
|
|
args[index] = impostor + ' ' + args[index].slice(sName.length);
|
|
return true;
|
|
}
|
|
if (args[index] === name) {
|
|
args[index] = impostor;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function startsWith (args, index, name) {
|
|
var qName = '"' + name + '"';
|
|
var qEXECPATH = '"' + EXECPATH + '"';
|
|
var jsName = JSON.stringify(name);
|
|
var jsEXECPATH = JSON.stringify(EXECPATH);
|
|
return startsWith2(args, index, name, EXECPATH) ||
|
|
startsWith2(args, index, qName, qEXECPATH) ||
|
|
startsWith2(args, index, jsName, jsEXECPATH);
|
|
}
|
|
|
|
function modifyLong (args, index) {
|
|
if (!args[index]) return;
|
|
return (startsWith(args, index, 'node') ||
|
|
startsWith(args, index, ARGV0) ||
|
|
startsWith(args, index, ENTRYPOINT) ||
|
|
startsWith(args, index, EXECPATH));
|
|
}
|
|
|
|
function modifyShort (args) {
|
|
if (!args[0]) return;
|
|
if (!Array.isArray(args[1])) {
|
|
args.splice(1, 0, []);
|
|
}
|
|
if (args[0] === 'node' ||
|
|
args[0] === ARGV0 ||
|
|
args[0] === ENTRYPOINT ||
|
|
args[0] === EXECPATH) {
|
|
args[0] = EXECPATH;
|
|
if (NODE_VERSION_MAJOR === 0) {
|
|
args[1] = args[1].filter(function (a) {
|
|
return (a.slice(0, 13) !== '--debug-port=');
|
|
});
|
|
}
|
|
} else {
|
|
for (var i = 1; i < args[1].length; i += 1) {
|
|
var mbc = args[1][i - 1];
|
|
if (mbc === '-c' || mbc === '/c') {
|
|
modifyLong(args[1], i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
childProcess.spawn = function () {
|
|
var args = cloneArgs(arguments);
|
|
setOptsEnv(args);
|
|
modifyShort(args);
|
|
return ancestor.spawn.apply(childProcess, args);
|
|
};
|
|
|
|
childProcess.spawnSync = function () {
|
|
var args = cloneArgs(arguments);
|
|
setOptsEnv(args);
|
|
modifyShort(args);
|
|
return ancestor.spawnSync.apply(childProcess, args);
|
|
};
|
|
|
|
childProcess.execFile = function () {
|
|
var args = cloneArgs(arguments);
|
|
setOptsEnv(args);
|
|
modifyShort(args);
|
|
return ancestor.execFile.apply(childProcess, args);
|
|
};
|
|
|
|
childProcess.execFileSync = function () {
|
|
var args = cloneArgs(arguments);
|
|
setOptsEnv(args);
|
|
modifyShort(args);
|
|
return ancestor.execFileSync.apply(childProcess, args);
|
|
};
|
|
|
|
childProcess.exec = function () {
|
|
var args = cloneArgs(arguments);
|
|
setOptsEnv(args);
|
|
modifyLong(args, 0);
|
|
return ancestor.exec.apply(childProcess, args);
|
|
};
|
|
|
|
childProcess.execSync = function () {
|
|
var args = cloneArgs(arguments);
|
|
setOptsEnv(args);
|
|
modifyLong(args, 0);
|
|
return ancestor.execSync.apply(childProcess, args);
|
|
};
|
|
}());
|
|
|
|
// /////////////////////////////////////////////////////////////////
|
|
// PROMISIFY ///////////////////////////////////////////////////////
|
|
// /////////////////////////////////////////////////////////////////
|
|
|
|
(function () {
|
|
var util = require('util');
|
|
var promisify = util.promisify;
|
|
if (promisify) {
|
|
var custom = promisify.custom;
|
|
var customPromisifyArgs = require('internal/util').customPromisifyArgs;
|
|
|
|
// /////////////////////////////////////////////////////////////
|
|
// FS //////////////////////////////////////////////////////////
|
|
// /////////////////////////////////////////////////////////////
|
|
|
|
Object.defineProperty(require('fs').exists, custom, {
|
|
value: function (path) {
|
|
return new Promise(function (resolve) {
|
|
require('fs').exists(path, function (exists) {
|
|
resolve(exists);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
|
|
Object.defineProperty(require('fs').read, customPromisifyArgs, {
|
|
value: [ 'bytesRead', 'buffer' ]
|
|
});
|
|
|
|
Object.defineProperty(require('fs').write, customPromisifyArgs, {
|
|
value: [ 'bytesWritten', 'buffer' ]
|
|
});
|
|
|
|
// /////////////////////////////////////////////////////////////
|
|
// CHILD_PROCESS ///////////////////////////////////////////////
|
|
// /////////////////////////////////////////////////////////////
|
|
|
|
var customPromiseExecFunction = function (o) {
|
|
return function () {
|
|
var args = Array.from(arguments);
|
|
return new Promise(function (resolve, reject) {
|
|
o.apply(undefined, args.concat(function (error, stdout, stderr) {
|
|
if (error !== null) {
|
|
error.stdout = stdout;
|
|
error.stderr = stderr;
|
|
reject(error);
|
|
} else {
|
|
resolve({ stdout: stdout, stderr: stderr });
|
|
}
|
|
}));
|
|
});
|
|
};
|
|
};
|
|
|
|
Object.defineProperty(require('child_process').exec, custom, {
|
|
value: customPromiseExecFunction(require('child_process').exec)
|
|
});
|
|
|
|
Object.defineProperty(require('child_process').execFile, custom, {
|
|
value: customPromiseExecFunction(require('child_process').execFile)
|
|
});
|
|
}
|
|
}());
|