2018-05-15 17:33:45 +00:00
|
|
|
|
var path = require('./path.js');
|
|
|
|
|
var hash32 = require('./encoding.js').hash32;
|
|
|
|
|
|
2018-05-24 18:15:09 +00:00
|
|
|
|
var NODE_TYPE_FILE = require('./constants.js').NODE_TYPE_FILE;
|
|
|
|
|
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;
|
2018-05-15 17:33:45 +00:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
2018-05-24 18:32:27 +00:00
|
|
|
|
function getQType(type) {
|
|
|
|
|
switch(type) {
|
2018-05-24 18:15:09 +00:00
|
|
|
|
case NODE_TYPE_FILE:
|
2018-05-15 17:33:45 +00:00
|
|
|
|
return P9_QTFILE;
|
2018-05-24 18:15:09 +00:00
|
|
|
|
case NODE_TYPE_DIRECTORY:
|
2018-05-15 17:33:45 +00:00
|
|
|
|
return P9_QTDIR;
|
2018-05-24 18:15:09 +00:00
|
|
|
|
case NODE_TYPE_SYMBOLIC_LINK:
|
2018-05-15 17:33:45 +00:00
|
|
|
|
return P9_QTSYMLINK;
|
|
|
|
|
default:
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-24 18:32:27 +00:00
|
|
|
|
function getPOSIXMode(type) {
|
|
|
|
|
switch(type) {
|
2018-05-24 18:15:09 +00:00
|
|
|
|
case NODE_TYPE_FILE:
|
2018-05-15 17:33:45 +00:00
|
|
|
|
return S_IFREG;
|
2018-05-24 18:15:09 +00:00
|
|
|
|
case NODE_TYPE_DIRECTORY:
|
2018-05-15 17:33:45 +00:00
|
|
|
|
return S_IFDIR;
|
2018-05-24 18:15:09 +00:00
|
|
|
|
case NODE_TYPE_SYMBOLIC_LINK:
|
2018-05-15 17:33:45 +00:00
|
|
|
|
return S_IFLNK;
|
|
|
|
|
default:
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-03-18 16:29:20 +00:00
|
|
|
|
|
2014-06-02 20:44:20 +00:00
|
|
|
|
function Node(options) {
|
2014-05-23 18:14:06 +00:00
|
|
|
|
var now = Date.now();
|
2014-03-18 16:29:20 +00:00
|
|
|
|
|
2014-06-02 20:44:20 +00:00
|
|
|
|
this.id = options.id;
|
2018-05-24 18:32:27 +00:00
|
|
|
|
this.type = options.type || NODE_TYPE_FILE; // node type (file, directory, etc)
|
2014-06-02 20:44:20 +00:00
|
|
|
|
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
|
|
|
|
|
this.mtime = options.mtime || now; // modified time
|
|
|
|
|
this.flags = options.flags || []; // file flags
|
|
|
|
|
this.xattrs = options.xattrs || {}; // extended attributes
|
|
|
|
|
this.nlinks = options.nlinks || 0; // links count
|
|
|
|
|
this.version = options.version || 0; // node version
|
2014-05-23 18:14:06 +00:00
|
|
|
|
this.blksize = undefined; // block size
|
|
|
|
|
this.nblocks = 1; // blocks count
|
2014-06-02 20:44:20 +00:00
|
|
|
|
this.data = options.data; // id for data object
|
2018-05-15 17:33:45 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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."
|
|
|
|
|
*/
|
2018-05-22 18:16:20 +00:00
|
|
|
|
|
|
|
|
|
options.p9 = options.p9 || {qid: {}};
|
|
|
|
|
|
2018-05-15 17:33:45 +00:00
|
|
|
|
this.p9 = {
|
|
|
|
|
qid: {
|
2018-05-24 18:32:27 +00:00
|
|
|
|
type: options.p9.qid.type || (getQType(this.type) || P9_QTFILE),
|
2018-05-15 17:33:45 +00:00
|
|
|
|
// use mtime for version info, since we already keep that updated
|
2018-05-22 18:16:20 +00:00
|
|
|
|
version: options.p9.qid.now || now,
|
2018-05-15 17:33:45 +00:00
|
|
|
|
// files have a unique `path` number, which takes into account files with same
|
|
|
|
|
// name but created at different times.
|
2018-05-22 18:16:20 +00:00
|
|
|
|
path: options.p9.qid.path || hash32(options.path + this.ctime)
|
2018-05-15 17:33:45 +00:00
|
|
|
|
},
|
|
|
|
|
// permissions and flags
|
|
|
|
|
// TODO: I don't think I'm doing this correctly yet...
|
2018-05-24 18:32:27 +00:00
|
|
|
|
mode: options.p9.mode || (getPOSIXMode(this.type) || S_IFREG),
|
2018-05-15 17:33:45 +00:00
|
|
|
|
// 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?
|
2018-05-22 18:16:20 +00:00
|
|
|
|
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
|
2018-05-15 17:33:45 +00:00
|
|
|
|
};
|
2014-06-02 20:44:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-05-22 18:16:20 +00:00
|
|
|
|
// 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);
|
|
|
|
|
};
|
|
|
|
|
|
2014-06-02 20:44:20 +00:00
|
|
|
|
// 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) {
|
|
|
|
|
if(options[prop]) {
|
|
|
|
|
callback(null);
|
|
|
|
|
} else {
|
|
|
|
|
options.guid(function(err, id) {
|
|
|
|
|
options[prop] = id;
|
|
|
|
|
callback(err);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Node.create = function(options, callback) {
|
|
|
|
|
// We expect both options.id and options.data to be provided/generated.
|
|
|
|
|
ensureID(options, 'id', function(err) {
|
|
|
|
|
if(err) {
|
|
|
|
|
callback(err);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ensureID(options, 'data', function(err) {
|
|
|
|
|
if(err) {
|
|
|
|
|
callback(err);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
callback(null, new Node(options));
|
|
|
|
|
});
|
|
|
|
|
});
|
2014-05-23 18:14:06 +00:00
|
|
|
|
};
|
2014-06-02 20:44:20 +00:00
|
|
|
|
|
2018-05-22 18:16:20 +00:00
|
|
|
|
Node.fromObject = function(object) {
|
|
|
|
|
return new Node({
|
|
|
|
|
id: object.id,
|
2018-05-24 18:32:27 +00:00
|
|
|
|
type: object.type,
|
2018-05-22 18:16:20 +00:00
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2014-06-02 20:44:20 +00:00
|
|
|
|
module.exports = Node;
|