Finish atime, ctime, mtime updates for fs operations, fix tests

This commit is contained in:
David Humphrey (:humph) david.humphrey@senecacollege.ca 2014-03-05 15:57:11 -05:00
parent 1fdd9ac476
commit 61111da85d
6 changed files with 186 additions and 39 deletions

View File

@ -58,6 +58,10 @@ define(function(require) {
XATTR_CREATE: XATTR_CREATE, XATTR_CREATE: XATTR_CREATE,
XATTR_REPLACE: XATTR_REPLACE, XATTR_REPLACE: XATTR_REPLACE,
NOATIME: 'NOATIME',
NOCTIME: 'NOCTIME',
NOMTIME: 'NOMTIME',
FS_READY: 'READY', FS_READY: 'READY',
FS_PENDING: 'PENDING', FS_PENDING: 'PENDING',
FS_ERROR: 'ERROR', FS_ERROR: 'ERROR',

180
src/fs.js
View File

@ -52,6 +52,9 @@ define(function(require) {
var O_FLAGS = require('src/constants').O_FLAGS; var O_FLAGS = require('src/constants').O_FLAGS;
var XATTR_CREATE = require('src/constants').XATTR_CREATE; var XATTR_CREATE = require('src/constants').XATTR_CREATE;
var XATTR_REPLACE = require('src/constants').XATTR_REPLACE; 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 providers = require('src/providers/providers');
var adapters = require('src/adapters/adapters'); 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) * 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) { 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) { if(times.ctime) {
node.ctime = times.ctime; node.ctime = times.ctime;
} update = true;
if(times.mtime) {
node.mtime = times.mtime;
} }
if(times.atime) { if(times.atime) {
node.atime = 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) { function set_extended_attribute (context, path_or_fd, name, value, flag, callback) {
var path;
function set_xattr (error, node) { function set_xattr (error, node) {
var xattr = (node ? node.xattrs[name] : null); 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) { if (error) {
callback(error); callback(error);
} }
@ -263,14 +298,16 @@ define(function(require) {
} }
else { else {
node.xattrs[name] = value; node.xattrs[name] = value;
context.put(node.id, node, callback); context.put(node.id, node, update_time);
} }
} }
if (typeof path_or_fd == 'string') { if (typeof path_or_fd == 'string') {
path = path_or_fd;
find_node(context, path_or_fd, set_xattr); find_node(context, path_or_fd, set_xattr);
} }
else if (typeof path_or_fd == 'object' && typeof path_or_fd.id == 'string') { 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); context.get(path_or_fd.id, set_xattr);
} }
else { 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) { function update_parent_directory_data(error) {
if(error) { if(error) {
callback(error); callback(error);
} else { } else {
parentDirectoryData[name] = new DirectoryEntry(directoryNode.id, MODE_DIRECTORY); 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() { function remove_directory_entry_from_parent_directory_node() {
delete parentDirectoryData[name]; delete parentDirectoryData[name];
context.put(parentDirectoryNode.data, parentDirectoryData, remove_directory_node); context.put(parentDirectoryNode.data, parentDirectoryData, update_time);
} }
function remove_directory_node(error) { function remove_directory_node(error) {
@ -566,7 +621,9 @@ define(function(require) {
callback(error); callback(error);
} else { } else {
fileNode = result; 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) { function update_directory_data(error) {
if(error) { if(error) {
callback(error); callback(error);
} else { } else {
directoryData[name] = new DirectoryEntry(fileNode.id, MODE_FILE); 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) { function read_file_data(error, result) {
if(error) { if(error) {
callback(error); callback(error);
} else { } else {
fileNode = result; 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) { if(error) {
callback(error); callback(error);
} else { } 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) { if(error) {
callback(error); callback(error);
} else { } 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) { if(error) {
callback(error); callback(error);
} else { } 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 newDirectoryData;
var fileNode; 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) { function update_file_node(error, result) {
if(error) { if(error) {
callback(error); callback(error);
} else { } else {
fileNode = result; fileNode = result;
fileNode.nlinks += 1; 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); callback(error);
} else { } else {
delete directoryData[name]; 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) { if(fileNode.nlinks < 1) {
context.delete(fileNode.id, delete_file_data); context.delete(fileNode.id, delete_file_data);
} else { } 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); 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) { function update_directory_data(error) {
if(error) { if(error) {
callback(error); callback(error);
} else { } else {
directoryData[name] = new DirectoryEntry(fileNode.id, MODE_SYMBOLIC_LINK); 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) { function utimes_file(context, path, atime, mtime, callback) {
path = normalize(path); path = normalize(path);
function update_times (error, node) { function update_times(error, node) {
if (error) { if (error) {
callback(error); callback(error);
} else { } else {
@ -1339,6 +1447,14 @@ define(function(require) {
function remove_xattr (error, node) { function remove_xattr (error, node) {
var xattr = (node ? node.xattrs : null); 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) { if (error) {
callback(error); callback(error);
} }
@ -1347,7 +1463,7 @@ define(function(require) {
} }
else { else {
delete node.xattrs[name]; 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 fremovexattr_file (context, ofd, name, callback) {
function remove_xattr (error, node) { 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) { if (error) {
callback(error); callback(error);
} }
@ -1373,7 +1497,7 @@ define(function(require) {
} }
else { else {
delete node.xattrs[name]; 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 // Open file system storage provider
provider.open(function(err, needsFormatting) { provider.open(function(err, needsFormatting) {
function complete(error) { 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) { if(error) {
fs.readyState = FS_ERROR; fs.readyState = FS_ERROR;
} else { } else {

View File

@ -11,9 +11,9 @@ define(["Filer", "util"], function(Filer, util) {
it('should return false if path does not exist', function(done) { it('should return false if path does not exist', function(done) {
var fs = util.fs(); var fs = util.fs();
fs.exists('/tmp', function(result) { fs.exists('/tmp', function(result) {
expect(result).to.exist; expect(result).to.be.false;
expect(result).equals(false);
done(); done();
}); });
}); });
@ -22,30 +22,33 @@ define(["Filer", "util"], function(Filer, util) {
var fs = util.fs(); var fs = util.fs();
fs.open('/myfile', 'w', function(err, fd) { fs.open('/myfile', 'w', function(err, fd) {
if(err) throw err;
fs.close(fd, function(err) {
if(err) throw err; if(err) throw err;
fs.close(fd, function(err) {
if(err) throw err; fs.exists('/myfile', function(result) {
fs.exists('/myfile', function(result) { expect(result).to.be.true;
expect(result).to.exist; done();
expect(result).equals(true);
done();
});
}); });
}); });
}); });
});
it('should follow symbolic links and return true for the resulting path', function(done) { it('should follow symbolic links and return true for the resulting path', function(done) {
var fs = util.fs(); var fs = util.fs();
fs.open('/myfile', 'w', function(error, fd) { fs.open('/myfile', 'w', function(error, fd) {
if(error) throw error; if(error) throw error;
fs.close(fd, function(error) { fs.close(fd, function(error) {
if(error) throw error; if(error) throw error;
fs.symlink('/myfile', '/myfilelink', function(error) { fs.symlink('/myfile', '/myfilelink', function(error) {
if(error) throw error; if(error) throw error;
fs.exists('/myfilelink', function(result) { fs.exists('/myfilelink', function(result) {
expect(result).to.exist; expect(result).to.be.true;
expect(result).equals(true);
done(); done();
}); });
}); });

View File

@ -28,7 +28,10 @@ define(["Filer", "util"], function(Filer, util) {
fs.stat('/myotherfile', function(error, result) { fs.stat('/myotherfile', function(error, result) {
expect(error).not.to.exist; expect(error).not.to.exist;
expect(result.nlinks).to.equal(2); 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(); done();
}); });
}); });
@ -52,7 +55,10 @@ define(["Filer", "util"], function(Filer, util) {
var _linkstats = result; var _linkstats = result;
fs.lstat('/myotherfile', function (error, result) { fs.lstat('/myotherfile', function (error, result) {
expect(error).not.to.exist; 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); expect(result.nlinks).to.equal(2);
done(); done();
}); });

View File

@ -102,7 +102,6 @@ define(["Filer", "util"], function(Filer, util) {
fs.stat('/testfile', function (error, stat) { fs.stat('/testfile', function (error, stat) {
expect(error).not.to.exist; expect(error).not.to.exist;
expect(stat.atime).to.equal(atime);
expect(stat.mtime).to.equal(mtime); expect(stat.mtime).to.equal(mtime);
done(); done();
}); });
@ -125,7 +124,6 @@ define(["Filer", "util"], function(Filer, util) {
fs.fstat(ofd, function (error, stat) { fs.fstat(ofd, function (error, stat) {
expect(error).not.to.exist; expect(error).not.to.exist;
expect(stat.atime).to.equal(atime);
expect(stat.mtime).to.equal(mtime); expect(stat.mtime).to.equal(mtime);
done(); done();
}); });
@ -146,7 +144,6 @@ define(["Filer", "util"], function(Filer, util) {
fs.stat('/testdir', function (error, stat) { fs.stat('/testdir', function (error, stat) {
expect(error).not.to.exist; expect(error).not.to.exist;
expect(stat.atime).to.equal(atime);
expect(stat.mtime).to.equal(mtime); expect(stat.mtime).to.equal(mtime);
done(); done();
}); });

View File

@ -92,7 +92,6 @@ define(["Filer", "util"], function(Filer, util) {
getTimes(fs, '/newfile', function(times) { getTimes(fs, '/newfile', function(times) {
expect(times.mtime).to.equal(date); expect(times.mtime).to.equal(date);
expect(times.atime).to.equal(date);
done(); done();
}); });
}); });