Repository: gulpjs/vinyl-fs (js)

Issue:
fs.futimes causes gulp build failure on AIX 6
node -v
8.11.4

gulp
@4.0.0

See [https://github.com/nodejs/node/issues/12609](https://github.com/nodejs/node/issues/12609). This causes the following error with gulp on any gulp.dest():

Error: ENOSYS: function not implemented, futime

Currently I'm using a monkeypatch to ignore fs.futimes ENOSYS errors in lib/file-operations.js, but I'm not exactly sure if it's a proper enough solution.

Pull request:
fix!: Avoid error and reflect filesystem stat if futimes not implemented
Closes #302

We attempt to reflect the vinyl stats to the filesystem using `futimes`, but if a system doesn't allow that due to ENOSYS, we don't want to error; however, the vinyl file stats need to match the filesystem stats, so we now sync them with the filesystem stats. This is fixing the issue, but is also a breaking change in how those stats are reflected.

Patch:
diff --git a/lib/file-operations.js b/lib/file-operations.js
index 27a94a7..e7c88c5 100644
--- a/lib/file-operations.js
+++ b/lib/file-operations.js
@@ -278,6 +278,13 @@ function updateMetadata(fd, file, callback) {
           file.stat.atime = timesDiff.atime;
           file.stat.mtime = timesDiff.mtime;
         }
+        // If a filesystem doesn't implement futimes, we don't callback with the error.
+        // Instead we update the stats to match filesystem and clear the error.
+        if (futimesErr && futimesErr.code === 'ENOSYS') {
+          file.stat.atime = stat.atime;
+          file.stat.mtime = stat.mtime;
+          futimesErr = null;
+        }
         if (ownerDiff) {
           return owner(propagatedErr || futimesErr);
         }


Test patch:
diff --git a/test/file-operations.js b/test/file-operations.js
index 11cbc84..2fc4228 100644
--- a/test/file-operations.js
+++ b/test/file-operations.js
@@ -1242,6 +1242,47 @@ describe('updateMetadata', function () {
     });
   });
 
+  it('sets stats to filesystem stats if futimes is not implemented (issue 302)', function (done) {
+    if (isWindows) {
+      this.skip();
+      return;
+    }
+
+    var futimesSpy = sinon.stub(fs, 'futimes').callsFake(function () {
+      var callback = arguments[arguments.length - 1];
+      var err = new Error('ENOSYS: function not implemented, futime');
+      err.errno = -109;
+      err.code = 'ENOSYS';
+      err.syscall = 'futime';
+      callback(err);
+    });
+
+    var fd = fs.openSync(outputPath, 'w+');
+    expect(typeof fd === 'number').toEqual(true);
+
+    var stat = fs.fstatSync(fd);
+
+    var file = new File({
+      base: outputBase,
+      path: outputPath,
+      contents: null,
+      stat: {
+        mtime: new Date(stat.mtime - 1000),
+        atime: new Date(stat.atime - 1000),
+      },
+    });
+
+    updateMetadata(fd, file, function (err) {
+      expect(err).not.toEqual(expect.anything());
+      expect(futimesSpy.callCount).toEqual(1);
+      // Times were updated to match the filesystem since futimes wasn't implemented
+      expect(file.stat.mtime).toEqual(stat.mtime);
+      expect(file.stat.atime).toEqual(stat.atime);
+
+      fs.close(fd, done);
+    });
+  });
+
   it('updates the mode on fs and vinyl object if there is a diff', function (done) {
     if (isWindows) {
       this.skip();