From 61111da85d03cac6128690aaa943a4073b4a8898 Mon Sep 17 00:00:00 2001 From: "David Humphrey (:humph) david.humphrey@senecacollege.ca" Date: Wed, 5 Mar 2014 15:57:11 -0500 Subject: [PATCH] Finish atime, ctime, mtime updates for fs operations, fix tests --- src/constants.js | 4 + src/fs.js | 180 +++++++++++++++++++++++++++++---- tests/spec/fs.exists.spec.js | 27 ++--- tests/spec/fs.link.spec.js | 10 +- tests/spec/fs.utimes.spec.js | 3 - tests/spec/shell/touch.spec.js | 1 - 6 files changed, 186 insertions(+), 39 deletions(-) diff --git a/src/constants.js b/src/constants.js index 74871ae..50b1e2e 100644 --- a/src/constants.js +++ b/src/constants.js @@ -58,6 +58,10 @@ define(function(require) { XATTR_CREATE: XATTR_CREATE, XATTR_REPLACE: XATTR_REPLACE, + NOATIME: 'NOATIME', + NOCTIME: 'NOCTIME', + NOMTIME: 'NOMTIME', + FS_READY: 'READY', FS_PENDING: 'PENDING', FS_ERROR: 'ERROR', diff --git a/src/fs.js b/src/fs.js index 42be0fd..483e806 100644 --- a/src/fs.js +++ b/src/fs.js @@ -52,6 +52,9 @@ define(function(require) { var O_FLAGS = require('src/constants').O_FLAGS; var XATTR_CREATE = require('src/constants').XATTR_CREATE; var XATTR_REPLACE = require('src/constants').XATTR_REPLACE; + var NOATIME = require('src/constants').NOATIME; + var NOMTIME = require('src/constants').NOMTIME; + var NOCTIME = require('src/constants').NOCTIME; var providers = require('src/providers/providers'); var adapters = require('src/adapters/adapters'); @@ -131,19 +134,41 @@ define(function(require) { /* * Update node times. Only passed times are modified (undefined times are ignored) + * and filesystem flags are examined in order to override update logic. */ function update_node_times(context, path, node, times, callback) { + // Honour mount flags for how we update times + var flags = context.flags; + if(_(flags).contains(NOCTIME)) { + delete times.ctime; + } + if(_(flags).contains(NOATIME)) { + delete times.atime; + } + if(_(flags).contains(NOMTIME)) { + delete times.mtime; + } + + // Only do the update if required (i.e., times are still present) + var update = false; if(times.ctime) { node.ctime = times.ctime; - } - if(times.mtime) { - node.mtime = times.mtime; + update = true; } if(times.atime) { node.atime = times.atime; + update = true; + } + if(times.mtime) { + node.mtime = times.mtime; + update = true; } - context.put(node.id, node, callback); + if(update) { + context.put(node.id, node, callback); + } else { + callback(); + } } /* @@ -249,9 +274,19 @@ define(function(require) { */ function set_extended_attribute (context, path_or_fd, name, value, flag, callback) { + var path; + function set_xattr (error, node) { var xattr = (node ? node.xattrs[name] : null); + function update_time(error) { + if(error) { + callback(error); + } else { + update_node_times(context, path, node, { ctime: Date.now() }, callback); + } + } + if (error) { callback(error); } @@ -263,14 +298,16 @@ define(function(require) { } else { node.xattrs[name] = value; - context.put(node.id, node, callback); + context.put(node.id, node, update_time); } } if (typeof path_or_fd == 'string') { + path = path_or_fd; find_node(context, path_or_fd, set_xattr); } else if (typeof path_or_fd == 'object' && typeof path_or_fd.id == 'string') { + path = path_or_fd.path; context.get(path_or_fd.id, set_xattr); } else { @@ -374,12 +411,21 @@ define(function(require) { } } + function update_time(error) { + if(error) { + callback(error); + } else { + var now = Date.now(); + update_node_times(context, parentPath, parentDirectoryNode, { mtime: now, ctime: now }, callback); + } + } + function update_parent_directory_data(error) { if(error) { callback(error); } else { parentDirectoryData[name] = new DirectoryEntry(directoryNode.id, MODE_DIRECTORY); - context.put(parentDirectoryNode.data, parentDirectoryData, callback); + context.put(parentDirectoryNode.data, parentDirectoryData, update_time); } } @@ -447,9 +493,18 @@ define(function(require) { } } + function update_time(error) { + if(error) { + callback(error); + } else { + var now = Date.now(); + update_node_times(context, parentPath, parentDirectoryNode, { mtime: now, ctime: now }, remove_directory_node); + } + } + function remove_directory_entry_from_parent_directory_node() { delete parentDirectoryData[name]; - context.put(parentDirectoryNode.data, parentDirectoryData, remove_directory_node); + context.put(parentDirectoryNode.data, parentDirectoryData, update_time); } function remove_directory_node(error) { @@ -566,7 +621,9 @@ define(function(require) { callback(error); } else { fileNode = result; - callback(null, fileNode); + update_node_times(context, path, fileNode, { atime: Date.now() }, function(error) { + callback(error, fileNode); + }); } } @@ -585,12 +642,21 @@ define(function(require) { } } + function update_time(error) { + if(error) { + callback(error); + } else { + var now = Date.now(); + update_node_times(context, parentPath, directoryNode, { mtime: now, ctime: now }, handle_update_result); + } + } + function update_directory_data(error) { if(error) { callback(error); } else { directoryData[name] = new DirectoryEntry(fileNode.id, MODE_FILE); - context.put(directoryNode.data, directoryData, handle_update_result); + context.put(directoryNode.data, directoryData, update_time); } } @@ -736,12 +802,26 @@ define(function(require) { } } + function update_time(error) { + if(error) { + callback(error); + } else { + + } + } + function read_file_data(error, result) { if(error) { callback(error); } else { fileNode = result; - context.get(fileNode.data, handle_file_data); + update_node_times(context, ofd.path, fileNode, { atime: Date.now() }, function(error) { + if(error) { + callback(error); + } else { + context.get(fileNode.data, handle_file_data); + } + }); } } @@ -756,7 +836,9 @@ define(function(require) { if(error) { callback(error); } else { - callback(null, result); + update_node_times(context, path, result, { atime: Date.now() }, function(error) { + callback(error, result); + }); } } @@ -768,7 +850,9 @@ define(function(require) { if(error) { callback(error); } else { - callback(null, result); + update_node_times(context, ofd.path, result, { atime: Date.now() }, function(error) { + callback(error, result); + }); } } @@ -815,7 +899,9 @@ define(function(require) { if(error) { callback(error); } else { - callback(null, result); + update_node_times(context, path, result, { atime: Date.now() }, function(error) { + callback(error, result); + }); } } } @@ -835,13 +921,21 @@ define(function(require) { var newDirectoryData; var fileNode; + function update_time(error) { + if(error) { + callback(error); + } else { + update_node_times(context, newpath, fileNode, { ctime: Date.now() }, callback); + } + } + function update_file_node(error, result) { if(error) { callback(error); } else { fileNode = result; fileNode.nlinks += 1; - context.put(fileNode.id, fileNode, callback); + context.put(fileNode.id, fileNode, update_time); } } @@ -915,7 +1009,10 @@ define(function(require) { callback(error); } else { delete directoryData[name]; - context.put(directoryNode.data, directoryData, callback); + context.put(directoryNode.data, directoryData, function(error) { + var now = Date.now(); + update_node_times(context, parentPath, directoryNode, { mtime: now, ctime: now }, callback); + }); } } @@ -936,7 +1033,9 @@ define(function(require) { if(fileNode.nlinks < 1) { context.delete(fileNode.id, delete_file_data); } else { - context.put(fileNode.id, fileNode, update_directory_data); + context.put(fileNode.id, fileNode, function(error) { + update_node_times(context, path, fileNode, { ctime: Date.now() }, update_directory_data); + }); } } } @@ -1040,12 +1139,21 @@ define(function(require) { context.put(fileNode.id, fileNode, update_directory_data); } + function update_time(error) { + if(error) { + callback(error); + } else { + var now = Date.now(); + update_node_times(context, parentPath, directoryNode, { mtime: now, ctime: now }, callback); + } + } + function update_directory_data(error) { if(error) { callback(error); } else { directoryData[name] = new DirectoryEntry(fileNode.id, MODE_SYMBOLIC_LINK); - context.put(directoryNode.data, directoryData, callback); + context.put(directoryNode.data, directoryData, update_time); } } } @@ -1203,7 +1311,7 @@ define(function(require) { function utimes_file(context, path, atime, mtime, callback) { path = normalize(path); - function update_times (error, node) { + function update_times(error, node) { if (error) { callback(error); } else { @@ -1339,6 +1447,14 @@ define(function(require) { function remove_xattr (error, node) { var xattr = (node ? node.xattrs : null); + function update_time(error) { + if(error) { + callback(error); + } else { + update_node_times(context, path, node, { ctime: Date.now() }, callback); + } + } + if (error) { callback(error); } @@ -1347,7 +1463,7 @@ define(function(require) { } else { delete node.xattrs[name]; - context.put(node.id, node, callback); + context.put(node.id, node, update_time); } } @@ -1365,6 +1481,14 @@ define(function(require) { function fremovexattr_file (context, ofd, name, callback) { function remove_xattr (error, node) { + function update_time(error) { + if(error) { + callback(error); + } else { + update_node_times(context, ofd.path, node, { ctime: Date.now() }, callback); + } + } + if (error) { callback(error); } @@ -1373,7 +1497,7 @@ define(function(require) { } else { delete node.xattrs[name]; - context.put(node.id, node, callback); + context.put(node.id, node, update_time); } } @@ -1514,7 +1638,21 @@ define(function(require) { // Open file system storage provider provider.open(function(err, needsFormatting) { function complete(error) { - fs.provider = provider; + // Wrap the provider so we can extend the context with fs flags. + // From this point forward we won't call open again, so drop it. + fs.provider = { + getReadWriteContext: function() { + var context = provider.getReadWriteContext(); + context.flags = flags; + return context; + }, + getReadOnlyContext: function() { + var context = provider.getReadOnlyContext(); + context.flags = flags; + return context; + } + }; + if(error) { fs.readyState = FS_ERROR; } else { diff --git a/tests/spec/fs.exists.spec.js b/tests/spec/fs.exists.spec.js index ff8bc03..5000d05 100644 --- a/tests/spec/fs.exists.spec.js +++ b/tests/spec/fs.exists.spec.js @@ -11,9 +11,9 @@ define(["Filer", "util"], function(Filer, util) { it('should return false if path does not exist', function(done) { var fs = util.fs(); - fs.exists('/tmp', function(result) { - expect(result).to.exist; - expect(result).equals(false); + + fs.exists('/tmp', function(result) { + expect(result).to.be.false; done(); }); }); @@ -22,30 +22,33 @@ define(["Filer", "util"], function(Filer, util) { var fs = util.fs(); fs.open('/myfile', 'w', function(err, fd) { + if(err) throw err; + + fs.close(fd, function(err) { if(err) throw err; - fs.close(fd, function(err) { - if(err) throw err; - fs.exists('/myfile', function(result) { - expect(result).to.exist; - expect(result).equals(true); - done(); - }); + + fs.exists('/myfile', function(result) { + expect(result).to.be.true; + done(); }); }); }); + }); it('should follow symbolic links and return true for the resulting path', function(done) { var fs = util.fs(); fs.open('/myfile', 'w', function(error, fd) { if(error) throw error; + fs.close(fd, function(error) { if(error) throw error; + fs.symlink('/myfile', '/myfilelink', function(error) { if(error) throw error; + fs.exists('/myfilelink', function(result) { - expect(result).to.exist; - expect(result).equals(true); + expect(result).to.be.true; done(); }); }); diff --git a/tests/spec/fs.link.spec.js b/tests/spec/fs.link.spec.js index d6ad840..b4db747 100644 --- a/tests/spec/fs.link.spec.js +++ b/tests/spec/fs.link.spec.js @@ -28,7 +28,10 @@ define(["Filer", "util"], function(Filer, util) { fs.stat('/myotherfile', function(error, result) { expect(error).not.to.exist; expect(result.nlinks).to.equal(2); - expect(result).to.deep.equal(_oldstats); + expect(result.dev).to.equal(_oldstats.dev); + expect(result.node).to.equal(_oldstats.node); + expect(result.size).to.equal(_oldstats.size); + expect(result.type).to.equal(_oldstats.type); done(); }); }); @@ -52,7 +55,10 @@ define(["Filer", "util"], function(Filer, util) { var _linkstats = result; fs.lstat('/myotherfile', function (error, result) { expect(error).not.to.exist; - expect(result).to.deep.equal(_linkstats); + expect(result.dev).to.equal(_linkstats.dev); + expect(result.node).to.equal(_linkstats.node); + expect(result.size).to.equal(_linkstats.size); + expect(result.type).to.equal(_linkstats.type); expect(result.nlinks).to.equal(2); done(); }); diff --git a/tests/spec/fs.utimes.spec.js b/tests/spec/fs.utimes.spec.js index 253f102..f87970f 100644 --- a/tests/spec/fs.utimes.spec.js +++ b/tests/spec/fs.utimes.spec.js @@ -102,7 +102,6 @@ define(["Filer", "util"], function(Filer, util) { fs.stat('/testfile', function (error, stat) { expect(error).not.to.exist; - expect(stat.atime).to.equal(atime); expect(stat.mtime).to.equal(mtime); done(); }); @@ -125,7 +124,6 @@ define(["Filer", "util"], function(Filer, util) { fs.fstat(ofd, function (error, stat) { expect(error).not.to.exist; - expect(stat.atime).to.equal(atime); expect(stat.mtime).to.equal(mtime); done(); }); @@ -146,7 +144,6 @@ define(["Filer", "util"], function(Filer, util) { fs.stat('/testdir', function (error, stat) { expect(error).not.to.exist; - expect(stat.atime).to.equal(atime); expect(stat.mtime).to.equal(mtime); done(); }); diff --git a/tests/spec/shell/touch.spec.js b/tests/spec/shell/touch.spec.js index 3b3a12a..224c8e7 100644 --- a/tests/spec/shell/touch.spec.js +++ b/tests/spec/shell/touch.spec.js @@ -92,7 +92,6 @@ define(["Filer", "util"], function(Filer, util) { getTimes(fs, '/newfile', function(times) { expect(times.mtime).to.equal(date); - expect(times.atime).to.equal(date); done(); }); });