Merge pull request #137 from humphd/issue2
Update atime, ctime, mtime on fs operations. Fixes #2
This commit is contained in:
commit
27262cdb67
|
@ -80,7 +80,10 @@ Accepts two arguments: an `options` object, and an optional `callback`. The `opt
|
||||||
object can specify a number of optional arguments, including:
|
object can specify a number of optional arguments, including:
|
||||||
|
|
||||||
* `name`: the name of the file system, defaults to `'"local'`
|
* `name`: the name of the file system, defaults to `'"local'`
|
||||||
* `flags`: one or more flags to use when creating/opening the file system. Use `'FORMAT'` to force Filer to format (i.e., erase) the file system
|
* `flags`: an Array of one or more flags to use when creating/opening the file system:
|
||||||
|
*`'FORMAT'` to force Filer to format (i.e., erase) the file system
|
||||||
|
*`'NOCTIME'` to force Filer to not update `ctime` on nodes when metadata changes (i.e., for better performance)
|
||||||
|
*`'NOMTIME'` to force Filer to not update `mtime` on nodes when data changes (i.e., for better performance)
|
||||||
* `provider`: an explicit storage provider to use for the file system's database context provider. See the section on [Storage Providers](#providers).
|
* `provider`: an explicit storage provider to use for the file system's database context provider. See the section on [Storage Providers](#providers).
|
||||||
|
|
||||||
The `callback` function indicates when the file system is ready for use. Depending on the storage provider used, this might
|
The `callback` function indicates when the file system is ready for use. Depending on the storage provider used, this might
|
||||||
|
@ -98,7 +101,7 @@ function fsReady(err, fs) {
|
||||||
|
|
||||||
fs = new Filer.FileSystem({
|
fs = new Filer.FileSystem({
|
||||||
name: "my-filesystem",
|
name: "my-filesystem",
|
||||||
flags: 'FORMAT',
|
flags: [ 'FORMAT' ],
|
||||||
provider: new Filer.FileSystem.providers.Memory()
|
provider: new Filer.FileSystem.providers.Memory()
|
||||||
}, fsReady);
|
}, fsReady);
|
||||||
```
|
```
|
||||||
|
|
|
@ -33,8 +33,12 @@ define(function(require) {
|
||||||
|
|
||||||
ROOT_DIRECTORY_NAME: '/', // basename(normalize(path))
|
ROOT_DIRECTORY_NAME: '/', // basename(normalize(path))
|
||||||
|
|
||||||
|
// FS Mount Flags
|
||||||
FS_FORMAT: 'FORMAT',
|
FS_FORMAT: 'FORMAT',
|
||||||
|
FS_NOCTIME: 'NOCTIME',
|
||||||
|
FS_NOMTIME: 'NOMTIME',
|
||||||
|
|
||||||
|
// FS File Open Flags
|
||||||
O_READ: O_READ,
|
O_READ: O_READ,
|
||||||
O_WRITE: O_WRITE,
|
O_WRITE: O_WRITE,
|
||||||
O_CREATE: O_CREATE,
|
O_CREATE: O_CREATE,
|
||||||
|
|
243
src/fs.js
243
src/fs.js
|
@ -52,6 +52,8 @@ 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 FS_NOMTIME = require('src/constants').FS_NOMTIME;
|
||||||
|
var FS_NOCTIME = require('src/constants').FS_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');
|
||||||
|
@ -70,7 +72,8 @@ define(function(require) {
|
||||||
* OpenFileDescription
|
* OpenFileDescription
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function OpenFileDescription(id, flags, position) {
|
function OpenFileDescription(path, id, flags, position) {
|
||||||
|
this.path = path;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.flags = flags;
|
this.flags = flags;
|
||||||
this.position = position;
|
this.position = position;
|
||||||
|
@ -101,8 +104,8 @@ define(function(require) {
|
||||||
this.id = id || guid();
|
this.id = id || guid();
|
||||||
this.mode = mode || MODE_FILE; // node type (file, directory, etc)
|
this.mode = mode || MODE_FILE; // node type (file, directory, etc)
|
||||||
this.size = size || 0; // size (bytes for files, entries for directories)
|
this.size = size || 0; // size (bytes for files, entries for directories)
|
||||||
this.atime = atime || now; // access time
|
this.atime = atime || now; // access time (will mirror ctime after creation)
|
||||||
this.ctime = ctime || now; // creation time
|
this.ctime = ctime || now; // creation/change time
|
||||||
this.mtime = mtime || now; // modified time
|
this.mtime = mtime || now; // modified time
|
||||||
this.flags = flags || []; // file flags
|
this.flags = flags || []; // file flags
|
||||||
this.xattrs = xattrs || {}; // extended attributes
|
this.xattrs = xattrs || {}; // extended attributes
|
||||||
|
@ -128,6 +131,46 @@ define(function(require) {
|
||||||
this.type = fileNode.mode;
|
this.type = fileNode.mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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(FS_NOCTIME)) {
|
||||||
|
delete times.ctime;
|
||||||
|
}
|
||||||
|
if(_(flags).contains(FS_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;
|
||||||
|
// We don't do atime tracking for perf reasons, but do mirror ctime
|
||||||
|
node.atime = times.ctime;
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
if(times.atime) {
|
||||||
|
// The only time we explicitly pass atime is when utimes(), futimes() is called.
|
||||||
|
// Override ctime mirror here if so
|
||||||
|
node.atime = times.atime;
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
if(times.mtime) {
|
||||||
|
node.mtime = times.mtime;
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(update) {
|
||||||
|
context.put(node.id, node, callback);
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* find_node
|
* find_node
|
||||||
*/
|
*/
|
||||||
|
@ -231,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);
|
||||||
}
|
}
|
||||||
|
@ -245,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 {
|
||||||
|
@ -356,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,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) {
|
||||||
|
@ -567,12 +640,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -596,11 +678,20 @@ define(function(require) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function update_time(error) {
|
||||||
|
if(error) {
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
var now = Date.now();
|
||||||
|
update_node_times(context, ofd.path, fileNode, { mtime: now, ctime: now }, return_nbytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function update_file_node(error) {
|
function update_file_node(error) {
|
||||||
if(error) {
|
if(error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
} else {
|
} else {
|
||||||
context.put(fileNode.id, fileNode, return_nbytes);
|
context.put(fileNode.id, fileNode, update_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,7 +706,6 @@ define(function(require) {
|
||||||
ofd.position = length;
|
ofd.position = length;
|
||||||
|
|
||||||
fileNode.size = length;
|
fileNode.size = length;
|
||||||
fileNode.mtime = Date.now();
|
|
||||||
fileNode.version += 1;
|
fileNode.version += 1;
|
||||||
|
|
||||||
context.put(fileNode.data, newData, update_file_node);
|
context.put(fileNode.data, newData, update_file_node);
|
||||||
|
@ -637,11 +727,20 @@ define(function(require) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function update_time(error) {
|
||||||
|
if(error) {
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
var now = Date.now();
|
||||||
|
update_node_times(context, ofd.path, fileNode, { mtime: now, ctime: now }, return_nbytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function update_file_node(error) {
|
function update_file_node(error) {
|
||||||
if(error) {
|
if(error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
} else {
|
} else {
|
||||||
context.put(fileNode.id, fileNode, return_nbytes);
|
context.put(fileNode.id, fileNode, update_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -663,7 +762,6 @@ define(function(require) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fileNode.size = newSize;
|
fileNode.size = newSize;
|
||||||
fileNode.mtime = Date.now();
|
|
||||||
fileNode.version += 1;
|
fileNode.version += 1;
|
||||||
|
|
||||||
context.put(fileNode.data, newData, update_file_node);
|
context.put(fileNode.data, newData, update_file_node);
|
||||||
|
@ -702,6 +800,14 @@ 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);
|
||||||
|
@ -801,13 +907,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -881,7 +995,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);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -902,7 +1019,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);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1006,12 +1125,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1089,14 +1217,22 @@ define(function(require) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function update_time(error) {
|
||||||
|
if(error) {
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
var now = Date.now();
|
||||||
|
update_node_times(context, path, fileNode, { mtime: now, ctime: now }, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function update_file_node (error) {
|
function update_file_node (error) {
|
||||||
if(error) {
|
if(error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
} else {
|
} else {
|
||||||
fileNode.size = length;
|
fileNode.size = length;
|
||||||
fileNode.mtime = Date.now();
|
|
||||||
fileNode.version += 1;
|
fileNode.version += 1;
|
||||||
context.put(fileNode.id, fileNode, callback);
|
context.put(fileNode.id, fileNode, update_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1133,14 +1269,21 @@ define(function(require) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function update_time(error) {
|
||||||
|
if(error) {
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
var now = Date.now();
|
||||||
|
update_node_times(context, ofd.path, fileNode, { mtime: now, ctime: now }, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
function update_file_node (error) {
|
function update_file_node (error) {
|
||||||
if(error) {
|
if(error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
} else {
|
} else {
|
||||||
fileNode.size = length;
|
fileNode.size = length;
|
||||||
fileNode.mtime = Date.now();
|
|
||||||
fileNode.version += 1;
|
fileNode.version += 1;
|
||||||
context.put(fileNode.id, fileNode, callback);
|
context.put(fileNode.id, fileNode, update_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1154,14 +1297,11 @@ 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 {
|
update_node_times(context, path, node, { atime: atime, ctime: mtime, mtime: mtime }, callback);
|
||||||
node.atime = atime;
|
|
||||||
node.mtime = mtime;
|
|
||||||
context.put(node.id, node, callback);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1181,11 +1321,8 @@ define(function(require) {
|
||||||
function update_times (error, node) {
|
function update_times (error, node) {
|
||||||
if (error) {
|
if (error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
}
|
} else {
|
||||||
else {
|
update_node_times(context, ofd.path, node, { atime: atime, ctime: mtime, mtime: mtime }, callback);
|
||||||
node.atime = atime;
|
|
||||||
node.mtime = mtime;
|
|
||||||
context.put(node.id, node, callback);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1296,6 +1433,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);
|
||||||
}
|
}
|
||||||
|
@ -1304,7 +1449,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1322,6 +1467,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);
|
||||||
}
|
}
|
||||||
|
@ -1330,7 +1483,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1471,7 +1624,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 {
|
||||||
|
@ -1520,7 +1687,7 @@ define(function(require) {
|
||||||
} else {
|
} else {
|
||||||
position = 0;
|
position = 0;
|
||||||
}
|
}
|
||||||
var openFileDescription = new OpenFileDescription(fileNode.id, flags, position);
|
var openFileDescription = new OpenFileDescription(path, fileNode.id, flags, position);
|
||||||
var fd = fs.allocDescriptor(openFileDescription);
|
var fd = fs.allocDescriptor(openFileDescription);
|
||||||
callback(null, fd);
|
callback(null, fd);
|
||||||
}
|
}
|
||||||
|
@ -1671,7 +1838,7 @@ define(function(require) {
|
||||||
if(err) {
|
if(err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
var ofd = new OpenFileDescription(fileNode.id, flags, 0);
|
var ofd = new OpenFileDescription(path, fileNode.id, flags, 0);
|
||||||
var fd = fs.allocDescriptor(ofd);
|
var fd = fs.allocDescriptor(ofd);
|
||||||
|
|
||||||
fstat_file(context, ofd, function(err2, fstatResult) {
|
fstat_file(context, ofd, function(err2, fstatResult) {
|
||||||
|
@ -1748,7 +1915,7 @@ define(function(require) {
|
||||||
if(err) {
|
if(err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
var ofd = new OpenFileDescription(fileNode.id, flags, 0);
|
var ofd = new OpenFileDescription(path, fileNode.id, flags, 0);
|
||||||
var fd = fs.allocDescriptor(ofd);
|
var fd = fs.allocDescriptor(ofd);
|
||||||
|
|
||||||
replace_data(context, ofd, data, 0, data.length, function(err2, nbytes) {
|
replace_data(context, ofd, data, 0, data.length, function(err2, nbytes) {
|
||||||
|
@ -1783,7 +1950,7 @@ define(function(require) {
|
||||||
if(err) {
|
if(err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
var ofd = new OpenFileDescription(fileNode.id, flags, fileNode.size);
|
var ofd = new OpenFileDescription(path, fileNode.id, flags, fileNode.size);
|
||||||
var fd = fs.allocDescriptor(ofd);
|
var fd = fs.allocDescriptor(ofd);
|
||||||
|
|
||||||
write_data(context, ofd, data, 0, data.length, ofd.position, function(err2, nbytes) {
|
write_data(context, ofd, data, 0, data.length, ofd.position, function(err2, nbytes) {
|
||||||
|
@ -2284,7 +2451,7 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadOnlyContext();
|
var context = fs.provider.getReadWriteContext();
|
||||||
_exists(context, fs.name, path, callback);
|
_exists(context, fs.name, path, callback);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -131,7 +131,13 @@ define(["Filer", "util"], function(Filer, util) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should fail when trying to write on ReadOnlyContext", function(done) {
|
/**
|
||||||
|
* With issue 123 (see https://github.com/js-platform/filer/issues/128) we had to
|
||||||
|
* start using readwrite contexts everywhere with IndexedDB. As such, we can't
|
||||||
|
* easily test this here, without knowing which provider we have. We test this
|
||||||
|
* in the actual providers, so this isn't really needed. Skipping for now.
|
||||||
|
*/
|
||||||
|
it.skip("should fail when trying to write on ReadOnlyContext", function(done) {
|
||||||
var provider = createProvider();
|
var provider = createProvider();
|
||||||
provider.open(function(error, firstAccess) {
|
provider.open(function(error, firstAccess) {
|
||||||
if(error) throw error;
|
if(error) throw error;
|
||||||
|
|
|
@ -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) {
|
|
||||||
expect(result).to.exist;
|
fs.exists('/tmp', function(result) {
|
||||||
expect(result).equals(false);
|
expect(result).to.be.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();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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();
|
||||||
});
|
});
|
||||||
|
|
|
@ -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();
|
||||||
});
|
});
|
||||||
|
|
|
@ -129,7 +129,11 @@ define(["Filer", "util"], function(Filer, util) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should fail when trying to write on ReadOnlyContext", function(done) {
|
/**
|
||||||
|
* With issue 123 (see https://github.com/js-platform/filer/issues/128) we had to
|
||||||
|
* start using readwrite contexts everywhere with IndexedDB. Skipping for now.
|
||||||
|
*/
|
||||||
|
it.skip("should fail when trying to write on ReadOnlyContext", function(done) {
|
||||||
var provider = _provider.provider;
|
var provider = _provider.provider;
|
||||||
provider.open(function(error, firstAccess) {
|
provider.open(function(error, firstAccess) {
|
||||||
if(error) throw error;
|
if(error) throw error;
|
||||||
|
|
|
@ -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();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
define(["Filer", "util"], function(Filer, util) {
|
||||||
|
|
||||||
|
describe('node times (atime, mtime, ctime) with mount flags', function() {
|
||||||
|
|
||||||
|
var dirname = "/dir";
|
||||||
|
var filename = "/dir/file";
|
||||||
|
|
||||||
|
function memoryFS(flags, callback) {
|
||||||
|
var name = util.uniqueName();
|
||||||
|
var fs = new Filer.FileSystem({
|
||||||
|
name: name,
|
||||||
|
flags: flags || [],
|
||||||
|
provider: new Filer.FileSystem.providers.Memory(name)
|
||||||
|
}, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTree(fs, callback) {
|
||||||
|
fs.mkdir(dirname, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
fs.open(filename, 'w', function(error, fd) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
fs.close(fd, callback);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function stat(fs, path, callback) {
|
||||||
|
fs.stat(path, function(error, stats) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
callback(stats);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We test the actual time updates in times.spec.js, whereas these just test
|
||||||
|
* the overrides with the mount flags. The particular fs methods called
|
||||||
|
* are unimportant, but are known to affect the particular times being suppressed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
it('should not update ctime when calling fs.rename() with NOCTIME', function(done) {
|
||||||
|
memoryFS(['NOCTIME'], function(error, fs) {
|
||||||
|
var newfilename = filename + '1';
|
||||||
|
|
||||||
|
createTree(fs, function() {
|
||||||
|
stat(fs, filename, function(stats1) {
|
||||||
|
|
||||||
|
fs.rename(filename, newfilename, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(fs, newfilename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.equal(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.equal(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not update ctime, mtime, atime when calling fs.truncate() with NOCTIME, NOMTIME', function(done) {
|
||||||
|
memoryFS(['NOCTIME', 'NOMTIME'], function(error, fs) {
|
||||||
|
createTree(fs, function() {
|
||||||
|
stat(fs, filename, function(stats1) {
|
||||||
|
|
||||||
|
fs.truncate(filename, 5, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(fs, filename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.equal(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.equal(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not update mtime when calling fs.truncate() with NOMTIME', function(done) {
|
||||||
|
memoryFS(['NOMTIME'], function(error, fs) {
|
||||||
|
createTree(fs, function() {
|
||||||
|
stat(fs, filename, function(stats1) {
|
||||||
|
|
||||||
|
fs.truncate(filename, 5, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(fs, filename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.be.above(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.be.above(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,622 @@
|
||||||
|
define(["Filer", "util"], function(Filer, util) {
|
||||||
|
|
||||||
|
describe('node times (atime, mtime, ctime)', function() {
|
||||||
|
beforeEach(util.setup);
|
||||||
|
afterEach(util.cleanup);
|
||||||
|
|
||||||
|
var dirname = "/dir";
|
||||||
|
var filename = "/dir/file";
|
||||||
|
|
||||||
|
function createTree(callback) {
|
||||||
|
var fs = util.fs();
|
||||||
|
fs.mkdir(dirname, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
fs.open(filename, 'w', function(error, fd) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
fs.close(fd, callback);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function stat(path, callback) {
|
||||||
|
var fs = util.fs();
|
||||||
|
fs.stat(path, function(error, stats) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
callback(stats);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should update ctime when calling fs.rename()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
var newfilename = filename + '1';
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
|
||||||
|
fs.rename(filename, newfilename, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(newfilename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.be.above(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.be.above(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update ctime, mtime, atime when calling fs.truncate()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
|
||||||
|
fs.truncate(filename, 5, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.be.above(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.be.above(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.be.above(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update ctime, mtime, atime when calling fs.ftruncate()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
|
||||||
|
fs.open(filename, 'w', function(error, fd) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
fs.ftruncate(fd, 5, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.be.above(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.be.above(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.be.above(stats1.atime);
|
||||||
|
|
||||||
|
fs.close(fd, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make no change when calling fs.stat()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
|
||||||
|
fs.stat(filename, function(error, stats2) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
expect(stats2.ctime).to.equal(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.equal(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make no change when calling fs.fstat()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
|
||||||
|
fs.open(filename, 'w', function(error, fd) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
fs.fstat(fd, function(error, stats2) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
expect(stats2.ctime).to.equal(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.equal(stats1.atime);
|
||||||
|
|
||||||
|
fs.close(fd, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make no change when calling fs.lstat()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
fs.link(filename, '/link', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
fs.lstat('/link', function(error, stats2) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
expect(stats2.ctime).to.equal(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.equal(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make no change when calling fs.exists()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
|
||||||
|
fs.exists(filename, function(exists) {
|
||||||
|
expect(exists).to.be.true;
|
||||||
|
|
||||||
|
fs.stat(filename, function(error, stats2) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
expect(stats2.ctime).to.equal(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.equal(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update ctime, atime when calling fs.link()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
fs.link(filename, '/link', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.be.above(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.be.above(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make no change when calling fs.symlink()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
fs.symlink(filename, '/link', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.equal(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.equal(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make no change when calling fs.readlink()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
fs.symlink(filename, '/link', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat('/link', function(stats1) {
|
||||||
|
fs.readlink('/link', function(error, contents) {
|
||||||
|
if(error) throw error;
|
||||||
|
expect(contents).to.equal(filename);
|
||||||
|
|
||||||
|
stat('/link', function(stats2) {
|
||||||
|
expect(stats2.ctime).to.equal(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.equal(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update ctime, atime, mtime of parent dir when calling fs.unlink()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
stat(dirname, function(stats1) {
|
||||||
|
fs.unlink(filename, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(dirname, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.be.above(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.be.above(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.be.above(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update ctime, atime, mtime of parent dir when calling fs.rmdir()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
stat('/', function(stats1) {
|
||||||
|
|
||||||
|
fs.unlink(filename, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
fs.rmdir(dirname, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat('/', function(stats2) {
|
||||||
|
expect(stats2.ctime).to.be.above(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.be.above(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.be.above(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update ctime, atime, mtime of parent dir when calling fs.mkdir()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
stat('/', function(stats1) {
|
||||||
|
|
||||||
|
fs.mkdir('/a', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat('/', function(stats2) {
|
||||||
|
expect(stats2.ctime).to.be.above(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.be.above(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.be.above(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make no change when calling fs.close()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
fs.open(filename, 'w', function(error, fd) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
fs.close(fd, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.equal(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.equal(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make no change when calling fs.open()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
fs.open(filename, 'w', function(error, fd) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.equal(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.equal(stats1.atime);
|
||||||
|
|
||||||
|
fs.close(fd, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fs.utimes and fs.futimes are tested elsewhere already, skipping
|
||||||
|
*/
|
||||||
|
|
||||||
|
it('should update atime, ctime, mtime when calling fs.write()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
var buffer = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
fs.open('/myfile', 'w', function(err, fd) {
|
||||||
|
if(err) throw error;
|
||||||
|
|
||||||
|
stat('/myfile', function(stats1) {
|
||||||
|
fs.write(fd, buffer, 0, buffer.length, 0, function(err, nbytes) {
|
||||||
|
if(err) throw error;
|
||||||
|
|
||||||
|
fs.close(fd, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat('/myfile', function(stats2) {
|
||||||
|
expect(stats2.ctime).to.be.above(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.be.above(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.be.above(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make no change when calling fs.read()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
var buffer = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
fs.open('/myfile', 'w', function(err, fd) {
|
||||||
|
if(err) throw err;
|
||||||
|
|
||||||
|
fs.write(fd, buffer, 0, buffer.length, 0, function(err, nbytes) {
|
||||||
|
if(err) throw err;
|
||||||
|
|
||||||
|
fs.close(fd, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
fs.open('/myfile', 'r', function(error, fd) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat('/myfile', function(stats1) {
|
||||||
|
var buffer2 = new Uint8Array(buffer.length);
|
||||||
|
fs.read(fd, buffer2, 0, buffer2.length, 0, function(err, nbytes) {
|
||||||
|
|
||||||
|
fs.close(fd, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat('/myfile', function(stats2) {
|
||||||
|
expect(stats2.ctime).to.equal(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.equal(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make no change when calling fs.readFile()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
fs.readFile(filename, function(error, data) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.equal(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.equal(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update atime, ctime, mtime when calling fs.writeFile()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
fs.writeFile(filename, 'data', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.be.above(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.be.above(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.be.above(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update atime, ctime, mtime when calling fs.appendFile()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
fs.appendFile(filename, '...more data', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.be.above(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.be.above(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.be.above(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update ctime, atime when calling fs.setxattr()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
fs.setxattr(filename, 'extra', 'data', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.be.above(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.be.above(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update ctime, atime when calling fs.fsetxattr()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
fs.open(filename, 'w', function(error, fd) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
fs.fsetxattr(fd, 'extra', 'data', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.be.above(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.be.above(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make no change when calling fs.getxattr()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
fs.setxattr(filename, 'extra', 'data', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
fs.getxattr(filename, 'extra', function(error, value) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.equal(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.equal(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make no change when calling fs.fgetxattr()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
fs.open(filename, 'w', function(error, fd) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
fs.fsetxattr(fd, 'extra', 'data', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
fs.fgetxattr(fd, 'extra', function(error, value) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.equal(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.equal(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update ctime, atime when calling fs.removexattr()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
fs.setxattr(filename, 'extra', 'data', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
fs.removexattr(filename, 'extra', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.be.above(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.be.above(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update ctime, atime when calling fs.fremovexattr()', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
createTree(function() {
|
||||||
|
fs.open(filename, 'w', function(error, fd) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
fs.fsetxattr(fd, 'extra', 'data', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats1) {
|
||||||
|
fs.fremovexattr(fd, 'extra', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
stat(filename, function(stats2) {
|
||||||
|
expect(stats2.ctime).to.be.above(stats1.ctime);
|
||||||
|
expect(stats2.mtime).to.equal(stats1.mtime);
|
||||||
|
expect(stats2.atime).to.be.above(stats1.atime);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
|
@ -32,6 +32,8 @@ define([
|
||||||
"spec/fs.utimes.spec",
|
"spec/fs.utimes.spec",
|
||||||
"spec/fs.xattr.spec",
|
"spec/fs.xattr.spec",
|
||||||
"spec/path-resolution.spec",
|
"spec/path-resolution.spec",
|
||||||
|
"spec/times.spec",
|
||||||
|
"spec/time-flags.spec",
|
||||||
|
|
||||||
// Filer.FileSystem.providers.*
|
// Filer.FileSystem.providers.*
|
||||||
"spec/providers/providers.spec",
|
"spec/providers/providers.spec",
|
||||||
|
|
Loading…
Reference in New Issue