From 93633da6228eda83646ba84b4e62dd1ddc1c860b Mon Sep 17 00:00:00 2001 From: David Humphrey Date: Tue, 22 May 2018 14:16:20 -0400 Subject: [PATCH] All basic operations now working in Linux 9P mounted fs --- src/filesystem/implementation.js | 39 ++++++++++++++++------ src/node.js | 55 ++++++++++++++++++++++++++------ src/shell/shell.js | 4 ++- src/stats.js | 2 ++ 4 files changed, 80 insertions(+), 20 deletions(-) diff --git a/src/filesystem/implementation.js b/src/filesystem/implementation.js index 8d5ebda..528264b 100644 --- a/src/filesystem/implementation.js +++ b/src/filesystem/implementation.js @@ -48,10 +48,12 @@ var Buffer = require('../buffer.js'); */ function update_node_times(context, path, node, times, callback) { var update = false; + // If updating the P9 info only, don't send change events (honour flags). + var queueChangeEvent = false; if(times.ctime || times.mtime) { // Update the qid's version field, since node has changed. - // TODO: this might more than I need to do... + // TODO: this might be more than I need to do... node.p9.qid.version = times.ctime || times.mtime; update = true; } @@ -70,24 +72,27 @@ function update_node_times(context, path, node, times, callback) { // We don't do atime tracking for perf reasons, but do mirror ctime node.atime = times.ctime; update = true; + queueChangeEvent = 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; + queueChangeEvent = true; } if(times.mtime) { node.mtime = times.mtime; - // Also update the qid's version filed, since file has changed. - node.p9.qid.version = times.mtime; update = true; + queueChangeEvent = true; } function complete(error) { // Queue this change so we can send watch events. // Unlike node.js, we send the full path vs. basename/dirname only. - context.changes.push({ event: 'change', path: path }); + if(queueChangeEvent) { + context.changes.push({ event: 'change', path: path }); + } callback(error); } @@ -908,6 +913,7 @@ function link_node(context, oldpath, newpath, callback) { newpath = normalize(newpath); var newname = basename(newpath); var newParentPath = dirname(newpath); + var ctime = Date.now(); var oldDirectoryNode; var oldDirectoryData; @@ -919,7 +925,7 @@ function link_node(context, oldpath, newpath, callback) { if(error) { callback(error); } else { - update_node_times(context, newpath, fileNode, { ctime: Date.now() }, callback); + update_node_times(context, newpath, fileNode, { ctime: ctime }, callback); } } @@ -927,8 +933,9 @@ function link_node(context, oldpath, newpath, callback) { if(error) { callback(error); } else { - fileNode = result; + fileNode = Node.fromObject(result); fileNode.nlinks += 1; + fileNode.updatePathInfo(newpath, ctime); context.putObject(fileNode.id, fileNode, update_time); } } @@ -2018,12 +2025,26 @@ function rename(fs, context, oldpath, newpath, callback) { var newName = Path.basename(newpath); var oldParentDirectory, oldParentData; var newParentDirectory, newParentData; + var ctime = Date.now(); + var fileNode; - function update_times(error, newNode) { + function update_times(error) { if(error) { callback(error); } else { - update_node_times(context, newpath, newNode, { ctime: Date.now() }, 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, ctime); + context.putObject(fileNode.id, fileNode, update_times); } } @@ -2031,7 +2052,7 @@ function rename(fs, context, oldpath, newpath, callback) { if(error) { callback(error); } else { - context.getObject(newParentData[newName].id, update_times); + context.getObject(newParentData[newName].id, update_file_node); } } diff --git a/src/node.js b/src/node.js index 3a119a7..1cfc6ff 100644 --- a/src/node.js +++ b/src/node.js @@ -75,29 +75,37 @@ function Node(options) { * should be different. The version is a version number for a file; typically, * it is incremented every time the file is modified." */ + + options.p9 = options.p9 || {qid: {}}; + this.p9 = { qid: { - type: getQType(this.mode) || P9_QTFILE, + type: options.p9.qid.type || (getQType(this.mode) || P9_QTFILE), // use mtime for version info, since we already keep that updated - version: now, + version: options.p9.qid.now || now, // files have a unique `path` number, which takes into account files with same // name but created at different times. - path: hash32(options.path + this.ctime) + path: options.p9.qid.path || hash32(options.path + this.ctime) }, // permissions and flags // TODO: I don't think I'm doing this correctly yet... - mode: getPOSIXMode(this.mode) || S_IFREG, + mode: options.p9.mode || (getPOSIXMode(this.mode) || S_IFREG), // Name of file/dir. Must be / if the file is the root directory of the server // TODO: do I need this or can I derive it from abs path? - name: options.path === ROOT_DIRECTORY_NAME ? ROOT_DIRECTORY_NAME : path.basename(options.path), - uid: 0x0, // owner name - gid: 0x0, // group name - muid: 0x0// name of the user who last modified the file + name: options.p9.name || (options.path === ROOT_DIRECTORY_NAME ? ROOT_DIRECTORY_NAME : path.basename(options.path)), + uid: options.p9.uid || 0x0, // owner name + gid: options.p9.gid || 0x0, // group name + muid: options.p9.muid || 0x0 // name of the user who last modified the file }; - - console.log('Node', this); } +// When the node's path changes, update info that relates to it. +Node.prototype.updatePathInfo = function(newPath, ctime) { + // XXX: need to confirm that qid's path actually changes on rename. + this.p9.qid.path = hash32(newPath + (ctime || this.ctime)); + this.p9.name = newPath === ROOT_DIRECTORY_NAME ? ROOT_DIRECTORY_NAME : path.basename(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) { @@ -130,4 +138,31 @@ Node.create = function(options, callback) { }); }; +Node.fromObject = function(object) { + return new Node({ + id: object.id, + mode: object.mode, + size: object.size, + atime: object.atime, + ctime: object.ctime, + mtime: object.mtime, + flags: object.flags, + xattrs: object.xattrs, + nlinks: object.nlinks, + data: object.data, + p9: { + qid: { + type: object.p9.qid.type, + version: object.p9.qid.version, + path: object.p9.qid.path + }, + mode: object.p9.mode, + name: object.p9.name, + uid: object.p9.uid, + gid: object.p9.gid, + muid: object.p9.muid + } + }); +}; + module.exports = Node; diff --git a/src/shell/shell.js b/src/shell/shell.js index 000fc02..0d46ebd 100644 --- a/src/shell/shell.js +++ b/src/shell/shell.js @@ -238,7 +238,9 @@ Shell.prototype.ls = function(dir, options, callback) { links: stats.nlinks, size: stats.size, modified: stats.mtime, - type: stats.type + type: stats.type, + // Also expose the Plan 9 bits + p9: stats.p9 }; if(options.recursive && stats.type === 'DIRECTORY') { diff --git a/src/stats.js b/src/stats.js index 15e6868..1f5080a 100644 --- a/src/stats.js +++ b/src/stats.js @@ -9,6 +9,8 @@ function Stats(fileNode, devName) { this.mtime = fileNode.mtime; this.ctime = fileNode.ctime; this.type = fileNode.mode; + // Expose extra Plan 9 bits too + this.p9 = fileNode.p9; } Stats.prototype.isFile = function() {