Fix mode, fs.link, fix other bugs and cleanup

This commit is contained in:
David Humphrey 2018-05-26 16:57:57 -04:00
parent 0aaaeacd1a
commit c526445a43
5 changed files with 67 additions and 54 deletions

View File

@ -24,6 +24,13 @@ module.exports = {
NODE_TYPE_SYMBOLIC_LINK: 'SYMLINK',
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,
BINARY_MIME_TYPE: 'application/octet-stream',

View File

@ -900,6 +900,7 @@ function link_node(context, oldpath, newpath, callback) {
var oldDirectoryData;
var newDirectoryNode;
var newDirectoryData;
var fileNodeID;
var fileNode;
function update_time(error) {
@ -914,18 +915,17 @@ function link_node(context, oldpath, newpath, callback) {
if(error) {
callback(error);
} else {
fileNode = Node.fromObject(result);
fileNode = result;
fileNode.nlinks += 1;
fileNode.updatePathInfo(newpath);
context.putObject(fileNode.id, fileNode, update_time);
}
}
function read_directory_entry(error, result) {
function read_file_node(error, result) {
if(error) {
callback(error);
} 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));
} else {
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) {
callback(error);
} else {
var stats = new Stats(result, fs.name);
var stats = new Stats(path, result, fs.name);
callback(null, stats);
}
}
@ -1661,7 +1662,7 @@ function fstat(fs, context, fd, callback) {
if(error) {
callback(error);
} else {
var stats = new Stats(result, fs.name);
var stats = new Stats(fd.path, result, fs.name);
callback(null, stats);
}
}
@ -1734,7 +1735,7 @@ function readFile(fs, context, path, options, callback) {
return callback(err);
}
var stats = new Stats(fstatResult, fs.name);
var stats = new Stats(ofd.path, fstatResult, fs.name);
if(stats.isDirectory()) {
cleanup();
@ -2009,31 +2010,20 @@ function rename(fs, context, oldpath, newpath, callback) {
var ctime = Date.now();
var fileNode;
function update_times(error) {
function update_times(error, result) {
if(error) {
callback(error);
} else {
fileNode = result;
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) {
if(error) {
callback(error);
} 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) {
callback(error);
} else {
var stats = new Stats(result, fs.name);
var stats = new Stats(path, result, fs.name);
callback(null, stats);
}
}

View File

@ -8,9 +8,25 @@ var NODE_TYPE_META = require('./constants.js').NODE_TYPE_META;
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
function pathToName(pathName) {
return pathName === ROOT_DIRECTORY_NAME ? ROOT_DIRECTORY_NAME : path.basename(pathName);
var S_IFREG = require('./constants.js').S_IFREG;
var S_IFDIR = require('./constants.js').S_IFDIR;
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) {
@ -18,7 +34,6 @@ function Node(options) {
this.id = options.id;
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.atime = options.atime || now; // access time (will mirror ctime after creation)
this.ctime = options.ctime || now; // creation/change time
@ -30,16 +45,11 @@ function Node(options) {
this.version = options.version || 1;
// 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.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,
// either from caller or one we generate using supplied guid fn.
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;

View File

@ -1,6 +1,7 @@
var Constants = require('./constants.js');
var Path = require('./path.js');
function Stats(fileNode, devName) {
function Stats(path, fileNode, devName) {
this.dev = devName;
this.node = fileNode.id;
this.type = fileNode.type;
@ -14,6 +15,7 @@ function Stats(fileNode, devName) {
this.mode = fileNode.mode;
this.uid = fileNode.uid;
this.gid = fileNode.gid;
this.name = Path.basename(path);
}
Stats.prototype.isFile = function() {

View File

@ -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) {
var fs = util.fs();