@@ -45,18 +45,38 @@ const util = require("util");
4545// using require here on purpose so we can override methods with any
4646// also even though imports are mutable in typescript the cognitive dissonance is too high because
4747// es modules
48- const _fs = require ( 'node:fs' ) ;
48+ const fs = require ( 'node:fs' ) ;
4949const url = require ( 'node:url' ) ;
5050const HOP_NON_LINK = Symbol . for ( 'HOP NON LINK' ) ;
5151const HOP_NOT_FOUND = Symbol . for ( 'HOP NOT FOUND' ) ;
52- function patcher ( fs = _fs , roots ) {
53- fs = fs || _fs ;
52+ const PATCHED_FS_METHODS = [
53+ 'lstat' ,
54+ 'lstatSync' ,
55+ 'realpath' ,
56+ 'realpathSync' ,
57+ 'readlink' ,
58+ 'readlinkSync' ,
59+ 'readdir' ,
60+ 'readdirSync' ,
61+ 'opendir' ,
62+ ] ;
63+ /**
64+ * Function that patches the `fs` module to not escape the given roots.
65+ * @returns a function to undo the patches.
66+ */
67+ function patcher ( roots ) {
68+ if ( fs . _unpatched ) {
69+ throw new Error ( 'FS is already patched.' ) ;
70+ }
5471 // Make the original version of the library available for when access to the
5572 // unguarded file system is necessary, such as the esbuild plugin that
5673 // protects against sandbox escaping that occurs through module resolution
5774 // in the Go binary. See
5875 // https://github.com/aspect-build/rules_esbuild/issues/58.
59- fs . _unpatched = Object . assign ( { } , fs ) ;
76+ fs . _unpatched = PATCHED_FS_METHODS . reduce ( ( obj , method ) => {
77+ obj [ method ] = fs [ method ] ;
78+ return obj ;
79+ } , { } ) ;
6080 roots = roots || [ ] ;
6181 roots = roots . filter ( ( root ) => fs . existsSync ( root ) ) ;
6282 if ( ! roots . length ) {
@@ -245,15 +265,8 @@ function patcher(fs = _fs, roots) {
245265 ! isEscape ( resolved , next , [ escapedRoot ] ) ) {
246266 return cb ( null , next ) ;
247267 }
248- // The escape from the root is not mappable back into the root; we must make
249- // this look like a real file so we call readlink on the realpath which we
250- // expect to return an error
251- return origRealpath ( resolved , readlinkRealpathCb ) ;
252- function readlinkRealpathCb ( err , str ) {
253- if ( err )
254- return cb ( err ) ;
255- return origReadlink ( str , cb ) ;
256- }
268+ // The escape from the root is not mappable back into the root; throw EINVAL
269+ return cb ( einval ( 'readlink' , args [ 0 ] ) ) ;
257270 }
258271 }
259272 else {
@@ -366,6 +379,7 @@ function patcher(fs = _fs, roots) {
366379 * this api is available as experimental without a flag so users can access it at any time.
367380 */
368381 const promisePropertyDescriptor = Object . getOwnPropertyDescriptor ( fs , 'promises' ) ;
382+ let unpatchPromises ;
369383 if ( promisePropertyDescriptor ) {
370384 const promises = { } ;
371385 promises . lstat = util . promisify ( fs . lstat ) ;
@@ -380,16 +394,28 @@ function patcher(fs = _fs, roots) {
380394 if ( promisePropertyDescriptor . get ) {
381395 const oldGetter = promisePropertyDescriptor . get . bind ( fs ) ;
382396 const cachedPromises = { } ;
383- promisePropertyDescriptor . get = ( ) => {
397+ function promisePropertyGetter ( ) {
384398 const _promises = oldGetter ( ) ;
385399 Object . assign ( cachedPromises , _promises , promises ) ;
386400 return cachedPromises ;
401+ }
402+ Object . defineProperty ( fs , 'promises' , Object . assign ( {
403+ get : promisePropertyGetter ,
404+ } , Object . create ( promisePropertyDescriptor ) ) ) ;
405+ unpatchPromises = function unpatchFsPromises ( ) {
406+ Object . defineProperty ( fs , 'promises' , promisePropertyDescriptor ) ;
387407 } ;
388- Object . defineProperty ( fs , 'promises' , promisePropertyDescriptor ) ;
389408 }
390409 else {
410+ const unpatched_promises = Object . keys ( promises ) . reduce ( ( obj , method ) => {
411+ obj [ method ] = fs . promises [ method ] ;
412+ return obj ;
413+ } , Object . create ( fs . promises ) ) ;
391414 // api can be patched directly
392415 Object . assign ( fs . promises , promises ) ;
416+ unpatchPromises = function unpatchFsPromises ( ) {
417+ Object . assign ( fs . promises , unpatched_promises ) ;
418+ } ;
393419 }
394420 }
395421 // =========================================================================
@@ -721,6 +747,13 @@ function patcher(fs = _fs, roots) {
721747 }
722748 }
723749 }
750+ return function revertPatch ( ) {
751+ Object . assign ( fs , fs . _unpatched ) ;
752+ delete fs . _unpatched ;
753+ if ( unpatchPromises ) {
754+ unpatchPromises ( ) ;
755+ }
756+ } ;
724757}
725758// =========================================================================
726759// generic helper functions
0 commit comments