diff --git a/README.md b/README.md index c671374..f300ac3 100644 --- a/README.md +++ b/README.md @@ -397,14 +397,19 @@ Callback gets `(error, stats)`, where `stats` is an object with the following pr ``` { - node: // internal node id (unique) - dev: // file system name - size: // file size in bytes - nlinks: // number of links - atime: // last access time - mtime: // last modified time - ctime: // creation time - type: // file type (FILE, DIRECTORY, SYMLINK) + node: // internal node id (unique) + dev: // file system name + name: // the entry's name (basename) + size: // file size in bytes + nlinks: // number of links + atime: // last access time + mtime: // last modified time + ctime: // creation time + type: // file type (FILE, DIRECTORY, SYMLINK), + gid: // group name + uid: // owner name + mode: // permissions + version: // version of the node } ``` @@ -1263,17 +1268,8 @@ sh.find('/app/user', { #### sh.ls(dir, [options], callback) Get the listing of a directory, returning an array of directory entries -in the following form: -``` -{ - path: the basename of the directory entry - links: the number of links to the entry - size: the size in bytes of the entry - modified: the last modified date/time - type: the type of the entry - contents: an optional array of child entries, if this entry is itself a directory -} -``` +in the same form as [fs.stat()](#stat), with the exception that a new Array named +`contents` is added for directory entries, containing child entries. By default `sh.ls()` gives a shallow listing. If you want to follow directories as they are encountered, use the `recursive=true` option. NOTE: diff --git a/src/constants.js b/src/constants.js index 3c27355..b3abb04 100644 --- a/src/constants.js +++ b/src/constants.js @@ -76,43 +76,5 @@ module.exports = { ENVIRONMENT: { TMP: '/tmp', PATH: '' - }, - - /** - * Plan 9 related - * - https://github.com/chaos/diod/blob/master/libnpfs/9p.h - * - https://en.wikibooks.org/wiki/C_Programming/POSIX_Reference/sys/stat.h - */ - P9: { - /** - * QID types - * - * @P9_QTDIR: directory - * @P9_QTAPPEND: append-only - * @P9_QTEXCL: excluse use (only one open handle allowed) - * @P9_QTMOUNT: mount points - * @P9_QTAUTH: authentication file - * @P9_QTTMP: non-backed-up files - * @P9_QTSYMLINK: symbolic links (9P2000.u) - * @P9_QTLINK: hard-link (9P2000.u) - * @P9_QTFILE: normal files - */ - QTDIR: 0x80, - QTAPPEND: 0x40, - QTEXCL: 0x20, - QTMOUNT: 0x10, - QTAUTH: 0x08, - QTTMP: 0x04, - QTSYMLINK: 0x02, - QTLINK: 0x01, - QTFILE: 0x00, - - /** - * POSIX System Values - */ - S_IFMT: 0xF000, // mask for file type - S_IFLNK: 0xA000, // symbolic link - S_IFDIR: 0x4000, // directory - S_IFREG: 0x8000 // regular file } }; diff --git a/src/encoding.js b/src/encoding.js index bd6189b..b3f1031 100644 --- a/src/encoding.js +++ b/src/encoding.js @@ -7,23 +7,7 @@ function encode(string) { return new Buffer(string, 'utf8'); } -// https://github.com/darkskyapp/string-hash -function hash32(string) { - var hash = 5381; - var i = string.length; - - while(i) { - hash = (hash * 33) ^ string.charCodeAt(--i); - } - - /* JavaScript does bitwise operations (like XOR, above) on 32-bit signed - * integers. Since we want the results to be always positive, convert the - * signed int to an unsigned by doing an unsigned bitshift. */ - return hash >>> 0; -} - module.exports = { encode: encode, - decode: decode, - hash32: hash32 + decode: decode }; diff --git a/src/filesystem/implementation.js b/src/filesystem/implementation.js index d6c2121..b5d1521 100644 --- a/src/filesystem/implementation.js +++ b/src/filesystem/implementation.js @@ -12,9 +12,6 @@ var NODE_TYPE_FILE = Constants.NODE_TYPE_FILE; var NODE_TYPE_DIRECTORY = Constants.NODE_TYPE_DIRECTORY; var NODE_TYPE_SYMBOLIC_LINK = Constants.NODE_TYPE_SYMBOLIC_LINK; var NODE_TYPE_META = Constants.NODE_TYPE_META; -var P9_QTDIR = Constants.P9.QTDIR; -var P9_QTFILE = Constants.P9.QTFILE; -var P9_QTSYMLINK = Constants.P9.QTSYMLINK; var ROOT_DIRECTORY_NAME = Constants.ROOT_DIRECTORY_NAME; var SUPER_NODE_ID = Constants.SUPER_NODE_ID; @@ -729,7 +726,7 @@ function replace_data(context, ofd, buffer, offset, length, callback) { ofd.position = length; fileNode.size = length; - fileNode.qid_version += 1; + fileNode.version += 1; context.putBuffer(fileNode.data, newData, update_file_node); } @@ -788,7 +785,7 @@ function write_data(context, ofd, buffer, offset, length, position, callback) { } fileNode.size = newSize; - fileNode.qid_version += 1; + fileNode.version += 1; context.putBuffer(fileNode.data, newData, update_file_node); } @@ -1258,7 +1255,7 @@ function truncate_file(context, path, length, callback) { callback(error); } else { fileNode.size = length; - fileNode.qid_version += 1; + fileNode.version += 1; context.putObject(fileNode.id, fileNode, update_time); } } @@ -1316,7 +1313,7 @@ function ftruncate_file(context, ofd, length, callback) { callback(error); } else { fileNode.size = length; - fileNode.qid_version += 1; + fileNode.version += 1; context.putObject(fileNode.id, fileNode, update_time); } } diff --git a/src/node.js b/src/node.js index 1d8619a..8164daf 100644 --- a/src/node.js +++ b/src/node.js @@ -6,29 +6,8 @@ var NODE_TYPE_DIRECTORY = require('./constants.js').NODE_TYPE_DIRECTORY; var NODE_TYPE_SYMBOLIC_LINK = require('./constants.js').NODE_TYPE_SYMBOLIC_LINK; var NODE_TYPE_META = require('./constants.js').NODE_TYPE_META; -var P9_QTFILE = require('./constants.js').P9.QTFILE; -var P9_QTDIR = require('./constants.js').P9.QTDIR; -var P9_QTSYMLINK = require('./constants.js').P9.QTSYMLINK; - -var S_IFLNK = require('./constants.js').P9.S_IFLNK; -var S_IFDIR = require('./constants.js').P9.S_IFDIR; -var S_IFREG = require('./constants.js').P9.S_IFREG; - var ROOT_DIRECTORY_NAME = require('./constants.js').ROOT_DIRECTORY_NAME; -function getQType(type) { - switch(type) { - case NODE_TYPE_FILE: - return P9_QTFILE; - case NODE_TYPE_DIRECTORY: - return P9_QTDIR; - case NODE_TYPE_SYMBOLIC_LINK: - return P9_QTSYMLINK; - default: - return P9_QTFILE; - } -} - // 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); @@ -48,26 +27,7 @@ function Node(options) { this.xattrs = options.xattrs || {}; // extended attributes this.nlinks = options.nlinks || 0; // links count this.data = options.data; // id for data object - - /** - * Plan 9 related metadata: - * https://web.archive.org/web/20170601072902/http://plan9.bell-labs.com/magic/man2html/5/0intro - * - * "The qid represents the server's unique identification for the file being - * accessed: two files on the same server hierarchy are the same if and only - * if their qids are the same. (The client may have multiple fids pointing to - * a single file on a server and hence having a single qid.) The thirteen–byte - * qid fields hold a one–byte type, specifying whether the file is a directory, - * append–only file, etc., and two unsigned integers: first the four–byte qid - * version, then the eight–byte qid path. The path is an integer unique among - * all files in the hierarchy. If a file is deleted and recreated with the same - * name in the same directory, the old and new path components of the qids - * should be different. The version is a version number for a file; typically, - * it is incremented every time the file is modified." - */ - this.qid_type = options.qid_type || (getQType(this.type)); - this.qid_version = options.qid_version || 1; - this.qid_path = options.qid_path || hash32(options.path + this.qid_version); + this.version = options.version || 1; // permissions and flags this.mode = options.mode || (this.type === NODE_TYPE_DIRECTORY ? /* 755 */ 493 : /* 644 */ 420); @@ -77,8 +37,6 @@ function Node(options) { // When the node's path changes, update info that relates to it. Node.prototype.updatePathInfo = function(newPath) { - // XXX: need to confirm that qid's path actually changes on rename. - this.qid_path = hash32(newPath + this.qid_version); this.name = pathToName(newPath); }; @@ -130,9 +88,7 @@ Node.fromObject = function(object) { mode: object.mode, uid: object.uid, gid: object.gid, - qid_type: object.qid_type, - qid_version: object.qid_version, - qid_path: object.qid_path + version: object.version }); }; diff --git a/src/shell/shell.js b/src/shell/shell.js index 0d46ebd..92e0c57 100644 --- a/src/shell/shell.js +++ b/src/shell/shell.js @@ -233,18 +233,10 @@ Shell.prototype.ls = function(dir, options, callback) { callback(error); return; } - var entry = { - path: Path.basename(name), - links: stats.nlinks, - size: stats.size, - modified: stats.mtime, - type: stats.type, - // Also expose the Plan 9 bits - p9: stats.p9 - }; + var entry = stats; if(options.recursive && stats.type === 'DIRECTORY') { - list(Path.join(pathname, entry.path), function(error, items) { + list(Path.join(pathname, entry.name), function(error, items) { if(error) { callback(error); return; diff --git a/src/stats.js b/src/stats.js index b83484d..d74698c 100644 --- a/src/stats.js +++ b/src/stats.js @@ -1,16 +1,19 @@ var Constants = require('./constants.js'); function Stats(fileNode, devName) { - this.node = fileNode.id; this.dev = devName; + this.node = fileNode.id; + this.type = fileNode.type; + this.name = fileNode.name; this.size = fileNode.size; this.nlinks = fileNode.nlinks; this.atime = fileNode.atime; this.mtime = fileNode.mtime; this.ctime = fileNode.ctime; - this.type = fileNode.type; - // Expose extra Plan 9 bits too - this.p9 = fileNode.p9; + this.version = fileNode.version; + this.mode = fileNode.mode; + this.uid = fileNode.uid; + this.gid = fileNode.gid; } Stats.prototype.isFile = function() { diff --git a/tests/spec/shell/ls.spec.js b/tests/spec/shell/ls.spec.js index c9a718d..f1e6e84 100644 --- a/tests/spec/shell/ls.spec.js +++ b/tests/spec/shell/ls.spec.js @@ -40,18 +40,18 @@ describe('FileSystemShell.ls', function() { expect(list.length).to.equal(2); var item0 = list[0]; - expect(item0.path).to.equal('file'); - expect(item0.links).to.equal(1); + expect(item0.name).to.equal('file'); + expect(item0.nlinks).to.equal(1); expect(item0.size).to.equal(1); - expect(item0.modified).to.be.a('number'); + expect(item0.mtime).to.be.a('number'); expect(item0.type).to.equal('FILE'); expect(item0.contents).not.to.exist; var item1 = list[1]; - expect(item1.path).to.equal('file2'); - expect(item1.links).to.equal(1); + expect(item1.name).to.equal('file2'); + expect(item1.nlinks).to.equal(1); expect(item1.size).to.equal(2); - expect(item1.modified).to.be.a('number'); + expect(item1.mtime).to.be.a('number'); expect(item1.type).to.equal('FILE'); expect(item0.contents).not.to.exist; @@ -84,19 +84,19 @@ describe('FileSystemShell.ls', function() { // We shouldn't rely on the order we'll get the listing list.forEach(function(item, i, arr) { - switch(item.path) { + switch(item.name) { case 'dir2': - expect(item.links).to.equal(1); + expect(item.nlinks).to.equal(1); expect(item.size).to.be.a('number'); - expect(item.modified).to.be.a('number'); + expect(item.mtime).to.be.a('number'); expect(item.type).to.equal('DIRECTORY'); expect(item.contents).not.to.exist; break; case 'file': case 'file2': - expect(item.links).to.equal(1); + expect(item.nlinks).to.equal(1); expect(item.size).to.equal(1); - expect(item.modified).to.be.a('number'); + expect(item.mtime).to.be.a('number'); expect(item.type).to.equal('FILE'); expect(item.contents).not.to.exist; break; @@ -143,27 +143,27 @@ describe('FileSystemShell.ls', function() { // We shouldn't rely on the order we'll get the listing list.forEach(function(item, i, arr) { - switch(item.path) { + switch(item.name) { case 'dir2': - expect(item.links).to.equal(1); + expect(item.nlinks).to.equal(1); expect(item.size).to.be.a('number'); - expect(item.modified).to.be.a('number'); + expect(item.mtime).to.be.a('number'); expect(item.type).to.equal('DIRECTORY'); expect(item.contents).to.exist; expect(item.contents.length).to.equal(1); var contents0 = item.contents[0]; - expect(contents0.path).to.equal('file'); - expect(contents0.links).to.equal(1); + expect(contents0.name).to.equal('file'); + expect(contents0.nlinks).to.equal(1); expect(contents0.size).to.equal(1); - expect(contents0.modified).to.be.a('number'); + expect(contents0.mtime).to.be.a('number'); expect(contents0.type).to.equal('FILE'); expect(contents0.contents).not.to.exist; break; case 'file': case 'file2': - expect(item.links).to.equal(1); + expect(item.nlinks).to.equal(1); expect(item.size).to.equal(1); - expect(item.modified).to.be.a('number'); + expect(item.mtime).to.be.a('number'); expect(item.type).to.equal('FILE'); expect(item.contents).not.to.exist; break;