@@ -309,7 +309,7 @@ export class Volume implements FsCallbackApi, FsSynchronousApi {
309309 this . props = Object . assign ( { Node, Link, File } , props ) ;
310310
311311 const root = this . createLink ( ) ;
312- root . setNode ( this . createNode ( true ) ) ;
312+ root . setNode ( this . createNode ( constants . S_IFDIR | 0o777 ) ) ;
313313
314314 const self = this ; // tslint:disable-line no-this-assignment
315315
@@ -349,8 +349,8 @@ export class Volume implements FsCallbackApi, FsSynchronousApi {
349349 }
350350
351351 createLink ( ) : Link ;
352- createLink ( parent : Link , name : string , isDirectory ?: boolean , perm ?: number ) : Link ;
353- createLink ( parent ?: Link , name ?: string , isDirectory : boolean = false , perm ?: number ) : Link {
352+ createLink ( parent : Link , name : string , isDirectory ?: boolean , mode ?: number ) : Link ;
353+ createLink ( parent ?: Link , name ?: string , isDirectory : boolean = false , mode ?: number ) : Link {
354354 if ( ! parent ) {
355355 return new this . props . Link ( this , null , '' ) ;
356356 }
@@ -359,7 +359,14 @@ export class Volume implements FsCallbackApi, FsSynchronousApi {
359359 throw new Error ( 'createLink: name cannot be empty' ) ;
360360 }
361361
362- return parent . createChild ( name , this . createNode ( isDirectory , perm ) ) ;
362+ // If no explicit permission is provided, use defaults based on type
363+ const finalPerm = mode ?? ( isDirectory ? 0o777 : 0o666 ) ;
364+ // To prevent making a breaking change, `mode` can also just be a permission number
365+ // and the file type is set based on `isDirectory`
366+ const hasFileType = mode && mode & constants . S_IFMT ;
367+ const modeType = hasFileType ? mode & constants . S_IFMT : isDirectory ? constants . S_IFDIR : constants . S_IFREG ;
368+ const finalMode = ( finalPerm & ~ constants . S_IFMT ) | modeType ;
369+ return parent . createChild ( name , this . createNode ( finalMode ) ) ;
363370 }
364371
365372 deleteLink ( link : Link ) : boolean {
@@ -387,10 +394,8 @@ export class Volume implements FsCallbackApi, FsSynchronousApi {
387394 return typeof releasedFd === 'number' ? releasedFd : Volume . fd -- ;
388395 }
389396
390- createNode ( isDirectory : boolean = false , perm ?: number ) : Node {
391- perm ??= isDirectory ? 0o777 : 0o666 ;
392- const node = new this . props . Node ( this . newInoNumber ( ) , perm ) ;
393- if ( isDirectory ) node . setIsDirectory ( ) ;
397+ createNode ( mode : number ) : Node {
398+ const node = new this . props . Node ( this . newInoNumber ( ) , mode ) ;
394399 this . inodes [ node . ino ] = node ;
395400 return node ;
396401 }
@@ -685,7 +690,7 @@ export class Volume implements FsCallbackApi, FsSynchronousApi {
685690 this . openFiles = 0 ;
686691
687692 this . root = this . createLink ( ) ;
688- this . root . setNode ( this . createNode ( true ) ) ;
693+ this . root . setNode ( this . createNode ( constants . S_IFDIR | 0o777 ) ) ;
689694 }
690695
691696 // Legacy interface
@@ -1798,7 +1803,7 @@ export class Volume implements FsCallbackApi, FsSynchronousApi {
17981803 const node = dir . getNode ( ) ;
17991804 if ( ! node . canWrite ( ) || ! node . canExecute ( ) ) throw createError ( EACCES , 'mkdir' , filename ) ;
18001805
1801- dir . createChild ( name , this . createNode ( true , modeNum ) ) ;
1806+ dir . createChild ( name , this . createNode ( constants . S_IFDIR | modeNum ) ) ;
18021807 }
18031808
18041809 /**
@@ -1836,7 +1841,7 @@ export class Volume implements FsCallbackApi, FsSynchronousApi {
18361841 }
18371842
18381843 created = true ;
1839- curr = curr . createChild ( steps [ i ] , this . createNode ( true , modeNum ) ) ;
1844+ curr = curr . createChild ( steps [ i ] , this . createNode ( constants . S_IFDIR | modeNum ) ) ;
18401845 }
18411846 return created ? filename : undefined ;
18421847 }
0 commit comments