@@ -28,7 +28,10 @@ const {
2828 gunzipSync,
2929 brotliDecompressSync,
3030 brotliDecompress,
31+ createBrotliDecompress,
32+ createGunzip,
3133} = require ( 'zlib' ) ;
34+ const { createHash } = require ( 'crypto' ) ;
3235
3336const common = { } ;
3437REQUIRE_COMMON ( common ) ;
@@ -510,6 +513,7 @@ function payloadFileSync(pointer) {
510513 ancestor . access = fs . access ;
511514 ancestor . mkdirSync = fs . mkdirSync ;
512515 ancestor . mkdir = fs . mkdir ;
516+ ancestor . createReadStream = fs . createReadStream ;
513517
514518 const windows = process . platform === 'win32' ;
515519
@@ -567,10 +571,53 @@ function payloadFileSync(pointer) {
567571 // open //////////////////////////////////////////////////////////
568572 // ///////////////////////////////////////////////////////////////
569573
574+ function removeTemporaryFolderAndContent ( folder ) {
575+ if ( NODE_VERSION_MAJOR <= 14 ) {
576+ if ( NODE_VERSION_MAJOR <= 10 ) {
577+ // folder must be empty
578+ for ( const f of fs . readdirSync ( folder ) ) {
579+ fs . unlinkSync ( path . join ( folder , f ) ) ;
580+ }
581+ fs . rmdirSync ( folder ) ;
582+ } else {
583+ fs . rmdirSync ( folder , { recursive : true } ) ;
584+ }
585+ } else {
586+ fs . rmSync ( folder , { recursive : true } ) ;
587+ }
588+ }
589+ const temporaryFiles = { } ;
590+ const os = require ( 'os' ) ;
591+ const tmpFolder = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , 'pkg-' ) ) ;
592+ process . on ( 'beforeExit' , ( ) => {
593+ removeTemporaryFolderAndContent ( tmpFolder ) ;
594+ } ) ;
595+ function deflateSync ( snapshotFilename ) {
596+ const content = fs . readFileSync ( snapshotFilename , { encoding : 'binary' } ) ;
597+ // content is already unziped !
598+ const hash = createHash ( 'sha256' ) . update ( content ) . digest ( 'hex' ) ;
599+ const fName = path . join ( tmpFolder , hash ) ;
600+ fs . writeFileSync ( fName , content ) ;
601+ return fName ;
602+ }
603+ function uncompressExternally ( snapshotFilename ) {
604+ let t = temporaryFiles [ snapshotFilename ] ;
605+ if ( ! t ) {
606+ const tmpFile = deflateSync ( snapshotFilename ) ;
607+ t = { tmpFile } ;
608+ temporaryFiles [ snapshotFilename ] = t ;
609+ }
610+ return t . tmpFile ;
611+ }
612+ function uncompressExternallyAndOpen ( snapshotFilename ) {
613+ const externalFile = uncompressExternally ( snapshotFilename ) ;
614+ const fd = fs . openSync ( externalFile , 'r' ) ;
615+ return fd ;
616+ }
617+
570618 function openFromSnapshot ( f , cb ) {
571619 const cb2 = cb || rethrow ;
572620 const entity = findVirtualFileSystemEntry ( f ) ;
573-
574621 if ( ! entity ) return cb2 ( error_ENOENT ( 'File or directory' , f ) ) ;
575622 const dock = { path : f , entity, position : 0 } ;
576623 const nullDevice = windows ? '\\\\.\\NUL' : '/dev/null' ;
@@ -587,13 +634,37 @@ function payloadFileSync(pointer) {
587634 }
588635 }
589636
637+ let bypassCompressCheckWhenCallbyCreateReadStream = false ;
638+
639+ fs . createReadStream = function createReadStream ( f ) {
640+ if ( ! insideSnapshot ( f ) ) {
641+ return ancestor . createReadStream . apply ( fs , arguments ) ;
642+ }
643+ if ( insideMountpoint ( f ) ) {
644+ return ancestor . createReadStream . apply ( fs , translateNth ( arguments , 0 , f ) ) ;
645+ }
646+ bypassCompressCheckWhenCallbyCreateReadStream = true ;
647+ const stream = ancestor . createReadStream . apply ( fs , arguments ) ;
648+ bypassCompressCheckWhenCallbyCreateReadStream = false ;
649+
650+ if ( DOCOMPRESS === GZIP ) {
651+ return stream . pipe ( createGunzip ( ) ) ;
652+ }
653+ if ( DOCOMPRESS === BROTLI ) {
654+ return stream . pipe ( createBrotliDecompress ( ) ) ;
655+ }
656+ return stream ;
657+ } ;
590658 fs . openSync = function openSync ( f ) {
591659 if ( ! insideSnapshot ( f ) ) {
592660 return ancestor . openSync . apply ( fs , arguments ) ;
593661 }
594662 if ( insideMountpoint ( f ) ) {
595663 return ancestor . openSync . apply ( fs , translateNth ( arguments , 0 , f ) ) ;
596664 }
665+ if ( DOCOMPRESS && ! bypassCompressCheckWhenCallbyCreateReadStream ) {
666+ return uncompressExternallyAndOpen ( f ) ;
667+ }
597668 return openFromSnapshot ( f ) ;
598669 } ;
599670
@@ -604,8 +675,11 @@ function payloadFileSync(pointer) {
604675 if ( insideMountpoint ( f ) ) {
605676 return ancestor . open . apply ( fs , translateNth ( arguments , 0 , f ) ) ;
606677 }
607-
608678 const callback = dezalgo ( maybeCallback ( arguments ) ) ;
679+ if ( DOCOMPRESS && ! bypassCompressCheckWhenCallbyCreateReadStream ) {
680+ const fd = uncompressExternallyAndOpen ( f ) ;
681+ return callback ( null , fd ) ;
682+ }
609683 openFromSnapshot ( f , callback ) ;
610684 } ;
611685
@@ -1344,18 +1418,70 @@ function payloadFileSync(pointer) {
13441418 // promises ////////////////////////////////////////////////////////
13451419 // ///////////////////////////////////////////////////////////////
13461420
1421+ const ancestor_promises = { } ;
13471422 if ( fs . promises !== undefined ) {
13481423 var util = require ( 'util' ) ;
1349- fs . promises . open = util . promisify ( fs . open ) ;
1350- fs . promises . read = util . promisify ( fs . read ) ;
1351- fs . promises . write = util . promisify ( fs . write ) ;
1352- fs . promises . readFile = util . promisify ( fs . readFile ) ;
1424+ ancestor_promises . open = fs . promises . open ;
1425+ ancestor_promises . read = fs . promises . read ;
1426+ ancestor_promises . write = fs . promises . write ;
1427+ ancestor_promises . readFile = fs . promises . readFile ;
1428+ ancestor_promises . readdir = fs . promises . readdir ;
1429+ ancestor_promises . realpath = fs . promises . realpath ;
1430+ ancestor_promises . stat = fs . promises . stat ;
1431+ ancestor_promises . lstat = fs . promises . lstat ;
1432+ ancestor_promises . fstat = fs . promises . fstat ;
1433+ ancestor_promises . access = fs . promises . access ;
1434+
1435+ fs . promises . open = async function open ( f ) {
1436+ if ( ! insideSnapshot ( f ) ) {
1437+ return ancestor_promises . open . apply ( this , arguments ) ;
1438+ }
1439+ if ( insideMountpoint ( f ) ) {
1440+ return ancestor_promises . open . apply (
1441+ this ,
1442+ translateNth ( arguments , 0 , f )
1443+ ) ;
1444+ }
1445+ const externalFile = uncompressExternally ( f ) ;
1446+ arguments [ 0 ] = externalFile ;
1447+ const fd = await ancestor_promises . open . apply ( this , arguments ) ;
1448+ if ( typeof fd === 'object' ) {
1449+ fd . _pkg = { externalFile, file : f } ;
1450+ }
1451+ return fd ;
1452+ } ;
1453+ fs . promises . readFile = async function readFile ( f ) {
1454+ if ( ! insideSnapshot ( f ) ) {
1455+ return ancestor_promises . readFile . apply ( this , arguments ) ;
1456+ }
1457+ if ( insideMountpoint ( f ) ) {
1458+ return ancestor_promises . readFile . apply (
1459+ this ,
1460+ translateNth ( arguments , 0 , f )
1461+ ) ;
1462+ }
1463+ const externalFile = uncompressExternally ( f ) ;
1464+ arguments [ 0 ] = externalFile ;
1465+ return ancestor_promises . readFile . apply ( this , arguments ) ;
1466+ } ;
1467+ fs . promises . write = async function write ( fd ) {
1468+ if ( fd . _pkg ) {
1469+ throw new Error (
1470+ `[PKG] Cannot write into Snapshot file : ${ fd . _pkg . file } `
1471+ ) ;
1472+ }
1473+ return ancestor_promises . write . apply ( this , arguments ) ;
1474+ } ;
13531475 fs . promises . readdir = util . promisify ( fs . readdir ) ;
1476+
1477+ /*
1478+ fs.promises.read = util.promisify(fs.read);
13541479 fs.promises.realpath = util.promisify(fs.realpath);
13551480 fs.promises.stat = util.promisify(fs.stat);
13561481 fs.promises.lstat = util.promisify(fs.lstat);
13571482 fs.promises.fstat = util.promisify(fs.fstat);
13581483 fs.promises.access = util.promisify(fs.access);
1484+ */
13591485 }
13601486
13611487 // ///////////////////////////////////////////////////////////////
@@ -1897,10 +2023,7 @@ function payloadFileSync(pointer) {
18972023
18982024 // Node addon files and .so cannot be read with fs directly, they are loaded with process.dlopen which needs a filesystem path
18992025 // we need to write the file somewhere on disk first and then load it
1900- const hash = require ( 'crypto' )
1901- . createHash ( 'sha256' )
1902- . update ( moduleContent )
1903- . digest ( 'hex' ) ;
2026+ const hash = createHash ( 'sha256' ) . update ( moduleContent ) . digest ( 'hex' ) ;
19042027
19052028 const tmpFolder = path . join ( require ( 'os' ) . tmpdir ( ) , hash ) ;
19062029 if ( ! fs . existsSync ( tmpFolder ) ) {
0 commit comments