@@ -146,6 +146,7 @@ FS.staticInit();
146146 this . name = name ;
147147 this . mode = mode ;
148148 this . rdev = rdev ;
149+ this . atime = this . mtime = this . ctime = Date . now ( ) ;
149150 }
150151 get read ( ) {
151152 return ( this . mode & this . readMode ) === this . readMode ;
@@ -174,60 +175,46 @@ FS.staticInit();
174175 path = PATH_FS . resolve ( path ) ;
175176
176177 if ( ! path ) return { path : '' , node : null } ;
178+ opts . follow_mount ??= true
177179
178- var defaults = {
179- follow_mount : true ,
180- recurse_count : 0
181- } ;
182- opts = Object . assign ( defaults , opts )
183-
184- if ( opts . recurse_count > 8 ) { // max recursive lookup of 8
185- throw new FS . ErrnoError ( { { { cDefs. ELOOP } } } ) ;
186- }
187-
188- // split the absolute path
189- var parts = path . split ( '/' ) . filter ( ( p ) => ! ! p ) ;
180+ // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
181+ linkloop : for ( var nlinks = 0 ; nlinks < 40 ; nlinks ++ ) {
182+ // split the absolute path
183+ var parts = path . split ( '/' ) . filter ( ( p ) => ! ! p ) ;
190184
191- // start at the root
192- var current = FS . root ;
193- var current_path = '/' ;
185+ // start at the root
186+ var current = FS . root ;
187+ var current_path = '/' ;
194188
195- for ( var i = 0 ; i < parts . length ; i ++ ) {
196- var islast = ( i === parts . length - 1 ) ;
197- if ( islast && opts . parent ) {
198- // stop resolving
199- break;
200- }
189+ for ( var i = 0 ; i < parts . length ; i ++ ) {
190+ var islast = ( i === parts . length - 1 ) ;
191+ if ( islast && opts . parent ) {
192+ // stop resolving
193+ break;
194+ }
201195
202- current = FS . lookupNode ( current , parts [ i ] ) ;
203- current_path = PATH . join2 ( current_path , parts [ i ] ) ;
196+ current = FS . lookupNode ( current , parts [ i ] ) ;
197+ current_path = PATH . join2 ( current_path , parts [ i ] ) ;
204198
205- // jump to the mount's root node if this is a mountpoint
206- if ( FS . isMountpoint ( current ) ) {
207- if ( ! islast || ( islast && opts . follow_mount ) ) {
199+ // jump to the mount's root node if this is a mountpoint
200+ if ( FS . isMountpoint ( current ) && ( ! islast || opts . follow_mount ) ) {
208201 current = current . mounted . root ;
209202 }
210- }
211-
212- // by default, lookupPath will not follow a symlink if it is the final path component.
213- // setting opts.follow = true will override this behavior.
214- if ( ! islast || opts . follow ) {
215- var count = 0 ;
216- while ( FS . isLink ( current . mode ) ) {
217- var link = FS . readlink ( current_path ) ;
218- current_path = PATH_FS . resolve ( PATH . dirname ( current_path ) , link ) ;
219203
220- var lookup = FS . lookupPath ( current_path , { recurse_count : opts . recurse_count + 1 } ) ;
221- current = lookup . node ;
222-
223- if ( count ++ > 40 ) { // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
224- throw new FS . ErrnoError ( { { { cDefs. ELOOP } } } ) ;
204+ // by default, lookupPath will not follow a symlink if it is the final path component.
205+ // setting opts.follow = true will override this behavior.
206+ if ( FS . isLink ( current . mode ) && ( ! islast || opts . follow ) ) {
207+ if ( ! current . node_ops . readlink ) {
208+ throw new FS . ErrnoError ( { { { cDefs . ENOSYS } } } ) ;
225209 }
210+ var link = current . node_ops . readlink ( current ) ;
211+ path = PATH_FS . resolve ( PATH . dirname ( current_path ) , link , ...parts . slice ( i + 1 ) ) ;
212+ continue linkloop ;
226213 }
227214 }
215+ return { path : current_path , node : current } ;
228216 }
229-
230- return { path : current_path , node : current } ;
217+ throw new FS . ErrnoError ( { { { cDefs. ELOOP } } } ) ;
231218 } ,
232219 getPath ( node ) {
233220 var path ;
@@ -372,6 +359,9 @@ FS.staticInit();
372359 return 0 ;
373360 } ,
374361 mayCreate ( dir , name ) {
362+ if ( ! FS . isDir ( dir . mode ) ) {
363+ return { { { cDefs . ENOTDIR } } } ;
364+ }
375365 try {
376366 var node = FS . lookupNode ( dir , name ) ;
377367 return { { { cDefs . EEXIST } } } ;
@@ -964,7 +954,7 @@ FS.staticInit();
964954 }
965955 node . node_ops . setattr ( node , {
966956 mode : ( mode & { { { cDefs . S_IALLUGO } } } ) | ( node . mode & ~ { { { cDefs . S_IALLUGO } } } ) ,
967- timestamp : Date . now ( )
957+ ctime : Date . now ( )
968958 } ) ;
969959 } ,
970960 lchmod ( path , mode ) {
@@ -1068,7 +1058,8 @@ FS.staticInit();
10681058 var lookup = FS . lookupPath ( path , { follow : true } ) ;
10691059 var node = lookup . node ;
10701060 node . node_ops . setattr ( node , {
1071- timestamp : Math . max ( atime , mtime )
1061+ atime : atime ,
1062+ mtime : mtime
10721063 } ) ;
10731064 } ,
10741065 open ( path , flags , mode = 0o666 ) {
@@ -1443,6 +1434,9 @@ FS.staticInit();
14431434 FS . mount ( {
14441435 mount ( ) {
14451436 var node = FS . createNode ( proc_self , 'fd' , { { { cDefs . S_IFDIR | 0o777 } } } , { { { cDefs . S_IXUGO } } } ) ;
1437+ node . stream_ops = {
1438+ llseek : MEMFS . stream_ops . llseek ,
1439+ } ;
14461440 node . node_ops = {
14471441 lookup ( parent , name ) {
14481442 var fd = + name ;
@@ -1451,9 +1445,15 @@ FS.staticInit();
14511445 parent : null ,
14521446 mount : { mountpoint : 'fake' } ,
14531447 node_ops : { readlink : ( ) => stream . path } ,
1448+ id : fd + 1 ,
14541449 } ;
14551450 ret . parent = ret ; // make it look like a simple root node
14561451 return ret ;
1452+ } ,
1453+ readdir ( ) {
1454+ return Array . from ( FS . streams . entries ( ) )
1455+ . filter ( ( [ k , v ] ) => v )
1456+ . map ( ( [ k , v ] ) => k . toString ( ) ) ;
14571457 }
14581458 } ;
14591459 return node ;
@@ -1670,7 +1670,7 @@ FS.staticInit();
16701670 buffer [ offset + i ] = result ;
16711671 }
16721672 if ( bytesRead ) {
1673- stream . node . timestamp = Date . now ( ) ;
1673+ stream . node . atime = Date . now ( ) ;
16741674 }
16751675 return bytesRead ;
16761676 } ,
@@ -1683,7 +1683,7 @@ FS.staticInit();
16831683 }
16841684 }
16851685 if ( length ) {
1686- stream . node . timestamp = Date . now ( ) ;
1686+ stream . node . mtime = stream . node . ctime = Date . now ( ) ;
16871687 }
16881688 return i ;
16891689 }
0 commit comments