Fix mode, fs.link, fix other bugs and cleanup
This commit is contained in:
parent
0aaaeacd1a
commit
c526445a43
|
@ -24,6 +24,13 @@ module.exports = {
|
||||||
NODE_TYPE_SYMBOLIC_LINK: 'SYMLINK',
|
NODE_TYPE_SYMBOLIC_LINK: 'SYMLINK',
|
||||||
NODE_TYPE_META: 'META',
|
NODE_TYPE_META: 'META',
|
||||||
|
|
||||||
|
S_IFREG: 0x8000,
|
||||||
|
S_IFDIR: 0x4000,
|
||||||
|
S_IFLNK: 0xA000,
|
||||||
|
|
||||||
|
DEFAULT_DIR_PERMISSIONS: 0x1ED, // 755
|
||||||
|
DEFAULT_FILE_PERMISSIONS: 0x1A4, // 644
|
||||||
|
|
||||||
SYMLOOP_MAX: 10,
|
SYMLOOP_MAX: 10,
|
||||||
|
|
||||||
BINARY_MIME_TYPE: 'application/octet-stream',
|
BINARY_MIME_TYPE: 'application/octet-stream',
|
||||||
|
|
|
@ -900,6 +900,7 @@ function link_node(context, oldpath, newpath, callback) {
|
||||||
var oldDirectoryData;
|
var oldDirectoryData;
|
||||||
var newDirectoryNode;
|
var newDirectoryNode;
|
||||||
var newDirectoryData;
|
var newDirectoryData;
|
||||||
|
var fileNodeID;
|
||||||
var fileNode;
|
var fileNode;
|
||||||
|
|
||||||
function update_time(error) {
|
function update_time(error) {
|
||||||
|
@ -914,18 +915,17 @@ function link_node(context, oldpath, newpath, callback) {
|
||||||
if(error) {
|
if(error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
} else {
|
} else {
|
||||||
fileNode = Node.fromObject(result);
|
fileNode = result;
|
||||||
fileNode.nlinks += 1;
|
fileNode.nlinks += 1;
|
||||||
fileNode.updatePathInfo(newpath);
|
|
||||||
context.putObject(fileNode.id, fileNode, update_time);
|
context.putObject(fileNode.id, fileNode, update_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function read_directory_entry(error, result) {
|
function read_file_node(error, result) {
|
||||||
if(error) {
|
if(error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
} else {
|
} else {
|
||||||
context.getObject(newDirectoryData[newname].id, update_file_node);
|
context.getObject(fileNodeID, update_file_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -938,7 +938,8 @@ function link_node(context, oldpath, newpath, callback) {
|
||||||
callback(new Errors.EEXIST('newpath resolves to an existing file', newname));
|
callback(new Errors.EEXIST('newpath resolves to an existing file', newname));
|
||||||
} else {
|
} else {
|
||||||
newDirectoryData[newname] = oldDirectoryData[oldname];
|
newDirectoryData[newname] = oldDirectoryData[oldname];
|
||||||
context.putObject(newDirectoryNode.data, newDirectoryData, read_directory_entry);
|
fileNodeID = newDirectoryData[newname].id;
|
||||||
|
context.putObject(newDirectoryNode.data, newDirectoryData, read_file_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1648,7 +1649,7 @@ function stat(fs, context, path, callback) {
|
||||||
if(error) {
|
if(error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
} else {
|
} else {
|
||||||
var stats = new Stats(result, fs.name);
|
var stats = new Stats(path, result, fs.name);
|
||||||
callback(null, stats);
|
callback(null, stats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1661,7 +1662,7 @@ function fstat(fs, context, fd, callback) {
|
||||||
if(error) {
|
if(error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
} else {
|
} else {
|
||||||
var stats = new Stats(result, fs.name);
|
var stats = new Stats(fd.path, result, fs.name);
|
||||||
callback(null, stats);
|
callback(null, stats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1734,7 +1735,7 @@ function readFile(fs, context, path, options, callback) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
var stats = new Stats(fstatResult, fs.name);
|
var stats = new Stats(ofd.path, fstatResult, fs.name);
|
||||||
|
|
||||||
if(stats.isDirectory()) {
|
if(stats.isDirectory()) {
|
||||||
cleanup();
|
cleanup();
|
||||||
|
@ -2009,31 +2010,20 @@ function rename(fs, context, oldpath, newpath, callback) {
|
||||||
var ctime = Date.now();
|
var ctime = Date.now();
|
||||||
var fileNode;
|
var fileNode;
|
||||||
|
|
||||||
function update_times(error) {
|
function update_times(error, result) {
|
||||||
if(error) {
|
if(error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
} else {
|
} else {
|
||||||
|
fileNode = result;
|
||||||
update_node_times(context, newpath, fileNode, { ctime: ctime }, callback);
|
update_node_times(context, newpath, fileNode, { ctime: ctime }, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function update_file_node(error, result) {
|
|
||||||
if(error) {
|
|
||||||
callback(error);
|
|
||||||
} else {
|
|
||||||
fileNode = Node.fromObject(result);
|
|
||||||
// Don't think I need this here...
|
|
||||||
// fileNode.nlinks += 1;
|
|
||||||
fileNode.updatePathInfo(newpath);
|
|
||||||
context.putObject(fileNode.id, fileNode, update_times);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function read_new_directory(error) {
|
function read_new_directory(error) {
|
||||||
if(error) {
|
if(error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
} else {
|
} else {
|
||||||
context.getObject(newParentData[newName].id, update_file_node);
|
context.getObject(newParentData[newName].id, update_times);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2139,7 +2129,7 @@ function lstat(fs, context, path, callback) {
|
||||||
if(error) {
|
if(error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
} else {
|
} else {
|
||||||
var stats = new Stats(result, fs.name);
|
var stats = new Stats(path, result, fs.name);
|
||||||
callback(null, stats);
|
callback(null, stats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
50
src/node.js
50
src/node.js
|
@ -8,9 +8,25 @@ var NODE_TYPE_META = require('./constants.js').NODE_TYPE_META;
|
||||||
|
|
||||||
var ROOT_DIRECTORY_NAME = require('./constants.js').ROOT_DIRECTORY_NAME;
|
var ROOT_DIRECTORY_NAME = require('./constants.js').ROOT_DIRECTORY_NAME;
|
||||||
|
|
||||||
// Name of file/dir. Must be '/' if the file is the root directory of the server
|
var S_IFREG = require('./constants.js').S_IFREG;
|
||||||
function pathToName(pathName) {
|
var S_IFDIR = require('./constants.js').S_IFDIR;
|
||||||
return pathName === ROOT_DIRECTORY_NAME ? ROOT_DIRECTORY_NAME : path.basename(pathName);
|
var S_IFLNK = require('./constants.js').S_IFLNK;
|
||||||
|
|
||||||
|
var DEFAULT_FILE_PERMISSIONS = require('./constants.js').DEFAULT_FILE_PERMISSIONS;
|
||||||
|
var DEFAULT_DIR_PERMISSIONS = require('./constants.js').DEFAULT_DIR_PERMISSIONS;
|
||||||
|
|
||||||
|
function getMode(type) {
|
||||||
|
switch(type) {
|
||||||
|
case NODE_TYPE_DIRECTORY:
|
||||||
|
return DEFAULT_DIR_PERMISSIONS | S_IFDIR;
|
||||||
|
case NODE_TYPE_SYMBOLIC_LINK:
|
||||||
|
return DEFAULT_FILE_PERMISSIONS | S_IFLNK;
|
||||||
|
/* jshint -W086 */
|
||||||
|
case NODE_TYPE_FILE:
|
||||||
|
// falls through
|
||||||
|
default:
|
||||||
|
return DEFAULT_FILE_PERMISSIONS | S_IFREG;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Node(options) {
|
function Node(options) {
|
||||||
|
@ -18,7 +34,6 @@ function Node(options) {
|
||||||
|
|
||||||
this.id = options.id;
|
this.id = options.id;
|
||||||
this.type = options.type || NODE_TYPE_FILE; // node type (file, directory, etc)
|
this.type = options.type || NODE_TYPE_FILE; // node type (file, directory, etc)
|
||||||
this.name = options.name || (pathToName(options.path));
|
|
||||||
this.size = options.size || 0; // size (bytes for files, entries for directories)
|
this.size = options.size || 0; // size (bytes for files, entries for directories)
|
||||||
this.atime = options.atime || now; // access time (will mirror ctime after creation)
|
this.atime = options.atime || now; // access time (will mirror ctime after creation)
|
||||||
this.ctime = options.ctime || now; // creation/change time
|
this.ctime = options.ctime || now; // creation/change time
|
||||||
|
@ -30,16 +45,11 @@ function Node(options) {
|
||||||
this.version = options.version || 1;
|
this.version = options.version || 1;
|
||||||
|
|
||||||
// permissions and flags
|
// permissions and flags
|
||||||
this.mode = options.mode || (this.type === NODE_TYPE_DIRECTORY ? /* 755 */ 493 : /* 644 */ 420);
|
this.mode = options.mode || (getMode(this.type));
|
||||||
this.uid = options.uid || 0x0; // owner name
|
this.uid = options.uid || 0x0; // owner name
|
||||||
this.gid = options.gid || 0x0; // group name
|
this.gid = options.gid || 0x0; // group name
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the node's path changes, update info that relates to it.
|
|
||||||
Node.prototype.updatePathInfo = function(newPath) {
|
|
||||||
this.name = pathToName(newPath);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Make sure the options object has an id on property,
|
// Make sure the options object has an id on property,
|
||||||
// either from caller or one we generate using supplied guid fn.
|
// either from caller or one we generate using supplied guid fn.
|
||||||
function ensureID(options, prop, callback) {
|
function ensureID(options, prop, callback) {
|
||||||
|
@ -72,24 +82,4 @@ Node.create = function(options, callback) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Node.fromObject = function(object) {
|
|
||||||
return new Node({
|
|
||||||
id: object.id,
|
|
||||||
type: object.type,
|
|
||||||
name: object.name,
|
|
||||||
size: object.size,
|
|
||||||
atime: object.atime,
|
|
||||||
ctime: object.ctime,
|
|
||||||
mtime: object.mtime,
|
|
||||||
flags: object.flags,
|
|
||||||
xattrs: object.xattrs,
|
|
||||||
nlinks: object.nlinks,
|
|
||||||
data: object.data,
|
|
||||||
mode: object.mode,
|
|
||||||
uid: object.uid,
|
|
||||||
gid: object.gid,
|
|
||||||
version: object.version
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = Node;
|
module.exports = Node;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
var Constants = require('./constants.js');
|
var Constants = require('./constants.js');
|
||||||
|
var Path = require('./path.js');
|
||||||
|
|
||||||
function Stats(fileNode, devName) {
|
function Stats(path, fileNode, devName) {
|
||||||
this.dev = devName;
|
this.dev = devName;
|
||||||
this.node = fileNode.id;
|
this.node = fileNode.id;
|
||||||
this.type = fileNode.type;
|
this.type = fileNode.type;
|
||||||
|
@ -14,6 +15,7 @@ function Stats(fileNode, devName) {
|
||||||
this.mode = fileNode.mode;
|
this.mode = fileNode.mode;
|
||||||
this.uid = fileNode.uid;
|
this.uid = fileNode.uid;
|
||||||
this.gid = fileNode.gid;
|
this.gid = fileNode.gid;
|
||||||
|
this.name = Path.basename(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stats.prototype.isFile = function() {
|
Stats.prototype.isFile = function() {
|
||||||
|
|
|
@ -42,6 +42,30 @@ describe('fs.link', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create hard link to identical data node', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
var contents = "Hello World!";
|
||||||
|
|
||||||
|
fs.writeFile('/file', contents, function(err) {
|
||||||
|
if(err) throw err;
|
||||||
|
|
||||||
|
fs.link('/file', '/hlink', function(err) {
|
||||||
|
if(err) throw err;
|
||||||
|
|
||||||
|
fs.readFile('/file', 'utf8', function(err, fileData) {
|
||||||
|
if(err) throw err;
|
||||||
|
|
||||||
|
fs.readFile('/hlink', 'utf8', function(err, hlinkData) {
|
||||||
|
if(err) throw err;
|
||||||
|
|
||||||
|
expect(fileData).to.equal(hlinkData);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should not follow symbolic links', function(done) {
|
it('should not follow symbolic links', function(done) {
|
||||||
var fs = util.fs();
|
var fs = util.fs();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue