@@ -487,6 +487,24 @@ FS.staticInit();
487487 stream . stream_ops ?. dup ?. ( stream ) ;
488488 return stream ;
489489 } ,
490+ streamGetAttr ( stream ) {
491+ var node = stream . node ;
492+ var res = stream . stream_ops ?. getattr ?. ( stream ) ?? node . node_ops ?. getattr ?. ( node ) ;
493+ if ( res ) {
494+ return res ;
495+ }
496+ throw new FS . ErrnoError ( { { { cDefs. EPERM } } } ) ;
497+ } ,
498+ streamSetAttr ( stream , attr ) {
499+ var node = stream . node ;
500+ var set ;
501+ if ( set = stream . stream_ops . setattr ) {
502+ return set ( stream , attr ) ;
503+ } else if ( set = node . node_ops . setattr ) {
504+ return set ( node , attr ) ;
505+ }
506+ throw new FS . ErrnoError ( { { { cDefs . EPERM } } } ) ;
507+ } ,
490508
491509 //
492510 // devices
@@ -966,7 +984,8 @@ FS.staticInit();
966984 return getattr ( node ) ;
967985 } ,
968986 fstat ( fd ) {
969- return FS . stat ( FS . getStreamChecked ( fd ) . path ) ;
987+ var stream = FS . getStreamChecked ( fd ) ;
988+ return FS . streamGetAttr ( stream ) ;
970989 } ,
971990 lstat ( path ) {
972991 return FS . stat ( path , true ) ;
@@ -991,7 +1010,10 @@ FS.staticInit();
9911010 } ,
9921011 fchmod ( fd , mode ) {
9931012 var stream = FS . getStreamChecked ( fd ) ;
994- FS . chmod ( stream . node , mode ) ;
1013+ FS . streamSetAttr ( stream , {
1014+ mode : ( mode & { { { cDefs . S_IALLUGO } } } ) | ( stream . node . mode & ~ { { { cDefs . S_IALLUGO } } } ) ,
1015+ ctime : Date . now ( )
1016+ } ) ;
9951017 } ,
9961018 chown ( path , uid , gid , dontFollow ) {
9971019 var node ;
@@ -1013,7 +1035,22 @@ FS.staticInit();
10131035 } ,
10141036 fchown( fd , uid, gid ) {
10151037 var stream = FS . getStreamChecked ( fd ) ;
1016- FS . chown ( stream . node , uid , gid ) ;
1038+ FS . streamSetAttr ( stream , {
1039+ timestamp : Date . now ( )
1040+ // we ignore the uid / gid for now
1041+ } ) ;
1042+ } ,
1043+ truncateChecks ( node ) {
1044+ if ( FS . isDir ( node . mode ) ) {
1045+ throw new FS . ErrnoError ( { { { cDefs . EISDIR } } } ) ;
1046+ }
1047+ if ( ! FS . isFile ( node . mode ) ) {
1048+ throw new FS . ErrnoError ( { { { cDefs . EINVAL } } } ) ;
1049+ }
1050+ var errCode = FS . nodePermissions ( node , 'w' ) ;
1051+ if ( errCode ) {
1052+ throw new FS . ErrnoError ( errCode ) ;
1053+ }
10171054 } ,
10181055 truncate( path , len ) {
10191056 if ( len < 0 ) {
@@ -1026,16 +1063,7 @@ FS.staticInit();
10261063 } else {
10271064 node = path ;
10281065 }
1029- if ( FS . isDir ( node . mode ) ) {
1030- throw new FS . ErrnoError ( { { { cDefs . EISDIR } } } ) ;
1031- }
1032- if ( ! FS . isFile ( node . mode ) ) {
1033- throw new FS . ErrnoError ( { { { cDefs . EINVAL } } } ) ;
1034- }
1035- var errCode = FS . nodePermissions ( node , 'w' ) ;
1036- if ( errCode ) {
1037- throw new FS . ErrnoError ( errCode ) ;
1038- }
1066+ FS . truncateChecks ( node ) ;
10391067 var setattr = FS . checkOpExists ( node . node_ops . setattr , { { { cDefs. EPERM } } } ) ;
10401068 setattr ( node , {
10411069 size : len ,
@@ -1044,10 +1072,14 @@ FS.staticInit();
10441072 } ,
10451073 ftruncate ( fd , len ) {
10461074 var stream = FS . getStreamChecked ( fd ) ;
1047- if ( ( stream . flags & { { { cDefs . O_ACCMODE } } } ) === { { { cDefs . O_RDONLY } } } ) {
1075+ if ( len < 0 || ( stream . flags & { { { cDefs . O_ACCMODE } } } ) === { { { cDefs . O_RDONLY } } } ) {
10481076 throw new FS . ErrnoError ( { { { cDefs . EINVAL } } } ) ;
10491077 }
1050- FS . truncate ( stream . node, len) ;
1078+ FS . truncateChecks ( stream . node ) ;
1079+ FS . streamSetAttr ( stream , {
1080+ size : len ,
1081+ timestamp : Date . now ( )
1082+ } ) ;
10511083 } ,
10521084 utime ( path , atime , mtime ) {
10531085 var lookup = FS . lookupPath ( path , { follow : true } ) ;
0 commit comments