Update sh.ls and stats to remove bits I don't need, add what I do.
This commit is contained in:
parent
ee412d4abe
commit
0aaaeacd1a
34
README.md
34
README.md
|
@ -397,14 +397,19 @@ Callback gets `(error, stats)`, where `stats` is an object with the following pr
|
||||||
|
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
node: <string> // internal node id (unique)
|
node: <string> // internal node id (unique)
|
||||||
dev: <string> // file system name
|
dev: <string> // file system name
|
||||||
size: <number> // file size in bytes
|
name: <string> // the entry's name (basename)
|
||||||
nlinks: <number> // number of links
|
size: <number> // file size in bytes
|
||||||
atime: <number> // last access time
|
nlinks: <number> // number of links
|
||||||
mtime: <number> // last modified time
|
atime: <number> // last access time
|
||||||
ctime: <number> // creation time
|
mtime: <number> // last modified time
|
||||||
type: <string> // file type (FILE, DIRECTORY, SYMLINK)
|
ctime: <number> // creation time
|
||||||
|
type: <string> // file type (FILE, DIRECTORY, SYMLINK),
|
||||||
|
gid: <number> // group name
|
||||||
|
uid: <number> // owner name
|
||||||
|
mode: <number> // permissions
|
||||||
|
version: <number> // version of the node
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1263,17 +1268,8 @@ sh.find('/app/user', {
|
||||||
#### sh.ls(dir, [options], callback)<a name="ls"></a>
|
#### sh.ls(dir, [options], callback)<a name="ls"></a>
|
||||||
|
|
||||||
Get the listing of a directory, returning an array of directory entries
|
Get the listing of a directory, returning an array of directory entries
|
||||||
in the following form:
|
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.
|
||||||
{
|
|
||||||
path: <String> the basename of the directory entry
|
|
||||||
links: <Number> the number of links to the entry
|
|
||||||
size: <Number> the size in bytes of the entry
|
|
||||||
modified: <Number> the last modified date/time
|
|
||||||
type: <String> the type of the entry
|
|
||||||
contents: <Array> an optional array of child entries, if this entry is itself a directory
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
By default `sh.ls()` gives a shallow listing. If you want to follow
|
By default `sh.ls()` gives a shallow listing. If you want to follow
|
||||||
directories as they are encountered, use the `recursive=true` option. NOTE:
|
directories as they are encountered, use the `recursive=true` option. NOTE:
|
||||||
|
|
|
@ -76,43 +76,5 @@ module.exports = {
|
||||||
ENVIRONMENT: {
|
ENVIRONMENT: {
|
||||||
TMP: '/tmp',
|
TMP: '/tmp',
|
||||||
PATH: ''
|
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
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,23 +7,7 @@ function encode(string) {
|
||||||
return new Buffer(string, 'utf8');
|
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 = {
|
module.exports = {
|
||||||
encode: encode,
|
encode: encode,
|
||||||
decode: decode,
|
decode: decode
|
||||||
hash32: hash32
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,9 +12,6 @@ var NODE_TYPE_FILE = Constants.NODE_TYPE_FILE;
|
||||||
var NODE_TYPE_DIRECTORY = Constants.NODE_TYPE_DIRECTORY;
|
var NODE_TYPE_DIRECTORY = Constants.NODE_TYPE_DIRECTORY;
|
||||||
var NODE_TYPE_SYMBOLIC_LINK = Constants.NODE_TYPE_SYMBOLIC_LINK;
|
var NODE_TYPE_SYMBOLIC_LINK = Constants.NODE_TYPE_SYMBOLIC_LINK;
|
||||||
var NODE_TYPE_META = Constants.NODE_TYPE_META;
|
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 ROOT_DIRECTORY_NAME = Constants.ROOT_DIRECTORY_NAME;
|
||||||
var SUPER_NODE_ID = Constants.SUPER_NODE_ID;
|
var SUPER_NODE_ID = Constants.SUPER_NODE_ID;
|
||||||
|
@ -729,7 +726,7 @@ function replace_data(context, ofd, buffer, offset, length, callback) {
|
||||||
ofd.position = length;
|
ofd.position = length;
|
||||||
|
|
||||||
fileNode.size = length;
|
fileNode.size = length;
|
||||||
fileNode.qid_version += 1;
|
fileNode.version += 1;
|
||||||
|
|
||||||
context.putBuffer(fileNode.data, newData, update_file_node);
|
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.size = newSize;
|
||||||
fileNode.qid_version += 1;
|
fileNode.version += 1;
|
||||||
|
|
||||||
context.putBuffer(fileNode.data, newData, update_file_node);
|
context.putBuffer(fileNode.data, newData, update_file_node);
|
||||||
}
|
}
|
||||||
|
@ -1258,7 +1255,7 @@ function truncate_file(context, path, length, callback) {
|
||||||
callback(error);
|
callback(error);
|
||||||
} else {
|
} else {
|
||||||
fileNode.size = length;
|
fileNode.size = length;
|
||||||
fileNode.qid_version += 1;
|
fileNode.version += 1;
|
||||||
context.putObject(fileNode.id, fileNode, update_time);
|
context.putObject(fileNode.id, fileNode, update_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1316,7 +1313,7 @@ function ftruncate_file(context, ofd, length, callback) {
|
||||||
callback(error);
|
callback(error);
|
||||||
} else {
|
} else {
|
||||||
fileNode.size = length;
|
fileNode.size = length;
|
||||||
fileNode.qid_version += 1;
|
fileNode.version += 1;
|
||||||
context.putObject(fileNode.id, fileNode, update_time);
|
context.putObject(fileNode.id, fileNode, update_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
48
src/node.js
48
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_SYMBOLIC_LINK = require('./constants.js').NODE_TYPE_SYMBOLIC_LINK;
|
||||||
var NODE_TYPE_META = require('./constants.js').NODE_TYPE_META;
|
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;
|
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
|
// Name of file/dir. Must be '/' if the file is the root directory of the server
|
||||||
function pathToName(pathName) {
|
function pathToName(pathName) {
|
||||||
return pathName === ROOT_DIRECTORY_NAME ? ROOT_DIRECTORY_NAME : path.basename(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.xattrs = options.xattrs || {}; // extended attributes
|
||||||
this.nlinks = options.nlinks || 0; // links count
|
this.nlinks = options.nlinks || 0; // links count
|
||||||
this.data = options.data; // id for data object
|
this.data = options.data; // id for data object
|
||||||
|
this.version = options.version || 1;
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
// permissions and flags
|
// permissions and flags
|
||||||
this.mode = options.mode || (this.type === NODE_TYPE_DIRECTORY ? /* 755 */ 493 : /* 644 */ 420);
|
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.
|
// When the node's path changes, update info that relates to it.
|
||||||
Node.prototype.updatePathInfo = function(newPath) {
|
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);
|
this.name = pathToName(newPath);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -130,9 +88,7 @@ Node.fromObject = function(object) {
|
||||||
mode: object.mode,
|
mode: object.mode,
|
||||||
uid: object.uid,
|
uid: object.uid,
|
||||||
gid: object.gid,
|
gid: object.gid,
|
||||||
qid_type: object.qid_type,
|
version: object.version
|
||||||
qid_version: object.qid_version,
|
|
||||||
qid_path: object.qid_path
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -233,18 +233,10 @@ Shell.prototype.ls = function(dir, options, callback) {
|
||||||
callback(error);
|
callback(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var entry = {
|
var entry = stats;
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
if(options.recursive && stats.type === 'DIRECTORY') {
|
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) {
|
if(error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
return;
|
return;
|
||||||
|
|
11
src/stats.js
11
src/stats.js
|
@ -1,16 +1,19 @@
|
||||||
var Constants = require('./constants.js');
|
var Constants = require('./constants.js');
|
||||||
|
|
||||||
function Stats(fileNode, devName) {
|
function Stats(fileNode, devName) {
|
||||||
this.node = fileNode.id;
|
|
||||||
this.dev = devName;
|
this.dev = devName;
|
||||||
|
this.node = fileNode.id;
|
||||||
|
this.type = fileNode.type;
|
||||||
|
this.name = fileNode.name;
|
||||||
this.size = fileNode.size;
|
this.size = fileNode.size;
|
||||||
this.nlinks = fileNode.nlinks;
|
this.nlinks = fileNode.nlinks;
|
||||||
this.atime = fileNode.atime;
|
this.atime = fileNode.atime;
|
||||||
this.mtime = fileNode.mtime;
|
this.mtime = fileNode.mtime;
|
||||||
this.ctime = fileNode.ctime;
|
this.ctime = fileNode.ctime;
|
||||||
this.type = fileNode.type;
|
this.version = fileNode.version;
|
||||||
// Expose extra Plan 9 bits too
|
this.mode = fileNode.mode;
|
||||||
this.p9 = fileNode.p9;
|
this.uid = fileNode.uid;
|
||||||
|
this.gid = fileNode.gid;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stats.prototype.isFile = function() {
|
Stats.prototype.isFile = function() {
|
||||||
|
|
|
@ -40,18 +40,18 @@ describe('FileSystemShell.ls', function() {
|
||||||
expect(list.length).to.equal(2);
|
expect(list.length).to.equal(2);
|
||||||
|
|
||||||
var item0 = list[0];
|
var item0 = list[0];
|
||||||
expect(item0.path).to.equal('file');
|
expect(item0.name).to.equal('file');
|
||||||
expect(item0.links).to.equal(1);
|
expect(item0.nlinks).to.equal(1);
|
||||||
expect(item0.size).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.type).to.equal('FILE');
|
||||||
expect(item0.contents).not.to.exist;
|
expect(item0.contents).not.to.exist;
|
||||||
|
|
||||||
var item1 = list[1];
|
var item1 = list[1];
|
||||||
expect(item1.path).to.equal('file2');
|
expect(item1.name).to.equal('file2');
|
||||||
expect(item1.links).to.equal(1);
|
expect(item1.nlinks).to.equal(1);
|
||||||
expect(item1.size).to.equal(2);
|
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(item1.type).to.equal('FILE');
|
||||||
expect(item0.contents).not.to.exist;
|
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
|
// We shouldn't rely on the order we'll get the listing
|
||||||
list.forEach(function(item, i, arr) {
|
list.forEach(function(item, i, arr) {
|
||||||
switch(item.path) {
|
switch(item.name) {
|
||||||
case 'dir2':
|
case 'dir2':
|
||||||
expect(item.links).to.equal(1);
|
expect(item.nlinks).to.equal(1);
|
||||||
expect(item.size).to.be.a('number');
|
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.type).to.equal('DIRECTORY');
|
||||||
expect(item.contents).not.to.exist;
|
expect(item.contents).not.to.exist;
|
||||||
break;
|
break;
|
||||||
case 'file':
|
case 'file':
|
||||||
case 'file2':
|
case 'file2':
|
||||||
expect(item.links).to.equal(1);
|
expect(item.nlinks).to.equal(1);
|
||||||
expect(item.size).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.type).to.equal('FILE');
|
||||||
expect(item.contents).not.to.exist;
|
expect(item.contents).not.to.exist;
|
||||||
break;
|
break;
|
||||||
|
@ -143,27 +143,27 @@ describe('FileSystemShell.ls', function() {
|
||||||
|
|
||||||
// We shouldn't rely on the order we'll get the listing
|
// We shouldn't rely on the order we'll get the listing
|
||||||
list.forEach(function(item, i, arr) {
|
list.forEach(function(item, i, arr) {
|
||||||
switch(item.path) {
|
switch(item.name) {
|
||||||
case 'dir2':
|
case 'dir2':
|
||||||
expect(item.links).to.equal(1);
|
expect(item.nlinks).to.equal(1);
|
||||||
expect(item.size).to.be.a('number');
|
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.type).to.equal('DIRECTORY');
|
||||||
expect(item.contents).to.exist;
|
expect(item.contents).to.exist;
|
||||||
expect(item.contents.length).to.equal(1);
|
expect(item.contents.length).to.equal(1);
|
||||||
var contents0 = item.contents[0];
|
var contents0 = item.contents[0];
|
||||||
expect(contents0.path).to.equal('file');
|
expect(contents0.name).to.equal('file');
|
||||||
expect(contents0.links).to.equal(1);
|
expect(contents0.nlinks).to.equal(1);
|
||||||
expect(contents0.size).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.type).to.equal('FILE');
|
||||||
expect(contents0.contents).not.to.exist;
|
expect(contents0.contents).not.to.exist;
|
||||||
break;
|
break;
|
||||||
case 'file':
|
case 'file':
|
||||||
case 'file2':
|
case 'file2':
|
||||||
expect(item.links).to.equal(1);
|
expect(item.nlinks).to.equal(1);
|
||||||
expect(item.size).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.type).to.equal('FILE');
|
||||||
expect(item.contents).not.to.exist;
|
expect(item.contents).not.to.exist;
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue