@@ -158,6 +158,49 @@ function createMountpoint(interior, exterior) {
158158 mountpoints . push ( { interior, exterior } ) ;
159159}
160160
161+ function copyFileSync ( source , target ) {
162+ let targetFile = target ;
163+
164+ // If target is a directory, a new file with the same name will be created
165+ if ( fs . existsSync ( target ) ) {
166+ if ( fs . lstatSync ( target ) . isDirectory ( ) ) {
167+ targetFile = path . join ( target , path . basename ( source ) ) ;
168+ }
169+ }
170+
171+ fs . writeFileSync ( targetFile , fs . readFileSync ( source ) ) ;
172+ }
173+
174+ function copyFolderRecursiveSync ( source , target ) {
175+ let files = [ ] ;
176+
177+ // Check if folder needs to be created or integrated
178+ const targetFolder = path . join ( target , path . basename ( source ) ) ;
179+ if ( ! fs . existsSync ( targetFolder ) ) {
180+ fs . mkdirSync ( targetFolder ) ;
181+ }
182+
183+ // Copy
184+ if ( fs . lstatSync ( source ) . isDirectory ( ) ) {
185+ files = fs . readdirSync ( source ) ;
186+ files . forEach ( ( file ) => {
187+ const curSource = path . join ( source , file ) ;
188+ if ( fs . lstatSync ( curSource ) . isDirectory ( ) ) {
189+ copyFolderRecursiveSync ( curSource , targetFolder ) ;
190+ } else {
191+ copyFileSync ( curSource , targetFolder ) ;
192+ }
193+ } ) ;
194+ }
195+ }
196+
197+ function createDirRecursively ( dir ) {
198+ if ( ! fs . existsSync ( dir ) ) {
199+ createDirRecursively ( path . join ( dir , '..' ) ) ;
200+ fs . mkdirSync ( dir ) ;
201+ }
202+ }
203+
161204/*
162205
163206// TODO move to some test
@@ -2020,88 +2063,41 @@ function payloadFileSync(pointer) {
20202063 const modulePath = revertMakingLong ( args [ 1 ] ) ;
20212064 const moduleBaseName = path . basename ( modulePath ) ;
20222065 const moduleFolder = path . dirname ( modulePath ) ;
2023- const unknownModuleErrorRegex = / ( [ ^ : ] + ) : c a n n o t o p e n s h a r e d o b j e c t f i l e : N o s u c h f i l e o r d i r e c t o r y / ;
20242066
2025- function tryImporting ( _tmpFolder , previousErrorMessage ) {
2026- try {
2027- const res = ancestor . dlopen . apply ( process , args ) ;
2028- return res ;
2029- } catch ( e ) {
2030- if ( e . message === previousErrorMessage ) {
2031- // we already tried to fix this and it didn't work, give up
2032- throw e ;
2033- }
2034- if ( e . message . match ( unknownModuleErrorRegex ) ) {
2035- // this case triggers on linux, the error message give us a clue on what dynamic linking library
2036- // is missing.
2037- // some modules are packaged with dynamic linking and needs to open other files that should be in
2038- // the same directory, in this case, we write this file in the same /tmp directory and try to
2039- // import the module again
2040-
2041- const moduleName = e . message . match ( unknownModuleErrorRegex ) [ 1 ] ;
2042- const importModulePath = path . join ( moduleFolder , moduleName ) ;
2043-
2044- if ( ! fs . existsSync ( importModulePath ) ) {
2045- throw new Error (
2046- `INTERNAL ERROR this file doesn't exist in the virtual file system :${ importModulePath } `
2047- ) ;
2048- }
2049- const moduleContent1 = fs . readFileSync ( importModulePath ) ;
2050- const tmpModulePath1 = path . join ( _tmpFolder , moduleName ) ;
2051-
2052- try {
2053- fs . statSync ( tmpModulePath1 ) ;
2054- } catch ( err ) {
2055- fs . writeFileSync ( tmpModulePath1 , moduleContent1 , { mode : 0o555 } ) ;
2056- }
2057- return tryImporting ( _tmpFolder , e . message ) ;
2058- }
2067+ // Example: moduleFolder = /snapshot/appname/node_modules/sharp/build/Release
2068+ const modulePkgPathRegex = / .* ?n o d e _ m o d u l e s \/ ( ( .+ ?) \/ .* ) / ;
2069+ // Example: modulePackagePath = sharp/build/Release
2070+ const modulePackagePath = moduleFolder . match ( modulePkgPathRegex ) [ 1 ] ;
2071+ // Example: modulePackageName = sharp
2072+ const modulePackageName = moduleFolder . match ( modulePkgPathRegex ) [ 2 ] ;
2073+ // Example: modulePkgFolder = /snapshot/appname/node_modules/sharp
2074+ const modulePkgFolder = moduleFolder . replace (
2075+ modulePackagePath ,
2076+ modulePackageName
2077+ ) ;
20592078
2060- // this case triggers on windows mainly.
2061- // we copy all stuff that exists in the folder of the .node module
2062- // into the temporary folders...
2063- const files = fs . readdirSync ( moduleFolder ) ;
2064- for ( const file of files ) {
2065- if ( file === moduleBaseName ) {
2066- // ignore the current module
2067- continue ;
2068- }
2069- const filenameSrc = path . join ( moduleFolder , file ) ;
2070-
2071- if ( fs . statSync ( filenameSrc ) . isDirectory ( ) ) {
2072- continue ;
2073- }
2074- const filenameDst = path . join ( _tmpFolder , file ) ;
2075- const content = fs . readFileSync ( filenameSrc ) ;
2076-
2077- fs . writeFileSync ( filenameDst , content , { mode : 0o555 } ) ;
2078- }
2079- return tryImporting ( _tmpFolder , e . message ) ;
2080- }
2081- }
20822079 if ( insideSnapshot ( modulePath ) ) {
20832080 const moduleContent = fs . readFileSync ( modulePath ) ;
20842081
20852082 // Node addon files and .so cannot be read with fs directly, they are loaded with process.dlopen which needs a filesystem path
20862083 // we need to write the file somewhere on disk first and then load it
2084+ // the hash is needed to be sure we reload the module in case it changes
20872085 const hash = createHash ( 'sha256' ) . update ( moduleContent ) . digest ( 'hex' ) ;
20882086
2089- const tmpFolder = path . join ( tmpdir ( ) , hash ) ;
2087+ // Example: /tmp/pkg/<hash>
2088+ const tmpFolder = path . join ( tmpdir ( ) , 'pkg' , hash ) ;
20902089 if ( ! fs . existsSync ( tmpFolder ) ) {
2091- fs . mkdirSync ( tmpFolder ) ;
2090+ // here we copy all files from the snapshot module folder to temporary folder
2091+ // we keep the module folder structure to prevent issues with modules that are statically
2092+ // linked using relative paths (Fix #1075)
2093+ createDirRecursively ( tmpFolder ) ;
2094+ copyFolderRecursiveSync ( modulePkgFolder , tmpFolder ) ;
20922095 }
2093- const tmpModulePath = path . join ( tmpFolder , moduleBaseName ) ;
20942096
2095- try {
2096- fs . statSync ( tmpModulePath ) ;
2097- } catch ( e ) {
2098- // Most likely this means the module is not on disk yet
2099- fs . writeFileSync ( tmpModulePath , moduleContent , { mode : 0o755 } ) ;
2100- }
2101- args [ 1 ] = tmpModulePath ;
2102- tryImporting ( tmpFolder ) ;
2103- } else {
2104- return ancestor . dlopen . apply ( process , args ) ;
2097+ // replace the path with the new module path
2098+ args [ 1 ] = path . join ( tmpFolder , modulePackagePath , moduleBaseName ) ;
21052099 }
2100+
2101+ return ancestor . dlopen . apply ( process , args ) ;
21062102 } ;
21072103} ) ( ) ;
0 commit comments