Update Filer for things needed for Plan 9 sharing
This commit is contained in:
parent
b026537f09
commit
2e627cfe5b
|
@ -76,5 +76,43 @@ 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
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,7 +7,23 @@ 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
|
||||
decode: decode,
|
||||
hash32: hash32
|
||||
};
|
||||
|
|
|
@ -12,6 +12,9 @@ var MODE_FILE = Constants.MODE_FILE;
|
|||
var MODE_DIRECTORY = Constants.MODE_DIRECTORY;
|
||||
var MODE_SYMBOLIC_LINK = Constants.MODE_SYMBOLIC_LINK;
|
||||
var MODE_META = Constants.MODE_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;
|
||||
|
@ -44,6 +47,15 @@ var Buffer = require('../buffer.js');
|
|||
* and filesystem flags are examined in order to override update logic.
|
||||
*/
|
||||
function update_node_times(context, path, node, times, callback) {
|
||||
var update = 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...
|
||||
node.p9.qid.version = times.ctime || times.mtime;
|
||||
update = true;
|
||||
}
|
||||
|
||||
// Honour mount flags for how we update times
|
||||
var flags = context.flags;
|
||||
if(_(flags).contains(FS_NOCTIME)) {
|
||||
|
@ -53,8 +65,6 @@ function update_node_times(context, path, node, times, callback) {
|
|||
delete times.mtime;
|
||||
}
|
||||
|
||||
// Only do the update if required (i.e., times are still present)
|
||||
var update = false;
|
||||
if(times.ctime) {
|
||||
node.ctime = times.ctime;
|
||||
// We don't do atime tracking for perf reasons, but do mirror ctime
|
||||
|
@ -69,6 +79,8 @@ function update_node_times(context, path, node, times, callback) {
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -133,7 +145,11 @@ function make_node(context, path, mode, callback) {
|
|||
callback(error);
|
||||
} else {
|
||||
parentNodeData = result;
|
||||
Node.create({guid: context.guid, mode: mode}, function(error, result) {
|
||||
Node.create({
|
||||
path: path,
|
||||
guid: context.guid,
|
||||
mode: mode
|
||||
}, function(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
return;
|
||||
|
@ -311,7 +327,7 @@ function ensure_root_directory(context, callback) {
|
|||
} else if(error && !(error instanceof Errors.ENOENT)) {
|
||||
callback(error);
|
||||
} else {
|
||||
SuperNode.create({guid: context.guid}, function(error, result) {
|
||||
SuperNode.create({ guid: context.guid }, function(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
return;
|
||||
|
@ -326,7 +342,12 @@ function ensure_root_directory(context, callback) {
|
|||
if(error) {
|
||||
callback(error);
|
||||
} else {
|
||||
Node.create({guid: context.guid, id: superNode.rnode, mode: MODE_DIRECTORY}, function(error, result) {
|
||||
Node.create({
|
||||
guid: context.guid,
|
||||
id: superNode.rnode,
|
||||
mode: MODE_DIRECTORY,
|
||||
path: ROOT_DIRECTORY_NAME
|
||||
}, function(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
return;
|
||||
|
@ -387,7 +408,11 @@ function make_directory(context, path, callback) {
|
|||
callback(error);
|
||||
} else {
|
||||
parentDirectoryData = result;
|
||||
Node.create({guid: context.guid, mode: MODE_DIRECTORY}, function(error, result) {
|
||||
Node.create({
|
||||
guid: context.guid,
|
||||
mode: MODE_DIRECTORY,
|
||||
path: path
|
||||
}, function(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
return;
|
||||
|
@ -624,7 +649,11 @@ function open_file(context, path, flags, callback) {
|
|||
}
|
||||
|
||||
function write_file_node() {
|
||||
Node.create({guid: context.guid, mode: MODE_FILE}, function(error, result) {
|
||||
Node.create({
|
||||
guid: context.guid,
|
||||
mode: MODE_FILE,
|
||||
path: path
|
||||
}, function(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
return;
|
||||
|
@ -1111,7 +1140,11 @@ function make_symbolic_link(context, srcpath, dstpath, callback) {
|
|||
}
|
||||
|
||||
function write_file_node() {
|
||||
Node.create({guid: context.guid, mode: MODE_SYMBOLIC_LINK}, function(error, result) {
|
||||
Node.create({
|
||||
guid: context.guid,
|
||||
mode: MODE_SYMBOLIC_LINK,
|
||||
path: dstpath
|
||||
}, function(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
return;
|
||||
|
|
80
src/node.js
80
src/node.js
|
@ -1,4 +1,46 @@
|
|||
var path = require('./path.js');
|
||||
var hash32 = require('./encoding.js').hash32;
|
||||
|
||||
var MODE_FILE = require('./constants.js').MODE_FILE;
|
||||
var MODE_DIRECTORY = require('./constants.js').MODE_DIRECTORY;
|
||||
var MODE_SYMBOLIC_LINK = require('./constants.js').MODE_SYMBOLIC_LINK;
|
||||
var MODE_META = require('./constants.js').MODE_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(mode) {
|
||||
switch(mode) {
|
||||
case MODE_FILE:
|
||||
return P9_QTFILE;
|
||||
case MODE_DIRECTORY:
|
||||
return P9_QTDIR;
|
||||
case MODE_SYMBOLIC_LINK:
|
||||
return P9_QTSYMLINK;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function getPOSIXMode(mode) {
|
||||
switch(mode) {
|
||||
case MODE_FILE:
|
||||
return S_IFREG;
|
||||
case MODE_DIRECTORY:
|
||||
return S_IFDIR;
|
||||
case MODE_SYMBOLIC_LINK:
|
||||
return S_IFLNK;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function Node(options) {
|
||||
var now = Date.now();
|
||||
|
@ -16,6 +58,44 @@ function Node(options) {
|
|||
this.blksize = undefined; // block size
|
||||
this.nblocks = 1; // blocks 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.p9 = {
|
||||
qid: {
|
||||
type: getQType(this.mode) || P9_QTFILE,
|
||||
// use mtime for version info, since we already keep that updated
|
||||
version: 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)
|
||||
},
|
||||
// permissions and flags
|
||||
// TODO: I don't think I'm doing this correctly yet...
|
||||
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
|
||||
};
|
||||
|
||||
console.log('Node', this);
|
||||
}
|
||||
|
||||
// Make sure the options object has an id on property,
|
||||
|
|
Loading…
Reference in New Issue