git ssb

0+

cel-desktop / ssb-pkg



Tree: 65191f9a9664f013ebe726bb95a1a54b086e1bd5

Files: 65191f9a9664f013ebe726bb95a1a54b086e1bd5 / prelude / bootstrap.js

51916 bytesRaw
1/* eslint-disable curly */
2/* eslint-disable new-cap */
3/* eslint-disable no-buffer-constructor */
4/* eslint-disable no-multi-spaces */
5/* eslint-disable no-underscore-dangle */
6/* eslint-disable prefer-rest-params */
7/* eslint-disable prefer-spread */
8
9/* global EXECPATH_FD */
10/* global PAYLOAD_POSITION */
11/* global PAYLOAD_SIZE */
12/* global REQUIRE_COMMON */
13/* global VIRTUAL_FILESYSTEM */
14/* global DEFAULT_ENTRYPOINT */
15
16'use strict';
17
18var common = {};
19REQUIRE_COMMON(common);
20
21var STORE_BLOB = common.STORE_BLOB;
22var STORE_CONTENT = common.STORE_CONTENT;
23var STORE_LINKS = common.STORE_LINKS;
24var STORE_STAT = common.STORE_STAT;
25
26var isRootPath = common.isRootPath;
27var normalizePath = common.normalizePath;
28var insideSnapshot = common.insideSnapshot;
29var stripSnapshot = common.stripSnapshot;
30var removeUplevels = common.removeUplevels;
31
32var FLAG_ENABLE_PROJECT = false;
33var NODE_VERSION_MAJOR = process.version.match(/^v(\d+)/)[1] | 0;
34
35// /////////////////////////////////////////////////////////////////
36// ENTRYPOINT //////////////////////////////////////////////////////
37// /////////////////////////////////////////////////////////////////
38
39// set ENTRYPOINT and ARGV0 here because
40// they can be altered during process run
41var ARGV0 = process.argv[0];
42var EXECPATH = process.execPath;
43var ENTRYPOINT = process.argv[1];
44
45if (process.env.PKG_EXECPATH === 'PKG_INVOKE_NODEJS') {
46 return { undoPatch: true };
47}
48
49if (NODE_VERSION_MAJOR < 12 || require('worker_threads').isMainThread) {
50 if (process.argv[1] !== 'PKG_DUMMY_ENTRYPOINT') {
51 // expand once patchless is introduced, that
52 // will obviously lack any work in node_main.cc
53 throw new Error('PKG_DUMMY_ENTRYPOINT EXPECTED');
54 }
55}
56
57if (process.env.PKG_EXECPATH === EXECPATH) {
58 process.argv.splice(1, 1);
59
60 if (process.argv[1] && process.argv[1] !== '-') {
61 // https://github.com/nodejs/node/blob/1a96d83a223ff9f05f7d942fb84440d323f7b596/lib/internal/bootstrap/node.js#L269
62 process.argv[1] = require('path').resolve(process.argv[1]);
63 }
64} else {
65 process.argv[1] = DEFAULT_ENTRYPOINT;
66}
67
68ENTRYPOINT = process.argv[1];
69delete process.env.PKG_EXECPATH;
70
71// /////////////////////////////////////////////////////////////////
72// EXECSTAT ////////////////////////////////////////////////////////
73// /////////////////////////////////////////////////////////////////
74
75var EXECSTAT = require('fs').statSync(EXECPATH);
76EXECSTAT.atimeMs = EXECSTAT.atime.getTime();
77EXECSTAT.mtimeMs = EXECSTAT.mtime.getTime();
78EXECSTAT.ctimeMs = EXECSTAT.ctime.getTime();
79EXECSTAT.birthtimeMs = EXECSTAT.birthtime.getTime();
80
81// /////////////////////////////////////////////////////////////////
82// MOUNTPOINTS /////////////////////////////////////////////////////
83// /////////////////////////////////////////////////////////////////
84
85var mountpoints = [];
86
87function insideMountpoint (f) {
88 if (!insideSnapshot(f)) return null;
89 var file = normalizePath(f);
90 var found = mountpoints.map(function (mountpoint) {
91 var interior = mountpoint.interior;
92 var exterior = mountpoint.exterior;
93 if (interior === file) return exterior;
94 var left = interior + require('path').sep;
95 if (file.slice(0, left.length) !== left) return null;
96 return exterior + file.slice(left.length - 1);
97 }).filter(function (result) {
98 return result;
99 });
100 if (found.length >= 2) throw new Error('UNEXPECTED-00');
101 if (found.length === 0) return null;
102 return found[0];
103}
104
105function readdirMountpoints (path) {
106 return mountpoints.map(function (mountpoint) {
107 return mountpoint.interior;
108 }).filter(function (interior) {
109 return require('path').dirname(interior) === path;
110 }).map(function (interior) {
111 return require('path').basename(interior);
112 });
113}
114
115function translate (f) {
116 var result = insideMountpoint(f);
117 if (!result) throw new Error('UNEXPECTED-05');
118 return result;
119}
120
121function cloneArgs (args_) {
122 return Array.prototype.slice.call(args_);
123}
124
125function translateNth (args_, index, f) {
126 var args = cloneArgs(args_);
127 args[index] = translate(f);
128 return args;
129}
130
131function createMountpoint (interior, exterior) {
132 // TODO validate
133 mountpoints.push({ interior: interior, exterior: exterior });
134}
135
136/*
137
138// TODO move to some test
139
140createMountpoint("d:\\snapshot\\countly\\plugins-ext", "d:\\deploy\\countly\\v16.02\\plugins-ext");
141
142console.log(insideMountpoint("d:\\snapshot"));
143console.log(insideMountpoint("d:\\snapshot\\"));
144console.log(insideMountpoint("d:\\snapshot\\countly"));
145console.log(insideMountpoint("d:\\snapshot\\countly\\"));
146console.log(insideMountpoint("d:\\snapshot\\countly\\plugins-ext"));
147console.log(insideMountpoint("d:\\snapshot\\countly\\plugins-ext\\"));
148console.log(insideMountpoint("d:\\snapshot\\countly\\plugins-ext\\1234"));
149
150console.log(translate("d:\\snapshot\\countly\\plugins-ext"));
151console.log(translate("d:\\snapshot\\countly\\plugins-ext\\"));
152console.log(translate("d:\\snapshot\\countly\\plugins-ext\\1234"));
153
154console.log(translateNth([], 0, "d:\\snapshot\\countly\\plugins-ext"));
155console.log(translateNth([], 0, "d:\\snapshot\\countly\\plugins-ext\\"));
156console.log(translateNth([], 0, "d:\\snapshot\\countly\\plugins-ext\\1234"));
157
158console.log(translateNth(["", "r+"], 0, "d:\\snapshot\\countly\\plugins-ext"));
159console.log(translateNth(["", "rw"], 0, "d:\\snapshot\\countly\\plugins-ext\\"));
160console.log(translateNth(["", "a+"], 0, "d:\\snapshot\\countly\\plugins-ext\\1234"));
161*/
162
163// /////////////////////////////////////////////////////////////////
164// PROJECT /////////////////////////////////////////////////////////
165// /////////////////////////////////////////////////////////////////
166
167function projectToFilesystem (f) {
168 var xpdn = require('path').dirname(
169 EXECPATH
170 );
171
172 var relatives = [];
173 relatives.push(
174 removeUplevels(
175 require('path').relative(
176 require('path').dirname(
177 DEFAULT_ENTRYPOINT
178 ), f
179 )
180 )
181 );
182
183 if (relatives[0].slice(0, 'node_modules'.length) === 'node_modules') {
184 // one more relative without starting 'node_modules'
185 relatives.push(relatives[0].slice('node_modules'.length + 1));
186 }
187
188 var uplevels = [];
189 var maxUplevels = xpdn.split(require('path').sep).length;
190 for (var i = 0, u = ''; i < maxUplevels; i += 1) {
191 uplevels.push(u);
192 u += '/..';
193 }
194
195 var results = [];
196 uplevels.forEach(function (uplevel) {
197 relatives.forEach(function (relative) {
198 results.push(require('path').join(
199 xpdn,
200 uplevel,
201 relative
202 ));
203 });
204 });
205 return results;
206}
207
208function projectToNearby (f) {
209 return require('path').join(
210 require('path').dirname(
211 EXECPATH
212 ),
213 require('path').basename(
214 f
215 )
216 );
217}
218
219function findNativeAddonSyncFreeFromRequire (path) {
220 if (!insideSnapshot(path)) throw new Error('UNEXPECTED-10');
221 if (path.slice(-5) !== '.node') return null; // leveldown.node.js
222 // check mearby first to prevent .node tampering
223 var projector = projectToNearby(path);
224 if (require('fs').existsSync(projector)) return projector;
225 var projectors = projectToFilesystem(path);
226 for (var i = 0; i < projectors.length; i += 1) {
227 if (require('fs').existsSync(projectors[i])) return projectors[i];
228 }
229 return null;
230}
231
232function findNativeAddonSyncUnderRequire (path) {
233 if (!FLAG_ENABLE_PROJECT) return null;
234 return findNativeAddonSyncFreeFromRequire(path);
235}
236
237// /////////////////////////////////////////////////////////////////
238// FLOW UTILS //////////////////////////////////////////////////////
239// /////////////////////////////////////////////////////////////////
240
241function asap (cb) {
242 process.nextTick(cb);
243}
244
245function dezalgo (cb) {
246 if (!cb) return cb;
247
248 var sync = true;
249 asap(function () {
250 sync = false;
251 });
252
253 return function zalgoSafe () {
254 var args = arguments;
255 if (sync) {
256 asap(function () {
257 cb.apply(undefined, args);
258 });
259 } else {
260 cb.apply(undefined, args);
261 }
262 };
263}
264
265function rethrow (error, arg) {
266 if (error) throw error;
267 return arg;
268}
269
270// /////////////////////////////////////////////////////////////////
271// PAYLOAD /////////////////////////////////////////////////////////
272// /////////////////////////////////////////////////////////////////
273
274if (typeof PAYLOAD_POSITION !== 'number' ||
275 typeof PAYLOAD_SIZE !== 'number') {
276 throw new Error('MUST HAVE PAYLOAD');
277}
278
279var readPayload = function (buffer, offset, length, position, callback) {
280 require('fs').read(EXECPATH_FD,
281 buffer, offset, length, PAYLOAD_POSITION + position, callback);
282};
283
284var readPayloadSync = function (buffer, offset, length, position) {
285 return require('fs').readSync(EXECPATH_FD,
286 buffer, offset, length, PAYLOAD_POSITION + position);
287};
288
289function payloadCopyUni (source, target, targetStart, sourceStart, sourceEnd, cb) {
290 var cb2 = cb || rethrow;
291 if (sourceStart >= source[1]) return cb2(null, 0);
292 if (sourceEnd >= source[1]) sourceEnd = source[1];
293 var payloadPos = source[0] + sourceStart;
294 var targetPos = targetStart;
295 var targetEnd = targetStart + sourceEnd - sourceStart;
296 if (cb) {
297 readPayload(target, targetPos, targetEnd - targetPos, payloadPos, cb);
298 } else {
299 return readPayloadSync(target, targetPos, targetEnd - targetPos, payloadPos);
300 }
301}
302
303function payloadCopyMany (source, target, targetStart, sourceStart, cb) {
304 var payloadPos = source[0] + sourceStart;
305 var targetPos = targetStart;
306 var targetEnd = targetStart + source[1] - sourceStart;
307 readPayload(target, targetPos, targetEnd - targetPos, payloadPos, function (error, chunkSize) {
308 if (error) return cb(error);
309 sourceStart += chunkSize;
310 targetPos += chunkSize;
311 if (chunkSize !== 0 && targetPos < targetEnd) {
312 payloadCopyMany(source, target, targetPos, sourceStart, cb);
313 } else {
314 return cb();
315 }
316 });
317}
318
319function payloadCopyManySync (source, target, targetStart, sourceStart) {
320 var payloadPos = source[0] + sourceStart;
321 var targetPos = targetStart;
322 var targetEnd = targetStart + source[1] - sourceStart;
323 var chunkSize;
324 while (true) {
325 chunkSize = readPayloadSync(target, targetPos, targetEnd - targetPos, payloadPos);
326 payloadPos += chunkSize;
327 targetPos += chunkSize;
328 if (!(chunkSize !== 0 && targetPos < targetEnd)) break;
329 }
330}
331
332function payloadFile (pointer, cb) {
333 var target = Buffer.alloc(pointer[1]);
334 payloadCopyMany(pointer, target, 0, 0, function (error) {
335 if (error) return cb(error);
336 cb(null, target);
337 });
338}
339
340function payloadFileSync (pointer) {
341 var target = Buffer.alloc(pointer[1]);
342 payloadCopyManySync(pointer, target, 0, 0);
343 return target;
344}
345
346// /////////////////////////////////////////////////////////////////
347// SETUP PROCESS ///////////////////////////////////////////////////
348// /////////////////////////////////////////////////////////////////
349
350(function () {
351 process.pkg = {};
352 process.versions.pkg = '%VERSION%';
353 process.pkg.mount = createMountpoint;
354 process.pkg.entrypoint = ENTRYPOINT;
355 process.pkg.defaultEntrypoint = DEFAULT_ENTRYPOINT;
356}());
357
358// /////////////////////////////////////////////////////////////////
359// PATH.RESOLVE REPLACEMENT ////////////////////////////////////////
360// /////////////////////////////////////////////////////////////////
361
362(function () {
363 var path = require('path');
364
365 process.pkg.path = {};
366 process.pkg.path.resolve = function () {
367 var args = cloneArgs(arguments);
368 args.unshift(path.dirname(ENTRYPOINT));
369 return path.resolve.apply(path, args); // eslint-disable-line prefer-spread
370 };
371}());
372
373// /////////////////////////////////////////////////////////////////
374// PATCH FS ////////////////////////////////////////////////////////
375// /////////////////////////////////////////////////////////////////
376
377(function () {
378 var fs = require('fs');
379 var ancestor = {};
380 ancestor.openSync = fs.openSync;
381 ancestor.open = fs.open;
382 ancestor.readSync = fs.readSync;
383 ancestor.read = fs.read;
384 ancestor.writeSync = fs.writeSync;
385 ancestor.write = fs.write;
386 ancestor.closeSync = fs.closeSync;
387 ancestor.close = fs.close;
388 ancestor.readFileSync = fs.readFileSync;
389 ancestor.readFile = fs.readFile;
390 // ancestor.writeFileSync = fs.writeFileSync; // based on openSync/writeSync/closeSync
391 // ancestor.writeFile = fs.writeFile; // based on open/write/close
392 ancestor.readdirSync = fs.readdirSync;
393 ancestor.readdir = fs.readdir;
394 ancestor.realpathSync = fs.realpathSync;
395 ancestor.realpath = fs.realpath;
396 ancestor.statSync = fs.statSync;
397 ancestor.stat = fs.stat;
398 ancestor.lstatSync = fs.lstatSync;
399 ancestor.lstat = fs.lstat;
400 ancestor.fstatSync = fs.fstatSync;
401 ancestor.fstat = fs.fstat;
402 ancestor.existsSync = fs.existsSync;
403 ancestor.exists = fs.exists;
404 ancestor.accessSync = fs.accessSync;
405 ancestor.access = fs.access;
406
407 var windows = process.platform === 'win32';
408
409 var docks = {};
410 var ENOTDIR = windows ? 4052 : 20;
411 var ENOENT = windows ? 4058 : 2;
412 var EISDIR = windows ? 4068 : 21;
413
414 function assertEncoding (encoding) {
415 if (encoding && !Buffer.isEncoding(encoding)) {
416 throw new Error('Unknown encoding: ' + encoding);
417 }
418 }
419
420 function maybeCallback (args) {
421 var cb = args[args.length - 1];
422 return typeof cb === 'function' ? cb : rethrow;
423 }
424
425 function error_ENOENT (fileOrDirectory, path) { // eslint-disable-line camelcase
426 var error = new Error(
427 fileOrDirectory + ' \'' + stripSnapshot(path) + '\' ' +
428 'was not included into executable at compilation stage. ' +
429 'Please recompile adding it as asset or script.'
430 );
431 error.errno = -ENOENT;
432 error.code = 'ENOENT';
433 error.path = path;
434 error.pkg = true;
435 return error;
436 }
437
438 function error_EISDIR (path) { // eslint-disable-line camelcase
439 var error = new Error(
440 'EISDIR: illegal operation on a directory, read'
441 );
442 error.errno = -EISDIR;
443 error.code = 'EISDIR';
444 error.path = path;
445 error.pkg = true;
446 return error;
447 }
448
449 function error_ENOTDIR (path) { // eslint-disable-line camelcase
450 var error = new Error(
451 'ENOTDIR: not a directory, scandir \'' + path + '\''
452 );
453 error.errno = -ENOTDIR;
454 error.code = 'ENOTDIR';
455 error.path = path;
456 error.pkg = true;
457 return error;
458 }
459
460 // ///////////////////////////////////////////////////////////////
461 // open //////////////////////////////////////////////////////////
462 // ///////////////////////////////////////////////////////////////
463
464 function openFromSnapshot (path_, cb) {
465 var cb2 = cb || rethrow;
466 var path = normalizePath(path_);
467 // console.log("openFromSnapshot", path);
468 var entity = VIRTUAL_FILESYSTEM[path];
469 if (!entity) return cb2(error_ENOENT('File or directory', path));
470 var dock = { path: path, entity: entity, position: 0 };
471 var nullDevice = windows ? '\\\\.\\NUL' : '/dev/null';
472 if (cb) {
473 ancestor.open.call(fs, nullDevice, 'r', function (error, fd) {
474 if (error) return cb(error);
475 docks[fd] = dock;
476 cb(null, fd);
477 });
478 } else {
479 var fd = ancestor.openSync.call(fs, nullDevice, 'r');
480 docks[fd] = dock;
481 return fd;
482 }
483 }
484
485 fs.openSync = function (path) {
486 if (!insideSnapshot(path)) {
487 return ancestor.openSync.apply(fs, arguments);
488 }
489 if (insideMountpoint(path)) {
490 return ancestor.openSync.apply(fs, translateNth(arguments, 0, path));
491 }
492
493 return openFromSnapshot(path);
494 };
495
496 fs.open = function (path) {
497 if (!insideSnapshot(path)) {
498 return ancestor.open.apply(fs, arguments);
499 }
500 if (insideMountpoint(path)) {
501 return ancestor.open.apply(fs, translateNth(arguments, 0, path));
502 }
503
504 var callback = dezalgo(maybeCallback(arguments));
505 openFromSnapshot(path, callback);
506 };
507
508 // ///////////////////////////////////////////////////////////////
509 // read //////////////////////////////////////////////////////////
510 // ///////////////////////////////////////////////////////////////
511
512 function readFromSnapshotSub (entityContent, dock, buffer, offset, length, position, cb) {
513 var p;
514 if ((position !== null) && (position !== undefined)) {
515 p = position;
516 } else {
517 p = dock.position;
518 }
519 if (cb) {
520 payloadCopyUni(entityContent, buffer, offset, p, p + length, function (error, bytesRead, buffer2) {
521 if (error) return cb(error);
522 dock.position = p + bytesRead;
523 cb(null, bytesRead, buffer2);
524 });
525 } else {
526 var bytesRead = payloadCopyUni(entityContent, buffer, offset, p, p + length);
527 dock.position = p + bytesRead;
528 return bytesRead;
529 }
530 }
531
532 function readFromSnapshot (fd, buffer, offset, length, position, cb) {
533 var cb2 = cb || rethrow;
534 if ((offset < 0) && (NODE_VERSION_MAJOR >= 10)) return cb2(new Error(
535 'The value of "offset" is out of range. It must be >= 0 && <= ' + buffer.length.toString() + '. Received ' + offset));
536 if (offset < 0) return cb2(new Error('Offset is out of bounds'));
537 if ((offset >= buffer.length) && (NODE_VERSION_MAJOR >= 6)) return cb2(null, 0);
538 if (offset >= buffer.length) return cb2(new Error('Offset is out of bounds'));
539 if ((offset + length > buffer.length) && (NODE_VERSION_MAJOR >= 10)) return cb2(new Error(
540 'The value of "length" is out of range. It must be >= 0 && <= ' + (buffer.length - offset).toString() + '. Received ' + length.toString()));
541 if (offset + length > buffer.length) return cb2(new Error('Length extends beyond buffer'));
542
543 var dock = docks[fd];
544 var entity = dock.entity;
545 var entityLinks = entity[STORE_LINKS];
546 if (entityLinks) return cb2(error_EISDIR(dock.path));
547 var entityContent = entity[STORE_CONTENT];
548 if (entityContent) return readFromSnapshotSub(entityContent, dock, buffer, offset, length, position, cb);
549 return cb2(new Error('UNEXPECTED-15'));
550 }
551
552 fs.readSync = function (fd, buffer, offset, length, position) {
553 if (!docks[fd]) {
554 return ancestor.readSync.apply(fs, arguments);
555 }
556
557 return readFromSnapshot(fd, buffer, offset, length, position);
558 };
559
560 fs.read = function (fd, buffer, offset, length, position) {
561 if (!docks[fd]) {
562 return ancestor.read.apply(fs, arguments);
563 }
564
565 var callback = dezalgo(maybeCallback(arguments));
566 readFromSnapshot(fd, buffer, offset, length, position, callback);
567 };
568
569 // ///////////////////////////////////////////////////////////////
570 // write /////////////////////////////////////////////////////////
571 // ///////////////////////////////////////////////////////////////
572
573 function writeToSnapshot (cb) {
574 var cb2 = cb || rethrow;
575 return cb2(new Error('Cannot write to packaged file'));
576 }
577
578 fs.writeSync = function (fd) {
579 if (!docks[fd]) {
580 return ancestor.writeSync.apply(fs, arguments);
581 }
582
583 return writeToSnapshot();
584 };
585
586 fs.write = function (fd) {
587 if (!docks[fd]) {
588 return ancestor.write.apply(fs, arguments);
589 }
590
591 var callback = dezalgo(maybeCallback(arguments));
592 writeToSnapshot(callback);
593 };
594
595 // ///////////////////////////////////////////////////////////////
596 // close /////////////////////////////////////////////////////////
597 // ///////////////////////////////////////////////////////////////
598
599 function closeFromSnapshot (fd, cb) {
600 delete docks[fd];
601 if (cb) {
602 ancestor.close.call(fs, fd, cb);
603 } else {
604 return ancestor.closeSync.call(fs, fd);
605 }
606 }
607
608 fs.closeSync = function (fd) {
609 if (!docks[fd]) {
610 return ancestor.closeSync.apply(fs, arguments);
611 }
612
613 return closeFromSnapshot(fd);
614 };
615
616 fs.close = function (fd) {
617 if (!docks[fd]) {
618 return ancestor.close.apply(fs, arguments);
619 }
620
621 var callback = dezalgo(maybeCallback(arguments));
622 closeFromSnapshot(fd, callback);
623 };
624
625 // ///////////////////////////////////////////////////////////////
626 // readFile //////////////////////////////////////////////////////
627 // ///////////////////////////////////////////////////////////////
628
629 function readFileOptions (options, hasCallback) {
630 if (!options || (hasCallback && typeof options === 'function')) {
631 return { encoding: null, flag: 'r' };
632 } else if (typeof options === 'string') {
633 return { encoding: options, flag: 'r' };
634 } else if (typeof options === 'object') {
635 return options;
636 } else {
637 return null;
638 }
639 }
640
641 function readFileFromSnapshotSub (entityContent, cb) {
642 if (cb) {
643 payloadFile(entityContent, cb);
644 } else {
645 return payloadFileSync(entityContent);
646 }
647 }
648
649 function readFileFromSnapshot (path_, cb) {
650 var cb2 = cb || rethrow;
651 var path = normalizePath(path_);
652 // console.log("readFileFromSnapshot", path);
653 var entity = VIRTUAL_FILESYSTEM[path];
654 if (!entity) return cb2(error_ENOENT('File', path));
655 var entityLinks = entity[STORE_LINKS];
656 if (entityLinks) return cb2(error_EISDIR(path));
657 var entityContent = entity[STORE_CONTENT];
658 if (entityContent) return readFileFromSnapshotSub(entityContent, cb);
659 var entityBlob = entity[STORE_BLOB];
660 if (entityBlob) return cb2(null, Buffer.from('source-code-not-available'));
661
662 // why return empty buffer?
663 // otherwise this error will arise:
664 // Error: UNEXPECTED-20
665 // at readFileFromSnapshot (e:0)
666 // at Object.fs.readFileSync (e:0)
667 // at Object.Module._extensions..js (module.js:421:20)
668 // at Module.load (module.js:357:32)
669 // at Function.Module._load (module.js:314:12)
670 // at Function.Module.runMain (e:0)
671 // at startup (node.js:140:18)
672 // at node.js:1001:3
673
674 return cb2(new Error('UNEXPECTED-20'));
675 }
676
677 fs.readFileSync = function (path, options_) {
678 if (path === 'dirty-hack-for-testing-purposes') {
679 return path;
680 }
681
682 if (!insideSnapshot(path)) {
683 return ancestor.readFileSync.apply(fs, arguments);
684 }
685 if (insideMountpoint(path)) {
686 return ancestor.readFileSync.apply(fs, translateNth(arguments, 0, path));
687 }
688
689 var options = readFileOptions(options_, false);
690
691 if (!options) {
692 return ancestor.readFileSync.apply(fs, arguments);
693 }
694
695 var encoding = options.encoding;
696 assertEncoding(encoding);
697
698 var buffer = readFileFromSnapshot(path);
699 if (encoding) buffer = buffer.toString(encoding);
700 return buffer;
701 };
702
703 fs.readFile = function (path, options_) {
704 if (!insideSnapshot(path)) {
705 return ancestor.readFile.apply(fs, arguments);
706 }
707 if (insideMountpoint(path)) {
708 return ancestor.readFile.apply(fs, translateNth(arguments, 0, path));
709 }
710
711 var options = readFileOptions(options_, true);
712
713 if (!options) {
714 return ancestor.readFile.apply(fs, arguments);
715 }
716
717 var encoding = options.encoding;
718 assertEncoding(encoding);
719
720 var callback = dezalgo(maybeCallback(arguments));
721 readFileFromSnapshot(path, function (error, buffer) {
722 if (error) return callback(error);
723 if (encoding) buffer = buffer.toString(encoding);
724 callback(null, buffer);
725 });
726 };
727
728 // ///////////////////////////////////////////////////////////////
729 // writeFile /////////////////////////////////////////////////////
730 // ///////////////////////////////////////////////////////////////
731
732 // writeFileSync based on openSync/writeSync/closeSync
733 // writeFile based on open/write/close
734
735 // ///////////////////////////////////////////////////////////////
736 // readdir ///////////////////////////////////////////////////////
737 // ///////////////////////////////////////////////////////////////
738
739 function readdirOptions (options, hasCallback) {
740 if (!options || (hasCallback && typeof options === 'function')) {
741 return { encoding: null };
742 } else if (typeof options === 'string') {
743 return { encoding: options };
744 } else if (typeof options === 'object') {
745 return options;
746 } else {
747 return null;
748 }
749 }
750
751 function Dirent (name, type) {
752 this.name = name;
753 this.type = type;
754 }
755
756 Dirent.prototype.isDirectory = function () {
757 return this.type === 2;
758 };
759
760 Dirent.prototype.isFile = function () {
761 return this.type === 1;
762 };
763
764 Dirent.prototype.isBlockDevice =
765 Dirent.prototype.isCharacterDevice =
766 Dirent.prototype.isSymbolicLink =
767 Dirent.prototype.isFIFO =
768 Dirent.prototype.isSocket = function () {
769 return false;
770 };
771
772 function getFileTypes (path_, entries) {
773 return entries.map(function (entry) {
774 var path = require('path').join(path_, entry);
775 var entity = VIRTUAL_FILESYSTEM[path];
776 if (entity[STORE_BLOB] || entity[STORE_CONTENT]) return new Dirent(entry, 1);
777 if (entity[STORE_LINKS]) return new Dirent(entry, 2);
778 throw new Error('UNEXPECTED-24');
779 });
780 }
781
782 function readdirRoot (path, cb) {
783 if (cb) {
784 ancestor.readdir(path, function (error, entries) {
785 if (error) return cb(error);
786 entries.push('snapshot');
787 cb(null, entries);
788 });
789 } else {
790 var entries = ancestor.readdirSync(path);
791 entries.push('snapshot');
792 return entries;
793 }
794 }
795
796 function readdirFromSnapshotSub (entityLinks, path, cb) {
797 if (cb) {
798 payloadFile(entityLinks, function (error, buffer) {
799 if (error) return cb(error);
800 cb(null, JSON.parse(buffer).concat(readdirMountpoints(path)));
801 });
802 } else {
803 var buffer = payloadFileSync(entityLinks);
804 return JSON.parse(buffer).concat(readdirMountpoints(path));
805 }
806 }
807
808 function readdirFromSnapshot (path_, isRoot, cb) {
809 var cb2 = cb || rethrow;
810 if (isRoot) return readdirRoot(path_, cb);
811 var path = normalizePath(path_);
812 // console.log("readdirFromSnapshot", path);
813 var entity = VIRTUAL_FILESYSTEM[path];
814 if (!entity) return cb2(error_ENOENT('Directory', path));
815 var entityBlob = entity[STORE_BLOB];
816 if (entityBlob) return cb2(error_ENOTDIR(path));
817 var entityContent = entity[STORE_CONTENT];
818 if (entityContent) return cb2(error_ENOTDIR(path));
819 var entityLinks = entity[STORE_LINKS];
820 if (entityLinks) return readdirFromSnapshotSub(entityLinks, path, cb);
821 return cb2(new Error('UNEXPECTED-25'));
822 }
823
824 fs.readdirSync = function (path, options_) {
825 var isRoot = isRootPath(path);
826
827 if (!insideSnapshot(path) && !isRoot) {
828 return ancestor.readdirSync.apply(fs, arguments);
829 }
830 if (insideMountpoint(path)) {
831 return ancestor.readdirSync.apply(fs, translateNth(arguments, 0, path));
832 }
833
834 var options = readdirOptions(options_, false);
835
836 if (!options) {
837 return ancestor.readdirSync.apply(fs, arguments);
838 }
839
840 var entries = readdirFromSnapshot(path, isRoot);
841 if (options.withFileTypes) entries = getFileTypes(path, entries);
842 return entries;
843 };
844
845 fs.readdir = function (path, options_) {
846 var isRoot = isRootPath(path);
847
848 if (!insideSnapshot(path) && !isRoot) {
849 return ancestor.readdir.apply(fs, arguments);
850 }
851 if (insideMountpoint(path)) {
852 return ancestor.readdir.apply(fs, translateNth(arguments, 0, path));
853 }
854
855 var options = readdirOptions(options_, true);
856
857 if (!options) {
858 return ancestor.readdir.apply(fs, arguments);
859 }
860
861 var callback = dezalgo(maybeCallback(arguments));
862 readdirFromSnapshot(path, isRoot, function (error, entries) {
863 if (error) return callback(error);
864 if (options.withFileTypes) entries = getFileTypes(path, entries);
865 callback(null, entries);
866 });
867 };
868
869 // ///////////////////////////////////////////////////////////////
870 // realpath //////////////////////////////////////////////////////
871 // ///////////////////////////////////////////////////////////////
872
873 function realpathFromSnapshot (path_) {
874 var path = normalizePath(path_);
875 // console.log("realpathFromSnapshot", path);
876 return path;
877 }
878
879 fs.realpathSync = function (path) {
880 if (!insideSnapshot(path)) {
881 return ancestor.realpathSync.apply(fs, arguments);
882 }
883 if (insideMountpoint(path)) {
884 // app should not know real file name
885 }
886
887 return realpathFromSnapshot(path);
888 };
889
890 fs.realpath = function (path) {
891 if (!insideSnapshot(path)) {
892 return ancestor.realpath.apply(fs, arguments);
893 }
894 if (insideMountpoint(path)) {
895 // app should not know real file name
896 }
897
898 var callback = dezalgo(maybeCallback(arguments));
899 callback(null, realpathFromSnapshot(path));
900 };
901
902 // ///////////////////////////////////////////////////////////////
903 // stat //////////////////////////////////////////////////////////
904 // ///////////////////////////////////////////////////////////////
905
906 function restore (s) {
907 s.blksize = 4096;
908 s.blocks = 0;
909 s.dev = 0;
910 s.gid = 20;
911 s.ino = 0;
912 s.nlink = 0;
913 s.rdev = 0;
914 s.uid = 500;
915
916 s.atime = new Date(EXECSTAT.atime);
917 s.mtime = new Date(EXECSTAT.mtime);
918 s.ctime = new Date(EXECSTAT.ctime);
919 s.birthtime = new Date(EXECSTAT.birthtime);
920
921 s.atimeMs = EXECSTAT.atimeMs;
922 s.mtimeMs = EXECSTAT.mtimeMs;
923 s.ctimeMs = EXECSTAT.ctimeMs;
924 s.birthtimeMs = EXECSTAT.birthtimeMs;
925
926 var isFileValue = s.isFileValue;
927 var isDirectoryValue = s.isDirectoryValue;
928 delete s.isFileValue;
929 delete s.isDirectoryValue;
930
931 s.isFile = function () {
932 return isFileValue;
933 };
934 s.isDirectory = function () {
935 return isDirectoryValue;
936 };
937 s.isSymbolicLink = function () {
938 return false;
939 };
940 s.isFIFO = function () {
941 return false;
942 };
943
944 return s;
945 }
946
947 function findNativeAddonForStat (path, cb) {
948 var cb2 = cb || rethrow;
949 var foundPath = findNativeAddonSyncUnderRequire(path);
950 if (!foundPath) return cb2(error_ENOENT('File or directory', path));
951 if (cb) {
952 ancestor.stat.call(fs, foundPath, cb);
953 } else {
954 return ancestor.statSync.call(fs, foundPath);
955 }
956 }
957
958 function statFromSnapshotSub (entityStat, cb) {
959 if (cb) {
960 payloadFile(entityStat, function (error, buffer) {
961 if (error) return cb(error);
962 cb(null, restore(JSON.parse(buffer)));
963 });
964 } else {
965 var buffer = payloadFileSync(entityStat);
966 return restore(JSON.parse(buffer));
967 }
968 }
969
970 function statFromSnapshot (path_, cb) {
971 var cb2 = cb || rethrow;
972 var path = normalizePath(path_);
973 // console.log("statFromSnapshot", path);
974 var entity = VIRTUAL_FILESYSTEM[path];
975 if (!entity) return findNativeAddonForStat(path, cb);
976 var entityStat = entity[STORE_STAT];
977 if (entityStat) return statFromSnapshotSub(entityStat, cb);
978 return cb2(new Error('UNEXPECTED-35'));
979 }
980
981 fs.statSync = function (path) {
982 if (!insideSnapshot(path)) {
983 return ancestor.statSync.apply(fs, arguments);
984 }
985 if (insideMountpoint(path)) {
986 return ancestor.statSync.apply(fs, translateNth(arguments, 0, path));
987 }
988
989 return statFromSnapshot(path);
990 };
991
992 fs.stat = function (path) {
993 if (!insideSnapshot(path)) {
994 return ancestor.stat.apply(fs, arguments);
995 }
996 if (insideMountpoint(path)) {
997 return ancestor.stat.apply(fs, translateNth(arguments, 0, path));
998 }
999
1000 var callback = dezalgo(maybeCallback(arguments));
1001 statFromSnapshot(path, callback);
1002 };
1003
1004 // ///////////////////////////////////////////////////////////////
1005 // lstat /////////////////////////////////////////////////////////
1006 // ///////////////////////////////////////////////////////////////
1007
1008 fs.lstatSync = function (path) {
1009 if (!insideSnapshot(path)) {
1010 return ancestor.lstatSync.apply(fs, arguments);
1011 }
1012 if (insideMountpoint(path)) {
1013 return ancestor.lstatSync.apply(fs, translateNth(arguments, 0, path));
1014 }
1015
1016 return statFromSnapshot(path);
1017 };
1018
1019 fs.lstat = function (path) {
1020 if (!insideSnapshot(path)) {
1021 return ancestor.lstat.apply(fs, arguments);
1022 }
1023 if (insideMountpoint(path)) {
1024 return ancestor.lstat.apply(fs, translateNth(arguments, 0, path));
1025 }
1026
1027 var callback = dezalgo(maybeCallback(arguments));
1028 statFromSnapshot(path, callback);
1029 };
1030
1031 // ///////////////////////////////////////////////////////////////
1032 // fstat /////////////////////////////////////////////////////////
1033 // ///////////////////////////////////////////////////////////////
1034
1035 function fstatFromSnapshot (fd, cb) {
1036 var cb2 = cb || rethrow;
1037 var entity = docks[fd].entity;
1038 var entityStat = entity[STORE_STAT];
1039 if (entityStat) return statFromSnapshotSub(entityStat, cb);
1040 return cb2(new Error('UNEXPECTED-40'));
1041 }
1042
1043 fs.fstatSync = function (fd) {
1044 if (!docks[fd]) {
1045 return ancestor.fstatSync.apply(fs, arguments);
1046 }
1047
1048 return fstatFromSnapshot(fd);
1049 };
1050
1051 fs.fstat = function (fd) {
1052 if (!docks[fd]) {
1053 return ancestor.fstat.apply(fs, arguments);
1054 }
1055
1056 var callback = dezalgo(maybeCallback(arguments));
1057 fstatFromSnapshot(fd, callback);
1058 };
1059
1060 // ///////////////////////////////////////////////////////////////
1061 // exists ////////////////////////////////////////////////////////
1062 // ///////////////////////////////////////////////////////////////
1063
1064 function findNativeAddonForExists (path) {
1065 var foundPath = findNativeAddonSyncFreeFromRequire(path);
1066 if (!foundPath) return false;
1067 return ancestor.existsSync.call(fs, foundPath);
1068 }
1069
1070 function existsFromSnapshot (path_) {
1071 var path = normalizePath(path_);
1072 // console.log("existsFromSnapshot", path);
1073 var entity = VIRTUAL_FILESYSTEM[path];
1074 if (!entity) return findNativeAddonForExists(path);
1075 return true;
1076 }
1077
1078 fs.existsSync = function (path) {
1079 if (!insideSnapshot(path)) {
1080 return ancestor.existsSync.apply(fs, arguments);
1081 }
1082 if (insideMountpoint(path)) {
1083 return ancestor.existsSync.apply(fs, translateNth(arguments, 0, path));
1084 }
1085
1086 return existsFromSnapshot(path);
1087 };
1088
1089 fs.exists = function (path) {
1090 if (!insideSnapshot(path)) {
1091 return ancestor.exists.apply(fs, arguments);
1092 }
1093 if (insideMountpoint(path)) {
1094 return ancestor.exists.apply(fs, translateNth(arguments, 0, path));
1095 }
1096
1097 var callback = dezalgo(maybeCallback(arguments));
1098 callback(existsFromSnapshot(path));
1099 };
1100
1101 // ///////////////////////////////////////////////////////////////
1102 // access ////////////////////////////////////////////////////////
1103 // ///////////////////////////////////////////////////////////////
1104
1105 function accessFromSnapshot (path_, cb) {
1106 var cb2 = cb || rethrow;
1107 var path = normalizePath(path_);
1108 // console.log("accessFromSnapshot", path);
1109 var entity = VIRTUAL_FILESYSTEM[path];
1110 if (!entity) return cb2(error_ENOENT('File or directory', path));
1111 return cb2(null, undefined);
1112 }
1113
1114 fs.accessSync = function (path) {
1115 if (!insideSnapshot(path)) {
1116 return ancestor.accessSync.apply(fs, arguments);
1117 }
1118 if (insideMountpoint(path)) {
1119 return ancestor.accessSync.apply(fs, translateNth(arguments, 0, path));
1120 }
1121
1122 return accessFromSnapshot(path);
1123 };
1124
1125 fs.access = function (path) {
1126 if (!insideSnapshot(path)) {
1127 return ancestor.access.apply(fs, arguments);
1128 }
1129 if (insideMountpoint(path)) {
1130 return ancestor.access.apply(fs, translateNth(arguments, 0, path));
1131 }
1132
1133 var callback = dezalgo(maybeCallback(arguments));
1134 accessFromSnapshot(path, callback);
1135 };
1136
1137 // ///////////////////////////////////////////////////////////////
1138 // INTERNAL //////////////////////////////////////////////////////
1139 // ///////////////////////////////////////////////////////////////
1140
1141 function makeLong (f) {
1142 return require('path')._makeLong(f);
1143 }
1144
1145 function revertMakingLong (f) {
1146 if (/^\\\\\?\\/.test(f)) return f.slice(4);
1147 return f;
1148 }
1149
1150 function findNativeAddonForInternalModuleStat (path_) {
1151 var path = findNativeAddonSyncUnderRequire(path_);
1152 if (!path) return -ENOENT;
1153 return process.binding('fs').internalModuleStat(makeLong(path));
1154 }
1155
1156 fs.internalModuleStat = function (long) {
1157 // from node comments:
1158 // Used to speed up module loading. Returns 0 if the path refers to
1159 // a file, 1 when it's a directory or < 0 on error (usually -ENOENT).
1160 // The speedup comes from not creating thousands of Stat and Error objects.
1161
1162 var path = revertMakingLong(long);
1163
1164 if (!insideSnapshot(path)) {
1165 return process.binding('fs').internalModuleStat(long);
1166 }
1167 if (insideMountpoint(path)) {
1168 return process.binding('fs').internalModuleStat(makeLong(translate(path)));
1169 }
1170
1171 path = normalizePath(path);
1172 // console.log("internalModuleStat", path);
1173 var entity = VIRTUAL_FILESYSTEM[path];
1174 if (!entity) return findNativeAddonForInternalModuleStat(path);
1175 var entityBlob = entity[STORE_BLOB];
1176 if (entityBlob) return 0;
1177 var entityContent = entity[STORE_CONTENT];
1178 if (entityContent) return 0;
1179 var entityLinks = entity[STORE_LINKS];
1180 if (entityLinks) return 1;
1181 return -ENOENT;
1182 };
1183
1184 fs.internalModuleReadFile = fs.internalModuleReadJSON = function (long) {
1185 // from node comments:
1186 // Used to speed up module loading. Returns the contents of the file as
1187 // a string or undefined when the file cannot be opened. The speedup
1188 // comes from not creating Error objects on failure.
1189
1190 var path = revertMakingLong(long);
1191 var bindingFs = process.binding('fs');
1192 var readFile = (bindingFs.internalModuleReadFile ||
1193 bindingFs.internalModuleReadJSON).bind(bindingFs);
1194 if (!insideSnapshot(path)) {
1195 return readFile(long);
1196 }
1197 if (insideMountpoint(path)) {
1198 return readFile(makeLong(translate(path)));
1199 }
1200
1201 path = normalizePath(path);
1202 // console.log("internalModuleReadFile", path);
1203 var entity = VIRTUAL_FILESYSTEM[path];
1204 if (!entity) return undefined;
1205 var entityContent = entity[STORE_CONTENT];
1206 if (!entityContent) return undefined;
1207 return payloadFileSync(entityContent).toString();
1208 };
1209}());
1210
1211// /////////////////////////////////////////////////////////////////
1212// PATCH MODULE ////////////////////////////////////////////////////
1213// /////////////////////////////////////////////////////////////////
1214
1215(function () {
1216 var Module = require('module');
1217 var ancestor = {};
1218 ancestor.require = Module.prototype.require;
1219 ancestor._compile = Module.prototype._compile;
1220 ancestor._resolveFilename = Module._resolveFilename;
1221 ancestor.runMain = Module.runMain;
1222
1223 Module.prototype.require = function (path) {
1224 try {
1225 return ancestor.require.apply(this, arguments);
1226 } catch (error) {
1227 if (((error.code === 'ENOENT') ||
1228 (error.code === 'MODULE_NOT_FOUND')) &&
1229 (!insideSnapshot(path)) &&
1230 (!require('path').isAbsolute(path))) {
1231 if (!error.pkg) {
1232 error.pkg = true;
1233 error.message += '\n' +
1234 '1) If you want to compile the package/file into ' +
1235 'executable, please pay attention to compilation ' +
1236 'warnings and specify a literal in \'require\' call. ' +
1237 '2) If you don\'t want to compile the package/file ' +
1238 'into executable and want to \'require\' it from ' +
1239 'filesystem (likely plugin), specify an absolute ' +
1240 'path in \'require\' call using process.cwd() or ' +
1241 'process.execPath.';
1242 }
1243 }
1244 throw error;
1245 }
1246 };
1247
1248 var im, makeRequireFunction;
1249
1250 if (NODE_VERSION_MAJOR === 0) {
1251 makeRequireFunction = function (self) {
1252 function rqfn (path) {
1253 return self.require(path);
1254 }
1255 rqfn.resolve = function (request) {
1256 return Module._resolveFilename(request, self);
1257 };
1258 rqfn.main = process.mainModule;
1259 rqfn.extensions = Module._extensions;
1260 rqfn.cache = Module._cache;
1261 return rqfn;
1262 };
1263 } else
1264 if (NODE_VERSION_MAJOR <= 9) {
1265 im = require('internal/module');
1266 if (NODE_VERSION_MAJOR <= 7) {
1267 makeRequireFunction = function (m) {
1268 return im.makeRequireFunction.call(m);
1269 };
1270 } else {
1271 makeRequireFunction = im.makeRequireFunction;
1272 }
1273 } else {
1274 im = require('internal/modules/cjs/helpers');
1275 makeRequireFunction = im.makeRequireFunction;
1276 // TODO esm modules along with cjs
1277 }
1278
1279 Module.prototype._compile = function (content, filename_) {
1280 if (!insideSnapshot(filename_)) {
1281 return ancestor._compile.apply(this, arguments);
1282 }
1283 if (insideMountpoint(filename_)) {
1284 // DONT TRANSLATE! otherwise __dirname gets real name
1285 return ancestor._compile.apply(this, arguments);
1286 }
1287
1288 var filename = normalizePath(filename_);
1289 // console.log("_compile", filename);
1290 var entity = VIRTUAL_FILESYSTEM[filename];
1291
1292 if (!entity) {
1293 // let user try to "_compile" a packaged file
1294 return ancestor._compile.apply(this, arguments);
1295 }
1296
1297 var entityBlob = entity[STORE_BLOB];
1298 var entityContent = entity[STORE_CONTENT];
1299
1300 if (entityBlob) {
1301 var options = {
1302 filename: filename,
1303 lineOffset: 0,
1304 displayErrors: true,
1305 cachedData: payloadFileSync(entityBlob),
1306 sourceless: !entityContent
1307 };
1308
1309 var Script = require('vm').Script;
1310 var code = entityContent
1311 ? require('module').wrap(payloadFileSync(entityContent))
1312 : undefined;
1313
1314 var script = new Script(code, options);
1315 var wrapper = script.runInThisContext(options);
1316 if (!wrapper) process.exit(4); // for example VERSION_MISMATCH
1317 var dirname = require('path').dirname(filename);
1318 var rqfn = makeRequireFunction(this);
1319 var args = [ this.exports, rqfn, this, filename, dirname ];
1320 return wrapper.apply(this.exports, args);
1321 }
1322
1323 if (entityContent) {
1324 if (entityBlob) throw new Error('UNEXPECTED-50');
1325 // content is already in utf8 and without BOM (that is expected
1326 // by stock _compile), but entityContent is still a Buffer
1327 return ancestor._compile.apply(this, arguments);
1328 }
1329
1330 throw new Error('UNEXPECTED-55');
1331 };
1332
1333 Module._resolveFilename = function () {
1334 var filename;
1335 var flagWasOn = false;
1336
1337 try {
1338 filename = ancestor._resolveFilename.apply(this, arguments);
1339 } catch (error) {
1340 if (error.code !== 'MODULE_NOT_FOUND') throw error;
1341
1342 FLAG_ENABLE_PROJECT = true;
1343 var savePathCache = Module._pathCache;
1344 Module._pathCache = Object.create(null);
1345 try {
1346 filename = ancestor._resolveFilename.apply(this, arguments);
1347 flagWasOn = true;
1348 } finally {
1349 Module._pathCache = savePathCache;
1350 FLAG_ENABLE_PROJECT = false;
1351 }
1352 }
1353
1354 if (!insideSnapshot(filename)) {
1355 return filename;
1356 }
1357 if (insideMountpoint(filename)) {
1358 return filename;
1359 }
1360
1361 if (flagWasOn) {
1362 FLAG_ENABLE_PROJECT = true;
1363 try {
1364 var found = findNativeAddonSyncUnderRequire(filename);
1365 if (found) filename = found;
1366 } finally {
1367 FLAG_ENABLE_PROJECT = false;
1368 }
1369 }
1370
1371 return filename;
1372 };
1373
1374 Module.runMain = function () {
1375 Module._load(ENTRYPOINT, null, true);
1376 process._tickCallback();
1377 };
1378}());
1379
1380// /////////////////////////////////////////////////////////////////
1381// PATCH CHILD_PROCESS /////////////////////////////////////////////
1382// /////////////////////////////////////////////////////////////////
1383
1384(function () {
1385 var childProcess = require('child_process');
1386 var ancestor = {};
1387 ancestor.spawn = childProcess.spawn;
1388 ancestor.spawnSync = childProcess.spawnSync;
1389 ancestor.execFile = childProcess.execFile;
1390 ancestor.execFileSync = childProcess.execFileSync;
1391 ancestor.exec = childProcess.exec;
1392 ancestor.execSync = childProcess.execSync;
1393
1394 function setOptsEnv (args) {
1395 var pos = args.length - 1;
1396 if (typeof args[pos] === 'function') pos -= 1;
1397 if (typeof args[pos] !== 'object' || Array.isArray(args[pos])) {
1398 pos += 1;
1399 args.splice(pos, 0, {});
1400 }
1401 var opts = args[pos];
1402 if (!opts.env) opts.env = require('util')._extend({}, process.env);
1403 if (opts.env.PKG_EXECPATH === 'PKG_INVOKE_NODEJS') return;
1404 opts.env.PKG_EXECPATH = EXECPATH;
1405 }
1406
1407 function startsWith2 (args, index, name, impostor) {
1408 var qsName = '"' + name + ' ';
1409 if (args[index].slice(0, qsName.length) === qsName) {
1410 args[index] = '"' + impostor + ' ' + args[index].slice(qsName.length);
1411 return true;
1412 }
1413 var sName = name + ' ';
1414 if (args[index].slice(0, sName.length) === sName) {
1415 args[index] = impostor + ' ' + args[index].slice(sName.length);
1416 return true;
1417 }
1418 if (args[index] === name) {
1419 args[index] = impostor;
1420 return true;
1421 }
1422 return false;
1423 }
1424
1425 function startsWith (args, index, name) {
1426 var qName = '"' + name + '"';
1427 var qEXECPATH = '"' + EXECPATH + '"';
1428 var jsName = JSON.stringify(name);
1429 var jsEXECPATH = JSON.stringify(EXECPATH);
1430 return startsWith2(args, index, name, EXECPATH) ||
1431 startsWith2(args, index, qName, qEXECPATH) ||
1432 startsWith2(args, index, jsName, jsEXECPATH);
1433 }
1434
1435 function modifyLong (args, index) {
1436 if (!args[index]) return;
1437 return (startsWith(args, index, 'node') ||
1438 startsWith(args, index, ARGV0) ||
1439 startsWith(args, index, ENTRYPOINT) ||
1440 startsWith(args, index, EXECPATH));
1441 }
1442
1443 function modifyShort (args) {
1444 if (!args[0]) return;
1445 if (!Array.isArray(args[1])) {
1446 args.splice(1, 0, []);
1447 }
1448 if (args[0] === 'node' ||
1449 args[0] === ARGV0 ||
1450 args[0] === ENTRYPOINT ||
1451 args[0] === EXECPATH) {
1452 args[0] = EXECPATH;
1453 if (NODE_VERSION_MAJOR === 0) {
1454 args[1] = args[1].filter(function (a) {
1455 return (a.slice(0, 13) !== '--debug-port=');
1456 });
1457 }
1458 } else {
1459 for (var i = 1; i < args[1].length; i += 1) {
1460 var mbc = args[1][i - 1];
1461 if (mbc === '-c' || mbc === '/c') {
1462 modifyLong(args[1], i);
1463 }
1464 }
1465 }
1466 }
1467
1468 childProcess.spawn = function () {
1469 var args = cloneArgs(arguments);
1470 setOptsEnv(args);
1471 modifyShort(args);
1472 return ancestor.spawn.apply(childProcess, args);
1473 };
1474
1475 childProcess.spawnSync = function () {
1476 var args = cloneArgs(arguments);
1477 setOptsEnv(args);
1478 modifyShort(args);
1479 return ancestor.spawnSync.apply(childProcess, args);
1480 };
1481
1482 childProcess.execFile = function () {
1483 var args = cloneArgs(arguments);
1484 setOptsEnv(args);
1485 modifyShort(args);
1486 return ancestor.execFile.apply(childProcess, args);
1487 };
1488
1489 childProcess.execFileSync = function () {
1490 var args = cloneArgs(arguments);
1491 setOptsEnv(args);
1492 modifyShort(args);
1493 return ancestor.execFileSync.apply(childProcess, args);
1494 };
1495
1496 childProcess.exec = function () {
1497 var args = cloneArgs(arguments);
1498 setOptsEnv(args);
1499 modifyLong(args, 0);
1500 return ancestor.exec.apply(childProcess, args);
1501 };
1502
1503 childProcess.execSync = function () {
1504 var args = cloneArgs(arguments);
1505 setOptsEnv(args);
1506 modifyLong(args, 0);
1507 return ancestor.execSync.apply(childProcess, args);
1508 };
1509}());
1510
1511// /////////////////////////////////////////////////////////////////
1512// PROMISIFY ///////////////////////////////////////////////////////
1513// /////////////////////////////////////////////////////////////////
1514
1515(function () {
1516 var util = require('util');
1517 var promisify = util.promisify;
1518 if (promisify) {
1519 var custom = promisify.custom;
1520 var customPromisifyArgs = require('internal/util').customPromisifyArgs;
1521
1522 // /////////////////////////////////////////////////////////////
1523 // FS //////////////////////////////////////////////////////////
1524 // /////////////////////////////////////////////////////////////
1525
1526 Object.defineProperty(require('fs').exists, custom, {
1527 value: function (path) {
1528 return new Promise(function (resolve) {
1529 require('fs').exists(path, function (exists) {
1530 resolve(exists);
1531 });
1532 });
1533 }
1534 });
1535
1536 Object.defineProperty(require('fs').read, customPromisifyArgs, {
1537 value: [ 'bytesRead', 'buffer' ]
1538 });
1539
1540 Object.defineProperty(require('fs').write, customPromisifyArgs, {
1541 value: [ 'bytesWritten', 'buffer' ]
1542 });
1543
1544 // /////////////////////////////////////////////////////////////
1545 // CHILD_PROCESS ///////////////////////////////////////////////
1546 // /////////////////////////////////////////////////////////////
1547
1548 var customPromiseExecFunction = function (o) {
1549 return function () {
1550 var args = Array.from(arguments);
1551 return new Promise(function (resolve, reject) {
1552 o.apply(undefined, args.concat(function (error, stdout, stderr) {
1553 if (error !== null) {
1554 error.stdout = stdout;
1555 error.stderr = stderr;
1556 reject(error);
1557 } else {
1558 resolve({ stdout: stdout, stderr: stderr });
1559 }
1560 }));
1561 });
1562 };
1563 };
1564
1565 Object.defineProperty(require('child_process').exec, custom, {
1566 value: customPromiseExecFunction(require('child_process').exec)
1567 });
1568
1569 Object.defineProperty(require('child_process').execFile, custom, {
1570 value: customPromiseExecFunction(require('child_process').execFile)
1571 });
1572 }
1573}());
1574
1575// /////////////////////////////////////////////////////////////////
1576// PATCH PROCESS ///////////////////////////////////////////////////
1577// /////////////////////////////////////////////////////////////////
1578
1579(function() {
1580 const fs = require('fs');
1581 var ancestor = {};
1582 ancestor.dlopen = process.dlopen;
1583
1584 process.dlopen = function () {
1585 const args = cloneArgs(arguments);
1586 const modulePath = args[1];
1587 const moduleDirname = require('path').dirname(modulePath);
1588 if (insideSnapshot(modulePath)) {
1589 // Node addon files and .so cannot be read with fs directly, they are loaded with process.dlopen which needs a filesystem path
1590 // we need to write the file somewhere on disk first and then load it
1591 const moduleContent = fs.readFileSync(modulePath);
1592 const moduleBaseName = require('path').basename(modulePath);
1593 const hash = require('crypto').createHash('sha256').update(moduleContent).digest('hex');
1594 const tmpModulePath = `${require('os').tmpdir()}/${hash}_${moduleBaseName}`;
1595 try {
1596 fs.statSync(tmpModulePath);
1597 } catch (e) {
1598 // Most likely this means the module is not on disk yet
1599 fs.writeFileSync(tmpModulePath, moduleContent, { mode: 0o444 });
1600 }
1601 args[1] = tmpModulePath;
1602 }
1603
1604 const unknownModuleErrorRegex = /([^:]+): cannot open shared object file: No such file or directory/;
1605 const tryImporting = function (previousErrorMessage) {
1606 try {
1607 const res = ancestor.dlopen.apply(process, args);
1608 return res;
1609 } catch (e) {
1610 if (e.message === previousErrorMessage) {
1611 // we already tried to fix this and it didn't work, give up
1612 throw e;
1613 }
1614 if (e.message.match(unknownModuleErrorRegex)) {
1615 // some modules are packaged with dynamic linking and needs to open other files that should be in
1616 // the same directory, in this case, we write this file in the same /tmp directory and try to
1617 // import the module again
1618 const moduleName = e.message.match(unknownModuleErrorRegex)[1];
1619 const modulePath = `${moduleDirname}/${moduleName}`;
1620 const moduleContent = fs.readFileSync(modulePath);
1621 const moduleBaseName = require('path').basename(modulePath);
1622 const tmpModulePath = `${require('os').tmpdir()}/${moduleBaseName}`;
1623 try {
1624 fs.statSync(tmpModulePath);
1625 } catch (e) {
1626 fs.writeFileSync(tmpModulePath, moduleContent, { mode: 0o444 });
1627 }
1628 return tryImporting(e.message);
1629 }
1630 throw e;
1631 }
1632 }
1633 tryImporting();
1634 }
1635}());
1636

Built with git-ssb-web