From c526445a4358f74865f7bcbdcf0a43514940bf4d Mon Sep 17 00:00:00 2001 From: David Humphrey Date: Sat, 26 May 2018 16:57:57 -0400 Subject: [PATCH] Fix mode, fs.link, fix other bugs and cleanup --- src/constants.js | 7 +++++ src/filesystem/implementation.js | 36 +++++++++-------------- src/node.js | 50 +++++++++++++------------------- src/stats.js | 4 ++- tests/spec/fs.link.spec.js | 24 +++++++++++++++ 5 files changed, 67 insertions(+), 54 deletions(-) diff --git a/src/constants.js b/src/constants.js index b3abb04..c7534ac 100644 --- a/src/constants.js +++ b/src/constants.js @@ -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', diff --git a/src/filesystem/implementation.js b/src/filesystem/implementation.js index b5d1521..794760f 100644 --- a/src/filesystem/implementation.js +++ b/src/filesystem/implementation.js @@ -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); } } diff --git a/src/node.js b/src/node.js index 8164daf..fb80959 100644 --- a/src/node.js +++ b/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; -// 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; diff --git a/src/stats.js b/src/stats.js index d74698c..11b7d4d 100644 --- a/src/stats.js +++ b/src/stats.js @@ -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() { diff --git a/tests/spec/fs.link.spec.js b/tests/spec/fs.link.spec.js index e1c8e1a..6c61082 100644 --- a/tests/spec/fs.link.spec.js +++ b/tests/spec/fs.link.spec.js @@ -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();