@@ -7,7 +7,7 @@ const Directory = require('./directory.js');
77const SymbolicLink = require ( './symlink.js' ) ;
88const { FSError} = require ( './error.js' ) ;
99const constants = require ( 'constants' ) ;
10- const getPathParts = require ( './filesystem.js' ) . getPathParts ;
10+ const { getPathParts, getRealPath } = require ( './filesystem.js' ) ;
1111
1212const MODE_TO_KTYPE = {
1313 [ constants . S_IFREG ] : constants . UV_DIRENT_FILE ,
@@ -260,10 +260,8 @@ Binding.prototype.realpath = function (filepath, encoding, callback, ctx) {
260260 throw new FSError ( 'ENOENT' , filepath ) ;
261261 }
262262
263- if ( process . platform === 'win32' && realPath . startsWith ( '\\\\?\\' ) ) {
264- // Remove win32 file namespace prefix \\?\
265- realPath = realPath . slice ( 4 ) ;
266- }
263+ // Remove win32 file namespace prefix \\?\
264+ realPath = getRealPath ( realPath ) ;
267265
268266 if ( encoding === 'buffer' ) {
269267 realPath = Buffer . from ( realPath ) ;
@@ -1073,12 +1071,45 @@ Binding.prototype.unlink = function (pathname, callback, ctx) {
10731071Binding . prototype . utimes = function ( pathname , atime , mtime , callback , ctx ) {
10741072 markSyscall ( ctx , 'utimes' ) ;
10751073
1074+ return maybeCallback ( normalizeCallback ( callback ) , ctx , this , function ( ) {
1075+ let filepath = deBuffer ( pathname ) ;
1076+ let item = this . _system . getItem ( filepath ) ;
1077+ let links = 0 ;
1078+ while ( item instanceof SymbolicLink ) {
1079+ if ( links > MAX_LINKS ) {
1080+ throw new FSError ( 'ELOOP' , filepath ) ;
1081+ }
1082+ filepath = path . resolve ( path . dirname ( filepath ) , item . getPath ( ) ) ;
1083+ item = this . _system . getItem ( filepath ) ;
1084+ ++ links ;
1085+ }
1086+ if ( ! item ) {
1087+ throw new FSError ( 'ENOENT' , pathname ) ;
1088+ }
1089+ item . setATime ( new Date ( atime * 1000 ) ) ;
1090+ item . setMTime ( new Date ( mtime * 1000 ) ) ;
1091+ } ) ;
1092+ } ;
1093+
1094+ /**
1095+ * Update timestamps.
1096+ * @param {string } pathname Path to item.
1097+ * @param {number } atime Access time (in seconds).
1098+ * @param {number } mtime Modification time (in seconds).
1099+ * @param {function(Error) } callback Optional callback.
1100+ * @param {object } ctx Context object (optional), only for nodejs v10+.
1101+ * @return {* } The return if no callback is provided.
1102+ */
1103+ Binding . prototype . lutimes = function ( pathname , atime , mtime , callback , ctx ) {
1104+ markSyscall ( ctx , 'utimes' ) ;
1105+
10761106 return maybeCallback ( normalizeCallback ( callback ) , ctx , this , function ( ) {
10771107 pathname = deBuffer ( pathname ) ;
10781108 const item = this . _system . getItem ( pathname ) ;
10791109 if ( ! item ) {
10801110 throw new FSError ( 'ENOENT' , pathname ) ;
10811111 }
1112+ // lutimes doesn't follow symlink
10821113 item . setATime ( new Date ( atime * 1000 ) ) ;
10831114 item . setMTime ( new Date ( mtime * 1000 ) ) ;
10841115 } ) ;
@@ -1098,7 +1129,17 @@ Binding.prototype.futimes = function (fd, atime, mtime, callback, ctx) {
10981129
10991130 return maybeCallback ( normalizeCallback ( callback ) , ctx , this , function ( ) {
11001131 const descriptor = this . getDescriptorById ( fd ) ;
1101- const item = descriptor . getItem ( ) ;
1132+ let item = descriptor . getItem ( ) ;
1133+ let filepath = this . _system . getFilepath ( item ) ;
1134+ let links = 0 ;
1135+ while ( item instanceof SymbolicLink ) {
1136+ if ( links > MAX_LINKS ) {
1137+ throw new FSError ( 'ELOOP' , filepath ) ;
1138+ }
1139+ filepath = path . resolve ( path . dirname ( filepath ) , item . getPath ( ) ) ;
1140+ item = this . _system . getItem ( filepath ) ;
1141+ ++ links ;
1142+ }
11021143 item . setATime ( new Date ( atime * 1000 ) ) ;
11031144 item . setMTime ( new Date ( mtime * 1000 ) ) ;
11041145 } ) ;
0 commit comments