@@ -332,35 +332,20 @@ namespace vfs {
332
332
}
333
333
}
334
334
335
- private _depth : string [ ] = [ ] ;
336
-
337
335
/**
338
336
* Make a directory and all of its parent paths (if they don't exist).
339
337
*/
340
338
public mkdirpSync ( path : string ) {
341
- try {
342
- this . _depth . push ( path ) ;
343
- path = this . _resolve ( path ) ;
344
- this . mkdirSync ( path ) ;
345
- }
346
- catch ( e ) {
347
- if ( e . code === "ENOENT" ) {
348
- if ( this . _depth . length > 10 ) {
349
- console . log ( `path: ${ path } ` ) ;
350
- console . log ( `dirname: ${ vpath . dirname ( path ) } ` ) ;
351
- console . log ( this . _depth ) ;
352
- throw e ;
353
- }
354
- this . mkdirpSync ( vpath . dirname ( path ) ) ;
355
- this . mkdirSync ( path ) ;
356
- }
357
- else if ( e . code !== "EEXIST" ) {
358
- throw e ;
339
+ path = this . _resolve ( path ) ;
340
+ const result = this . _walk ( path , /*noFollow*/ true , ( error , result ) => {
341
+ if ( error . code === "ENOENT" ) {
342
+ this . _mkdir ( result ) ;
343
+ return "retry" ;
359
344
}
360
- }
361
- finally {
362
- this . _depth . pop ( ) ;
363
- }
345
+ return "throw" ;
346
+ } ) ;
347
+
348
+ if ( ! result . node ) this . _mkdir ( result ) ;
364
349
}
365
350
366
351
/**
@@ -464,9 +449,11 @@ namespace vfs {
464
449
public mkdirSync ( path : string ) {
465
450
if ( this . isReadonly ) throw createIOError ( "EROFS" ) ;
466
451
467
- const { parent , links , node : existingNode , basename } = this . _walk ( this . _resolve ( path ) , /*noFollow*/ true ) ;
468
- if ( existingNode ) throw createIOError ( "EEXIST" ) ;
452
+ this . _mkdir ( this . _walk ( this . _resolve ( path ) , /*noFollow*/ true ) ) ;
453
+ }
469
454
455
+ private _mkdir ( { parent, links, node : existingNode , basename } : WalkResult ) {
456
+ if ( existingNode ) throw createIOError ( "EEXIST" ) ;
470
457
const time = this . time ( ) ;
471
458
const node = this . _mknod ( parent ? parent . dev : ++ devCount , S_IFDIR , /*mode*/ 0o777 , time ) ;
472
459
this . _addLink ( parent , links , basename , node , time ) ;
@@ -810,17 +797,18 @@ namespace vfs {
810
797
* @param path The path to follow.
811
798
* @param noFollow A value indicating whether to *not* dereference a symbolic link at the
812
799
* end of a path.
813
- * @param allowPartial A value indicating whether to return a partial result if the node
814
- * at the end of the path cannot be found.
815
800
*
816
801
* @link http://man7.org/linux/man-pages/man7/path_resolution.7.html
817
802
*/
818
- private _walk ( path : string , noFollow ?: boolean ) : WalkResult {
803
+ private _walk ( path : string , noFollow ?: boolean , onError ?: ( error : NodeJS . ErrnoException , fragment : WalkResult ) => "retry" | "throw" ) : WalkResult ;
804
+ private _walk ( path : string , noFollow ?: boolean , onError ?: ( error : NodeJS . ErrnoException , fragment : WalkResult ) => "stop" | "retry" | "throw" ) : WalkResult | undefined ;
805
+ private _walk ( path : string , noFollow ?: boolean , onError ?: ( error : NodeJS . ErrnoException , fragment : WalkResult ) => "stop" | "retry" | "throw" ) : WalkResult | undefined {
819
806
let links = this . _getRootLinks ( ) ;
820
807
let parent : DirectoryInode | undefined ;
821
808
let components = vpath . parse ( path ) ;
822
809
let step = 0 ;
823
810
let depth = 0 ;
811
+ let retry = false ;
824
812
while ( true ) {
825
813
if ( depth >= 40 ) throw createIOError ( "ELOOP" ) ;
826
814
const lastStep = step === components . length - 1 ;
@@ -830,7 +818,8 @@ namespace vfs {
830
818
return { realpath : vpath . format ( components ) , basename, parent, links, node } ;
831
819
}
832
820
if ( node === undefined ) {
833
- throw createIOError ( "ENOENT" ) ;
821
+ if ( trapError ( createIOError ( "ENOENT" ) , node ) ) continue ;
822
+ return undefined ;
834
823
}
835
824
if ( isSymlink ( node ) ) {
836
825
const dirname = vpath . format ( components . slice ( 0 , step ) ) ;
@@ -840,15 +829,30 @@ namespace vfs {
840
829
components = vpath . parse ( symlink ) . concat ( components . slice ( step + 1 ) ) ;
841
830
step = 0 ;
842
831
depth ++ ;
832
+ retry = false ;
843
833
continue ;
844
834
}
845
835
if ( isDirectory ( node ) ) {
846
836
links = this . _getLinks ( node ) ;
847
837
parent = node ;
848
838
step ++ ;
839
+ retry = false ;
849
840
continue ;
850
841
}
851
- throw createIOError ( "ENOTDIR" ) ;
842
+ if ( trapError ( createIOError ( "ENOTDIR" ) , node ) ) continue ;
843
+ return undefined ;
844
+ }
845
+
846
+ function trapError ( error : NodeJS . ErrnoException , node ?: Inode ) {
847
+ const realpath = vpath . format ( components . slice ( 0 , step + 1 ) ) ;
848
+ const basename = components [ step ] ;
849
+ const result = ! retry && onError ? onError ( error , { realpath, basename, parent, links, node } ) : "throw" ;
850
+ if ( result === "stop" ) return false ;
851
+ if ( result === "retry" ) {
852
+ retry = true ;
853
+ return true ;
854
+ }
855
+ throw error ;
852
856
}
853
857
}
854
858
@@ -1118,6 +1122,7 @@ namespace vfs {
1118
1122
export function createIOError ( code : keyof typeof IOErrorMessages ) {
1119
1123
const err : NodeJS . ErrnoException = new Error ( `${ code } : ${ IOErrorMessages [ code ] } ` ) ;
1120
1124
err . code = code ;
1125
+ if ( Error . captureStackTrace ) Error . captureStackTrace ( err , createIOError ) ;
1121
1126
return err ;
1122
1127
}
1123
1128
0 commit comments