├── .gitignore
├── .gitmodules
├── Makefile
├── README.md
├── examples
├── combo.js
├── mountd.js
├── murmur3.js
└── nfsd.js
├── lib
├── index.js
├── mount
│ ├── client.js
│ ├── dump_reply.js
│ ├── errors.js
│ ├── index.js
│ ├── mnt_call.js
│ ├── mnt_reply.js
│ ├── mount_reply.js
│ ├── server.js
│ ├── umnt_call.js
│ └── umnt_reply.js
└── nfs
│ ├── access_call.js
│ ├── access_reply.js
│ ├── client.js
│ ├── commit_call.js
│ ├── commit_reply.js
│ ├── create_call.js
│ ├── create_reply.js
│ ├── errors.js
│ ├── fattr3.js
│ ├── fs_info_call.js
│ ├── fs_info_reply.js
│ ├── fs_stat_call.js
│ ├── fs_stat_reply.js
│ ├── get_attr_call.js
│ ├── get_attr_reply.js
│ ├── index.js
│ ├── link_call.js
│ ├── link_reply.js
│ ├── lookup_call.js
│ ├── lookup_reply.js
│ ├── mkdir_call.js
│ ├── mkdir_reply.js
│ ├── mknod_call.js
│ ├── mknod_reply.js
│ ├── nfs_call.js
│ ├── nfs_reply.js
│ ├── path_conf_call.js
│ ├── path_conf_reply.js
│ ├── read_call.js
│ ├── read_reply.js
│ ├── readdir_call.js
│ ├── readdir_reply.js
│ ├── readdirplus_call.js
│ ├── readdirplus_reply.js
│ ├── readlink_call.js
│ ├── readlink_reply.js
│ ├── remove_call.js
│ ├── remove_reply.js
│ ├── rename_call.js
│ ├── rename_reply.js
│ ├── rmdir_call.js
│ ├── rmdir_reply.js
│ ├── sattr3.js
│ ├── server.js
│ ├── set_attr_call.js
│ ├── set_attr_reply.js
│ ├── symlink_call.js
│ ├── symlink_reply.js
│ ├── wcc_data.js
│ ├── write_call.js
│ └── write_reply.js
├── package.json
├── smf
└── manifests
│ └── portmap.xml.in
├── test
├── helper.js
├── mount.test.js
└── nfs.test.js
└── tools
├── bashstyle
├── jsl.node.conf
├── jsl.web.conf
├── jsstyle.conf
├── mk
├── Makefile.defs
├── Makefile.deps
├── Makefile.node_deps.defs
├── Makefile.node_deps.targ
├── Makefile.smf.defs
├── Makefile.smf.targ
└── Makefile.targ
├── mkrepo
├── runtests.in
└── service_bundle.dtd.1
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /tmp
3 | build
4 | docs/*.json
5 | docs/*.html
6 | cscope.in.out
7 | cscope.po.out
8 | cscope.out
9 | smf/manifests/*.xml
10 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "deps/jsstyle"]
2 | path = deps/jsstyle
3 | url = https://github.com/joyent/jsstyle.git
4 | [submodule "deps/restdown"]
5 | path = deps/restdown
6 | url = https://github.com/trentm/restdown.git
7 | [submodule "deps/javascriptlint"]
8 | path = deps/javascriptlint
9 | url = https://github.com/davepacheco/javascriptlint.git
10 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2013, Joyent, Inc. All rights reserved.
3 | #
4 |
5 | #
6 | # Tools
7 | #
8 | NODEUNIT := ./node_modules/.bin/nodeunit
9 | NPM := npm
10 |
11 | #
12 | # Files
13 | #
14 | DOC_FILES = index.restdown
15 | JS_FILES := $(shell find lib test -name '*.js')
16 | JSON_FILES = package.json
17 | JSL_CONF_NODE = tools/jsl.node.conf
18 | JSL_FILES_NODE = $(JS_FILES)
19 | JSSTYLE_FILES = $(JS_FILES)
20 | JSSTYLE_FLAGS = -f tools/jsstyle.conf
21 | SMF_MANIFESTS_IN = smf/manifests/portmap.xml.in
22 |
23 | include ./tools/mk/Makefile.defs
24 | include ./tools/mk/Makefile.smf.defs
25 |
26 | #
27 | # Repo-specific targets
28 | #
29 | .PHONY: all
30 | all: $(SMF_MANIFESTS) | $(NODEUNIT) $(REPO_DEPS)
31 | $(NPM) rebuild
32 |
33 | $(NODEUNIT): | $(NPM_EXEC)
34 | $(NPM) install
35 |
36 | CLEAN_FILES += $(NODEUNIT) ./node_modules/nodeunit node_modules
37 |
38 | .PHONY: test
39 | test: $(NODEUNIT)
40 | $(NPM) test
41 |
42 | include ./tools/mk/Makefile.deps
43 | include ./tools/mk/Makefile.smf.targ
44 | include ./tools/mk/Makefile.targ
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # tl;dr
2 |
3 | nfs bindings for node.js
4 |
--------------------------------------------------------------------------------
/examples/mountd.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var fs = require('fs');
8 | var path = require('path');
9 |
10 | var assert = require('assert-plus');
11 | var bunyan = require('bunyan');
12 | var libuuid = require('node-uuid');
13 | var nfs = require('../lib');
14 | var rpc = require('oncrpc');
15 |
16 |
17 |
18 | ///--- Globals
19 |
20 | var MOUNTS = {};
21 |
22 |
23 |
24 | ////--- Private Functions
25 |
26 | function authorize(req, res, next) {
27 | if (!req.user_allowed([0])) {
28 | next(new nfs.MountAccessError('uid 0 required'));
29 | } else {
30 | next();
31 | }
32 | }
33 |
34 |
35 | function check_dirpath(req, res, next) {
36 | assert.string(req.dirpath, 'req.dirpath');
37 |
38 | var p = path.normalize(req.dirpath);
39 | if (p.length > 64) {
40 | next(new nfs.MountNameTooLongError(p + ' > 64 bytes'));
41 | }
42 |
43 | fs.stat(p, function (err, stats) {
44 | if (err) {
45 | if (err.code === 'ENOENT') {
46 | next(new nfs.MountNoEntError(err));
47 | } else if (err.code === 'EACCES') {
48 | req.log.warn({
49 | err: err,
50 | path: p
51 | }, 'unable to read directory');
52 | next(new nfs.MountAccessError(err));
53 | } else {
54 | next(new nfs.MountIOError(err, 'internal error'));
55 | }
56 | } else if (!stats.isDirectory()) {
57 | next(new nfs.MountNotDirError());
58 | } else {
59 | res.setFileHandle(libuuid.v4());
60 | res.writeHead();
61 | res.end();
62 | next();
63 | }
64 | });
65 | }
66 |
67 |
68 |
69 | ///--- Mainline
70 |
71 | (function main() {
72 | var log = bunyan.createLogger({
73 | name: 'mountd',
74 | level: 'info',
75 | src: true,
76 | stream: process.stdout,
77 | serializers: rpc.serializers
78 | });
79 |
80 | var server = nfs.createMountServer({
81 | log: log
82 | });
83 |
84 | server.mnt(authorize, check_dirpath);
85 |
86 | server.on('after', function (name, req, res, err) {
87 | log.info({
88 | rpc_call: req,
89 | rpc_reply: res,
90 | err: err
91 | }, '%s: handled', name);
92 | });
93 |
94 | server.on('uncaughtException', function (req, res, err) {
95 | console.error('ERROR: %s', err.stack);
96 | process.exit(1);
97 | });
98 |
99 | server.start(function () {
100 | console.log('ready');
101 | });
102 | })();
103 |
--------------------------------------------------------------------------------
/examples/murmur3.js:
--------------------------------------------------------------------------------
1 | // This source file copied from
2 | // https://github.com/garycourt/murmurhash-js/blob/master/murmurhash3_gc.js
3 | //
4 | // Copyright (c) 2011 Gary Court
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining
7 | // a copy of this software and associated documentation files (the
8 | // "Software"), to deal in the Software without restriction, including
9 | // without limitation the rights to use, copy, modify, merge, publish,
10 | // distribute, sublicense, and/or sell copies of the Software, and to
11 | // permit persons to whom the Software is furnished to do so, subject to
12 | // the following conditions:
13 | //
14 | // The above copyright notice and this permission notice shall be
15 | // included in all copies or substantial portions of the Software.
16 | //
17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | /**
26 | * JS Implementation of MurmurHash3 (r136) (as of May 20, 2011)
27 | *
28 | * @author Gary Court
29 | * @see http://github.com/garycourt/murmurhash-js
30 | * @author Austin Appleby
31 | * @see http://sites.google.com/site/murmurhash/
32 | *
33 | * @param {string} key ASCII only
34 | * @param {number} seed Positive integer only
35 | * @return {number} 32-bit positive integer hash
36 | */
37 | /*jsl:ignore*/
38 | /* BEGIN JSSTYLED */
39 | function murmurhash3_32_gc(key, seed) {
40 | var remainder, bytes, h1, h1b, c1, c1b, c2, c2b, k1, i;
41 |
42 | remainder = key.length & 3; // key.length % 4
43 | bytes = key.length - remainder;
44 | h1 = seed;
45 | c1 = 0xcc9e2d51;
46 | c2 = 0x1b873593;
47 | i = 0;
48 |
49 | while (i < bytes) {
50 | k1 =
51 | ((key.charCodeAt(i) & 0xff)) |
52 | ((key.charCodeAt(++i) & 0xff) << 8) |
53 | ((key.charCodeAt(++i) & 0xff) << 16) |
54 | ((key.charCodeAt(++i) & 0xff) << 24);
55 | ++i;
56 |
57 | k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff;
58 | k1 = (k1 << 15) | (k1 >>> 17);
59 | k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff;
60 |
61 | h1 ^= k1;
62 | h1 = (h1 << 13) | (h1 >>> 19);
63 | h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff;
64 | h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16));
65 | }
66 |
67 | k1 = 0;
68 |
69 | switch (remainder) {
70 | case 3: k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16;
71 | case 2: k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8;
72 | case 1: k1 ^= (key.charCodeAt(i) & 0xff);
73 |
74 | k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;
75 | k1 = (k1 << 15) | (k1 >>> 17);
76 | k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;
77 | h1 ^= k1;
78 | }
79 |
80 | h1 ^= key.length;
81 |
82 | h1 ^= h1 >>> 16;
83 | h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff;
84 | h1 ^= h1 >>> 13;
85 | h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff;
86 | h1 ^= h1 >>> 16;
87 |
88 | return h1 >>> 0;
89 | }
90 | module.exports = murmurhash3_32_gc;
91 | /* END JSSTYLED */
92 | /*jsl:end*/
93 |
--------------------------------------------------------------------------------
/examples/nfsd.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var bunyan = require('bunyan');
8 | var nfs = require('../lib');
9 | var rpc = require('oncrpc');
10 |
11 |
12 |
13 | (function main() {
14 | var bunyan = require('bunyan');
15 |
16 | var log = bunyan.createLogger({
17 | name: 'nfsd',
18 | level: 'info',
19 | src: true,
20 | stream: process.stdout,
21 | serializers: rpc.serializers
22 | });
23 |
24 | var server = nfs.createNfsServer({
25 | log: log
26 | });
27 |
28 | // server.dump(function dump(req, res, next) {
29 | // res.addMapping({
30 | // name: '/var/tmp',
31 | // dirname: '/var/tmp'
32 | // });
33 | // // res.addMapping({
34 | // // name: 'mount',
35 | // // prog: 100005,
36 | // // vers: 3,
37 | // // prot: 6,
38 | // // port: 1892
39 | // // });
40 | // res.writeHead();
41 | // res.end();
42 | // next();
43 | // });
44 |
45 | server.on('after', function (name, req, res, err) {
46 | log.info({
47 | rpc_call: req,
48 | rpc_reply: res,
49 | err: err
50 | }, '%s: handled', name);
51 | });
52 |
53 | server.start(function () {
54 | log.info('nfsd listening at %j', server.address());
55 | });
56 | })();
57 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 |
8 |
9 | ///--- Helpers
10 |
11 | function _export(obj) {
12 | Object.keys(obj).forEach(function (k) {
13 | module.exports[k] = obj[k];
14 | });
15 | }
16 |
17 |
18 |
19 | ///--- Exports
20 |
21 | module.exports = {};
22 |
23 | _export(require('./mount'));
24 | _export(require('./nfs'));
25 |
--------------------------------------------------------------------------------
/lib/mount/client.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var util = require('util');
8 |
9 | var assert = require('assert-plus');
10 | var clone = require('clone');
11 | var once = require('once');
12 | var rpc = require('oncrpc');
13 |
14 | var MountDumpReply = require('./dump_reply').MountDumpReply;
15 | var MountMntCall = require('./mnt_call').MountMntCall;
16 | var MountMntReply = require('./mnt_reply').MountMntReply;
17 | var MountUmntCall = require('./umnt_call').MountUmntCall;
18 | var MountUmntReply = require('./umnt_reply').MountUmntReply;
19 |
20 |
21 |
22 | ///--- Helpers
23 |
24 | function createCallback(cb) {
25 | cb = once(cb);
26 |
27 | function _callback(err, reply) {
28 | if (err) {
29 | cb(err, reply);
30 | return;
31 | }
32 |
33 | reply.once('error', cb);
34 | reply.once('end', cb.bind(null, null, reply));
35 | reply.resume();
36 | }
37 |
38 | return (_callback);
39 | }
40 |
41 |
42 |
43 | ///--- API
44 |
45 | function MountClient(opts) {
46 | assert.object(opts, 'options');
47 | if (opts.log) {
48 | var l = opts.log;
49 | delete opts.log;
50 | }
51 |
52 | var _opts = clone(opts);
53 | _opts.log = opts.log = l;
54 | _opts.name = 'mount';
55 | _opts.program = 100005;
56 | _opts.version = 3;
57 |
58 | rpc.RpcClient.call(this, _opts);
59 | }
60 | util.inherits(MountClient, rpc.RpcClient);
61 |
62 |
63 | MountClient.prototype.dump = function dump(cb) {
64 | assert.func(cb, 'callback');
65 |
66 | var call = new rpc.RpcCall({
67 | incoming: false,
68 | proc: 2
69 | });
70 |
71 | this._rpc(call, MountDumpReply, createCallback(cb));
72 |
73 | call.end();
74 |
75 | return (this);
76 | };
77 |
78 |
79 | MountClient.prototype.mnt = function mnt(dirpath, cb) {
80 | assert.string(dirpath, 'dirpath');
81 | assert.func(cb, 'callback');
82 |
83 | var call = new MountMntCall({
84 | dirpath: dirpath,
85 | incoming: false,
86 | proc: 1
87 | });
88 |
89 | this._rpc(call, MountMntReply, createCallback(cb));
90 |
91 | call.end();
92 |
93 | return (this);
94 | };
95 |
96 |
97 | MountClient.prototype.umnt = function umnt(dirpath, cb) {
98 | assert.string(dirpath, 'dirpath');
99 | assert.func(cb, 'callback');
100 |
101 | cb = once(cb);
102 |
103 | var call = new MountUmntCall({
104 | dirpath: dirpath,
105 | incoming: false,
106 | proc: 3
107 | });
108 |
109 | this._rpc(call, MountUmntReply, createCallback(cb));
110 |
111 | call.end();
112 |
113 |
114 | return (this);
115 | };
116 |
117 |
118 |
119 | ///--- Exports
120 |
121 | module.exports = {
122 | MountClient: MountClient,
123 | createMountClient: function createMountClient(opts) {
124 | return (new MountClient(opts));
125 | }
126 | };
127 |
--------------------------------------------------------------------------------
/lib/mount/dump_reply.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var path = require('path');
8 | var util = require('util');
9 |
10 | var assert = require('assert-plus');
11 | var clone = require('clone');
12 | var rpc = require('oncrpc');
13 |
14 |
15 |
16 | ///--- Globals
17 | var RpcReply = rpc.RpcReply;
18 | var XDR = rpc.XDR;
19 |
20 |
21 |
22 |
23 | ///--- Helpers
24 |
25 | function calculate_buffer_length(mappings) {
26 | assert.arrayOfObject(mappings, 'mappings');
27 | var sz = 0;
28 | mappings.forEach(function (m) {
29 | sz += 4; // boolean marker
30 | sz += XDR.byteLength(m.name);
31 | sz += XDR.byteLength(m.dirpath);
32 | });
33 | sz += 4; // final boolean marker
34 |
35 | return (sz);
36 | }
37 |
38 |
39 |
40 | ///--- API
41 |
42 | function MountDumpReply(opts) {
43 | RpcReply.call(this, opts);
44 |
45 | this.mappings = [];
46 |
47 | this._nfs_mount_dump_reply = true; // MDB
48 | }
49 | util.inherits(MountDumpReply, RpcReply);
50 |
51 |
52 | MountDumpReply.prototype.addMapping = function addMapping(opts, noClone) {
53 | assert.object(opts);
54 | assert.string(opts.name, 'options.name');
55 | assert.string(opts.dirpath, 'options.dirpath');
56 | assert.optionalBool(noClone, 'noClone');
57 |
58 | this.mappings.push(noClone ? opts : clone(opts));
59 | };
60 |
61 |
62 | MountDumpReply.prototype._transform = function _transform(chunk, enc, cb) {
63 | if (this.incoming) {
64 | var xdr = new XDR(chunk);
65 |
66 | while (xdr.readBool()) {
67 | this.addMapping({
68 | name: xdr.readString(),
69 | dirpath: xdr.readString()
70 | }, true);
71 | }
72 | } else {
73 | this.push(chunk);
74 | }
75 |
76 | cb();
77 | };
78 |
79 |
80 | MountDumpReply.prototype.writeHead = function writeHead() {
81 | var len = calculate_buffer_length(this.mappings);
82 | var xdr = this._serialize(len);
83 |
84 | this.mappings.forEach(function (p) {
85 | xdr.writeBool(true);
86 | xdr.writeString(p.name);
87 | xdr.writeString(p.dirpath);
88 | });
89 | xdr.writeBool(false);
90 |
91 | this.write(xdr.buffer());
92 | };
93 |
94 |
95 | MountDumpReply.prototype.toString = function toString() {
96 | var fmt = '[object MountDumpReply ]';
97 | return (util.format(fmt, this.xid, this.mappings));
98 | };
99 |
100 |
101 |
102 | ///--- Exports
103 |
104 | module.exports = {
105 | MountDumpReply: MountDumpReply
106 | };
107 |
--------------------------------------------------------------------------------
/lib/mount/errors.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var util = require('util');
8 |
9 | var assert = require('assert-plus');
10 | var rpc = require('oncrpc');
11 |
12 |
13 |
14 | ///--- Globals
15 |
16 | // var _MOUNTSTAT3 = {
17 | // MNT3_OK: 0, // no error
18 | // MNT3ERR_Perm: 1, // Not owner
19 | // MNT3ERR_NoEnt: 2, // No such file or directory
20 | // MNT3ERR_IO: 5, // I/O error
21 | // MNT3ERR_Access: 13, // Permission denied
22 | // MNT3ERR_NotDir: 20, // Not a directory
23 | // MNT3ERR_Inval: 22, // Invalid argument
24 | // MNT3ERR_NameTooLong: 63, // Filename too long
25 | // MNT3ERR_NotSupp: 10004, // Operation not supported
26 | // MNT3ERR_ServerFault: 10006 // A failure on the server
27 | // };
28 |
29 |
30 | var MOUNTSTAT3 = {
31 | MNT3_OK: 0, // no error
32 | MNT3ERR_PERM: 1, // Not owner
33 | MNT3ERR_NOENT: 2, // No such file or directory
34 | MNT3ERR_IO: 5, // I/O error
35 | MNT3ERR_ACCES: 13, // Permission denied
36 | MNT3ERR_NOTDIR: 20, // Not a directory
37 | MNT3ERR_INVAL: 22, // Invalid argument
38 | MNT3ERR_NAMETOOLONG: 63, // Filename too long
39 | MNT3ERR_NOTSUPP: 10004, // Operation not supported
40 | MNT3ERR_SERVERFAULT: 10006 // A failure on the server
41 | };
42 |
43 |
44 |
45 | ///--- Base API
46 |
47 | function MountError(cause, msg) {
48 | rpc.RpcError.apply(this, arguments);
49 | }
50 | MountError.prototype.name = 'MountError';
51 | util.inherits(MountError, rpc.RpcError);
52 |
53 |
54 | MountError.prototype.toBuffer = function toBuffer() {
55 | var xdr = this._serialize(4);
56 | xdr.writeInt(this.mountstat3);
57 |
58 | return (xdr.buffer());
59 | };
60 |
61 |
62 |
63 | ///--- Exports
64 |
65 | module.exports = {
66 | MountError: MountError
67 | };
68 |
69 | // Object.keys(MOUNTSTAT3).forEach(function (k) {
70 | // if (k === 'MNT3_OK')
71 | // return;
72 |
73 | // var name = 'Mount' + k.split('_')[1] + 'Error';
74 | // var err = function () {
75 | // MountError.apply(this, arguments);
76 | // this.mountstat3 = MOUNTSTAT3[k];
77 | // };
78 | // util.inherits(err, MountError);
79 | // err.prototype.name = name;
80 |
81 | // module.exports[name] = err;
82 | // });
83 |
84 | Object.keys(MOUNTSTAT3).forEach(function (k) {
85 | module.exports[k] = MOUNTSTAT3[k];
86 | });
87 |
--------------------------------------------------------------------------------
/lib/mount/index.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 |
8 |
9 | ///--- Helpers
10 |
11 | function _export(obj) {
12 | Object.keys(obj).forEach(function (k) {
13 | module.exports[k] = obj[k];
14 | });
15 | }
16 |
17 |
18 |
19 | ///--- Exports
20 |
21 | module.exports = {};
22 |
23 | _export(require('./client'));
24 | _export(require('./dump_reply'));
25 | _export(require('./errors'));
26 | _export(require('./mnt_call'));
27 | _export(require('./mnt_reply'));
28 | _export(require('./server'));
29 | _export(require('./umnt_call'));
30 | _export(require('./umnt_reply'));
31 |
--------------------------------------------------------------------------------
/lib/mount/mnt_call.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var util = require('util');
8 |
9 | var assert = require('assert-plus');
10 | var rpc = require('oncrpc');
11 |
12 |
13 |
14 | ///--- Globals
15 |
16 | var RpcCall = rpc.RpcCall;
17 | var XDR = rpc.XDR;
18 |
19 |
20 |
21 | ///--- API
22 |
23 | function MountMntCall(opts) {
24 | RpcCall.call(this, opts, true);
25 |
26 | this.dirpath = opts.dirpath || '';
27 |
28 | this._nfs_mount_mnt_call = true; // MDB
29 | }
30 | util.inherits(MountMntCall, RpcCall);
31 |
32 |
33 | MountMntCall.prototype._transform = function _transform(chunk, enc, cb) {
34 | if (this.incoming) {
35 | var xdr = new XDR(chunk);
36 | this.dirpath = xdr.readString();
37 | } else {
38 | this.push(chunk);
39 | }
40 |
41 | cb();
42 | };
43 |
44 |
45 | MountMntCall.prototype.writeHead = function writeHead() {
46 | var xdr = this._serialize(XDR.byteLength(this.dirpath));
47 | xdr.writeString(this.dirpath);
48 |
49 | this.write(xdr.buffer());
50 | };
51 |
52 |
53 | MountMntCall.prototype.toString = function toString() {
54 | var fmt = '[object MountMntCall ]';
55 | return (util.format(fmt, this.xid, this.dirpath));
56 | };
57 |
58 |
59 |
60 | ///--- Exports
61 |
62 | module.exports = {
63 | MountMntCall: MountMntCall
64 | };
65 |
--------------------------------------------------------------------------------
/lib/mount/mnt_reply.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var path = require('path');
8 | var util = require('util');
9 |
10 | var assert = require('assert-plus');
11 | var clone = require('clone');
12 | var rpc = require('oncrpc');
13 |
14 | var mnt_err = require('./errors');
15 | var MountReply = require('./mount_reply').MountReply;
16 |
17 |
18 | ///--- Globals
19 |
20 | var XDR = rpc.XDR;
21 |
22 |
23 |
24 |
25 | ///--- Helpers
26 |
27 | function calculate_buffer_length(mappings) {
28 | assert.arrayOfObject(mappings, 'mappings');
29 | var sz = 0;
30 | mappings.forEach(function (m) {
31 | sz += 4; // boolean marker
32 | sz += XDR.byteLength(m.name);
33 | sz += XDR.byteLength(m.dirpath);
34 | });
35 | sz += 4; // final boolean marker
36 |
37 | return (sz);
38 | }
39 |
40 |
41 |
42 | ///--- API
43 |
44 | function MountMntReply(opts) {
45 | MountReply.call(this, opts);
46 |
47 | this.fhs_status = 0;
48 | this.mountinfo = {
49 | fhandle: '',
50 | auth_flavors: [1]
51 | };
52 |
53 | this._nfs_mount_mnt_reply = true; // MDB
54 | }
55 | util.inherits(MountMntReply, MountReply);
56 | MountMntReply.prototype.__defineSetter__('status', function (s) {
57 | assert.number(s, 'status');
58 | this.fhs_status = s;
59 | });
60 | MountMntReply.prototype.__defineGetter__('status', function () {
61 | return (this.fhs_status);
62 | });
63 | MountMntReply.prototype._allowed_error_codes = [
64 | mnt_err.MNT3ERR_NOENT,
65 | mnt_err.MNT3ERR_IO,
66 | mnt_err.MNT3ERR_ACCES,
67 | mnt_err.MNT3ERR_NOTDIR,
68 | mnt_err.MNT3ERR_NAMETOOLONG
69 | ];
70 |
71 |
72 | MountMntReply.prototype.setFileHandle = function setFileHandle(fh) {
73 | assert.string(fh, 'file_handle');
74 |
75 | this.mountinfo.fhandle = fh;
76 |
77 | if (this.mountinfo.fhandle.length > 64)
78 | this.mountinfo.fhandle.length = 64;
79 |
80 | return (this.mountinfo.fhandle);
81 | };
82 |
83 |
84 | MountMntReply.prototype._transform = function _transform(chunk, enc, cb) {
85 | if (this.incoming) {
86 | var xdr = new XDR(chunk);
87 |
88 | this.fhs_status = xdr.readInt();
89 | if (this.fhs_status === 0) {
90 | this.mountinfo.fhandle = xdr.readString();
91 | this.mountinfo.auth_flavors = xdr.readIntArray();
92 | }
93 | } else {
94 | this.push(chunk);
95 | }
96 |
97 | cb();
98 | };
99 |
100 |
101 | MountMntReply.prototype.writeHead = function writeHead() {
102 | var len = 4;
103 | if (this.fhs_status === 0) {
104 | len += XDR.byteLength(this.mountinfo.fhandle);
105 | len += XDR.byteLength(this.mountinfo.auth_flavors);
106 | }
107 | var xdr = this._serialize(len);
108 |
109 | xdr.writeInt(this.fhs_status);
110 | if (this.fhs_status === 0) {
111 | xdr.writeString(this.mountinfo.fhandle);
112 | xdr.writeIntArray(this.mountinfo.auth_flavors);
113 | }
114 |
115 | this.write(xdr.buffer());
116 | };
117 |
118 |
119 | MountMntReply.prototype.toString = function toString() {
120 | var fmt = '[object MountMntReply ]';
121 | return (util.format(fmt, this.xid, this.fhs_status, this.mountinfo));
122 | };
123 |
124 |
125 |
126 | ///--- Exports
127 |
128 | module.exports = {
129 | MountMntReply: MountMntReply
130 | };
131 |
--------------------------------------------------------------------------------
/lib/mount/mount_reply.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var util = require('util');
8 |
9 | var assert = require('assert-plus');
10 | var RpcReply = require('oncrpc').RpcReply;
11 |
12 | var mnt_err = require('./errors');
13 |
14 |
15 |
16 | ///--- Errors
17 |
18 | var ALLOWED_ERRORS = [
19 | mnt_err.MNT3ERR_NOENT,
20 | mnt_err.MNT3ERR_IO,
21 | mnt_err.MNT3ERR_ACCES,
22 | mnt_err.MNT3ERR_NOTDIR,
23 | mnt_err.MNT3ERR_NAMETOOLONG,
24 | mnt_err.MNT3ERR_SERVERFAULT
25 | ];
26 |
27 | ///--- API
28 |
29 | function MountReply(opts) {
30 | assert.object(opts, 'options');
31 |
32 | RpcReply.call(this, opts);
33 |
34 | this._mount_reply = true; // MDB
35 | }
36 | util.inherits(MountReply, RpcReply);
37 |
38 |
39 | MountReply.prototype.error = function error(status) {
40 | assert.number(status, 'status');
41 |
42 | if (!ALLOWED_ERRORS.some(function (c) {
43 | return (c === status);
44 | })) {
45 | throw new Error(status + ' is not an allowed status code');
46 | }
47 |
48 | this.status = status;
49 | this.send();
50 | };
51 |
52 |
53 |
54 | ///--- Exports
55 |
56 | module.exports = {
57 | MountReply: MountReply
58 | };
59 |
--------------------------------------------------------------------------------
/lib/mount/server.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var util = require('util');
8 |
9 | var assert = require('assert-plus');
10 | var clone = require('clone');
11 | var rpc = require('oncrpc');
12 |
13 | var errors = require('./errors');
14 | var MountDumpReply = require('./dump_reply').MountDumpReply;
15 | var MountMntCall = require('./mnt_call').MountMntCall;
16 | var MountMntReply = require('./mnt_reply').MountMntReply;
17 | var MountUmntCall = require('./umnt_call').MountUmntCall;
18 | var MountUmntReply = require('./umnt_reply').MountUmntReply;
19 |
20 |
21 |
22 | ///--- Globals
23 |
24 | var slice = Function.prototype.call.bind(Array.prototype.slice);
25 | var RpcServer = rpc.RpcServer;
26 |
27 |
28 |
29 | ///--- API
30 |
31 | function MountServer(opts) {
32 | assert.object(opts, 'options');
33 | if (opts.log) {
34 | var l = opts.log;
35 | delete opts.log;
36 | }
37 |
38 | var _opts = clone(opts);
39 | _opts.log = opts.log = l;
40 | _opts.name = 'mount';
41 | _opts.program = 100005;
42 | _opts.version = [1, 3];
43 |
44 | RpcServer.call(this, _opts);
45 | }
46 | util.inherits(MountServer, RpcServer);
47 |
48 |
49 | MountServer.prototype.dump = function dump() {
50 | var cfg = {
51 | name: 'dump',
52 | procedure: 2,
53 | reply: MountDumpReply
54 | };
55 | this._mount(cfg, slice(arguments));
56 |
57 | return (this);
58 | };
59 |
60 |
61 |
62 | MountServer.prototype.mnt = function mnt() {
63 | var cfg = {
64 | name: 'mnt',
65 | procedure: 1,
66 | call: MountMntCall,
67 | reply: MountMntReply
68 | };
69 | this._mount(cfg, slice(arguments));
70 |
71 | return (this);
72 | };
73 |
74 |
75 | MountServer.prototype.umnt = function umnt() {
76 | var cfg = {
77 | name: 'umnt',
78 | procedure: 3,
79 | call: MountUmntCall,
80 | reply: MountUmntReply
81 | };
82 | this._mount(cfg, slice(arguments));
83 |
84 | return (this);
85 | };
86 |
87 |
88 | MountServer.prototype.start = function start(host, cb) {
89 | var args = slice(arguments);
90 | args.unshift(1892);
91 | this.listen.apply(this, args);
92 | };
93 |
94 |
95 |
96 | ///--- Exports
97 |
98 | module.exports = {
99 | MountServer: MountServer,
100 | createMountServer: function createMountServer(opts) {
101 | return (new MountServer(opts));
102 | }
103 | };
104 |
--------------------------------------------------------------------------------
/lib/mount/umnt_call.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var util = require('util');
8 |
9 | var assert = require('assert-plus');
10 | var rpc = require('oncrpc');
11 |
12 |
13 |
14 | ///--- Globals
15 |
16 | var RpcCall = rpc.RpcCall;
17 | var XDR = rpc.XDR;
18 |
19 |
20 |
21 | ///--- API
22 |
23 | function MountUmntCall(opts) {
24 | RpcCall.call(this, opts, true);
25 |
26 | this.dirpath = opts.dirpath || '';
27 |
28 | this._nfs_mount_umnt_call = true; // MDB
29 | }
30 | util.inherits(MountUmntCall, RpcCall);
31 |
32 |
33 | MountUmntCall.prototype._transform = function _transform(chunk, enc, cb) {
34 | if (this.incoming) {
35 | var xdr = new XDR(chunk);
36 | this.dirpath = xdr.readString();
37 | } else {
38 | this.push(chunk);
39 | }
40 |
41 | cb();
42 | };
43 |
44 |
45 | MountUmntCall.prototype.writeHead = function writeHead() {
46 | var xdr = this._serialize(XDR.byteLength(this.dirpath));
47 | xdr.writeString(this.dirpath);
48 |
49 | this.write(xdr.buffer());
50 | };
51 |
52 |
53 | MountUmntCall.prototype.toString = function toString() {
54 | var fmt = '[object MountUmntCall ]';
55 | return (util.format(fmt, this.xid, this.dirpath));
56 | };
57 |
58 |
59 |
60 | ///--- Exports
61 |
62 | module.exports = {
63 | MountUmntCall: MountUmntCall
64 | };
65 |
--------------------------------------------------------------------------------
/lib/mount/umnt_reply.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var path = require('path');
8 | var util = require('util');
9 |
10 | var assert = require('assert-plus');
11 | var clone = require('clone');
12 | var rpc = require('oncrpc');
13 |
14 | var mnt_err = require('./errors');
15 | var MountReply = require('./mount_reply').MountReply;
16 |
17 |
18 | ///--- API
19 |
20 | function MountUmntReply(opts) {
21 | MountReply.call(this, opts);
22 |
23 | this._nfs_mount_umnt_reply = true; // MDB
24 | }
25 | util.inherits(MountUmntReply, MountReply);
26 | MountUmntReply.prototype.__defineSetter__('status', function (s) {});
27 | MountUmntReply.prototype.__defineGetter__('status', function () {
28 | return (0);
29 | });
30 | MountUmntReply.prototype._allowed_error_codes = [];
31 |
32 |
33 | MountUmntReply.prototype.toString = function toString() {
34 | var fmt = '[object MountUmntReply ]';
35 | return (util.format(fmt, this.xid));
36 | };
37 |
38 |
39 |
40 | ///--- Exports
41 |
42 | module.exports = {
43 | MountUmntReply: MountUmntReply
44 | };
45 |
--------------------------------------------------------------------------------
/lib/nfs/errors.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var util = require('util');
8 |
9 | var assert = require('assert-plus');
10 | var rpc = require('oncrpc');
11 |
12 |
13 |
14 | ///--- Globals
15 |
16 | var NFSSTAT3 = {
17 | NFS3_OK: 0,
18 | NFS3ERR_PERM: 1,
19 | NFS3ERR_NOENT: 2,
20 | NFS3ERR_IO: 5,
21 | NFS3ERR_NXIO: 6,
22 | NFS3ERR_ACCES: 13,
23 | NFS3ERR_EXIST: 17,
24 | NFS3ERR_XDEV: 18,
25 | NFS3ERR_NODEV: 19,
26 | NFS3ERR_NOTDIR: 20,
27 | NFS3ERR_ISDIR: 21,
28 | NFS3ERR_INVAL: 22,
29 | NFS3ERR_FBIG: 27,
30 | NFS3ERR_NOSPACE: 28,
31 | NFS3ERR_ROFS: 30,
32 | NFS3ERR_MLINK: 31,
33 | NFS3ERR_NAMETOOLONG: 63,
34 | NFS3ERR_NOTEMPTY: 66,
35 | NFS3ERR_DQUOT: 69,
36 | NFS3ERR_STALE: 70,
37 | NFS3ERR_REMOTE: 71,
38 | NFS3ERR_BADHANDLE: 10001,
39 | NFS3ERR_NOT_SYNC: 10002,
40 | NFS3ERR_BAD_COOKIE: 10003,
41 | NFS3ERR_NOTSUPP: 10004,
42 | NFS3ERR_TOOSMALL: 10005,
43 | NFS3ERR_SERVERFAULT: 10006,
44 | NFS3ERR_BADTYPE: 10007,
45 | NFS3ERR_JUKEBOX: 10008
46 | };
47 |
48 |
49 |
50 | ///--- Base API
51 |
52 | function NfsError(cause, msg) {
53 | rpc.RpcError.apply(this, arguments);
54 | }
55 | NfsError.prototype.name = 'NfsError';
56 | util.inherits(NfsError, rpc.RpcError);
57 |
58 |
59 | NfsError.prototype.toBuffer = function toBuffer() {
60 | var xdr = this._serialize(4);
61 | xdr.writeInt(this.nfsstat3);
62 |
63 | return (xdr.buffer());
64 | };
65 |
66 |
67 |
68 | ///--- Exports
69 |
70 | module.exports = {
71 | NfsError: NfsError
72 | };
73 |
74 | // Object.keys(_NFSSTAT3).forEach(function (k) {
75 | // if (k === 'NFS3_OK')
76 | // return;
77 |
78 | // var name = 'Nfs' + k.split('_')[1] + 'Error';
79 | // var err = function () {
80 | // NfsError.apply(this, arguments);
81 | // this.nfsstat3 = NFSSTAT3[k];
82 | // };
83 | // util.inherits(err, NfsError);
84 | // err.prototype.name = name;
85 |
86 | // module.exports[name] = err;
87 | // });
88 |
89 |
90 | Object.keys(NFSSTAT3).forEach(function (k) {
91 | module.exports[k] = NFSSTAT3[k];
92 | });
93 |
--------------------------------------------------------------------------------
/lib/nfs/fattr3.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var path = require('path');
8 | var util = require('util');
9 |
10 | var assert = require('assert-plus');
11 | var clone = require('clone');
12 | var rpc = require('oncrpc');
13 |
14 |
15 |
16 | ///--- Globals
17 |
18 | var XDR = rpc.XDR;
19 |
20 |
21 |
22 | ///--- Globals
23 |
24 | var ftype3 = {
25 | NF3REG: 1,
26 | NF3DIR: 2,
27 | NF3BLK: 3,
28 | NF3CHR: 4,
29 | NF3LNK: 5,
30 | NF3SOCK: 6,
31 | NF3FIFO: 7
32 | };
33 |
34 |
35 | // struct nfstime3 {
36 | // uint32 seconds;
37 | // uint32 nseconds;
38 | // };
39 |
40 | // struct specdata3 {
41 | // uint32 specdata1;
42 | // uint32 specdata2;
43 | // };
44 |
45 | // struct fattr3 {
46 | // ftype3 type; // unit32
47 | // mode3 mode; // uint32
48 | // uint32 nlink; // uint32
49 | // uid3 uid; // uint32
50 | // gid3 gid; // uint32
51 | // size3 size; // uint64
52 | // size3 used; // uint64
53 | // specdata3 rdev;
54 | // uint64 fsid;
55 | // fileid3 fileid; // uint64
56 | // nfstime3 atime;
57 | // nfstime3 mtime;
58 | // nfstime3 ctime;
59 | // };
60 |
61 |
62 | function get_type(t) {
63 | var type;
64 |
65 | if (t.isFile()) {
66 | type = ftype3.NF3REG;
67 | } else if (t.isDirectory()) {
68 | type = ftype3.NF3DIR;
69 | } else if (t.isBlockDevice()) {
70 | type = ftype3.NF3CHR;
71 | } else if (t.isSymbolicLink()) {
72 | type = ftype3.NF3LNK;
73 | } else if (t.isSocket()) {
74 | type = ftype3.NF3SOCK;
75 | } else if (t.isFIFO()) {
76 | type = ftype3.NF3FIFO;
77 | } else {
78 | type = -1;
79 | }
80 |
81 | return (type);
82 | }
83 |
84 |
85 | function create_fattr3(stats) {
86 | var fattr3 = {
87 | type: get_type(stats),
88 | mode: stats.mode,
89 | nlink: stats.nlink,
90 | uid: stats.uid,
91 | gid: stats.gid,
92 | size: stats.size,
93 | used: stats.size,
94 | rdev: {
95 | specdata1: 0,
96 | specdata2: 0
97 | },
98 | fsid: stats.dev,
99 | fileid: stats.ino,
100 | atime: {
101 | seconds: Math.floor(new Date(stats.atime).getTime() / 1000),
102 | nseconds: 0
103 | },
104 | mtime: {
105 | seconds: Math.floor(new Date(stats.mtime).getTime() / 1000),
106 | nseconds: 0
107 | },
108 | ctime: {
109 | seconds: Math.floor(new Date(stats.ctime).getTime() / 1000),
110 | nseconds: 0
111 | }
112 | };
113 |
114 | return (fattr3);
115 | }
116 |
117 |
118 | function parse_fattr3(xdr) {
119 | assert.object(xdr, 'xdr');
120 |
121 | var fattr3 = {
122 | type: xdr.readInt(),
123 | mode: xdr.readInt(),
124 | nlink: xdr.readInt(),
125 | uid: xdr.readInt(),
126 | gid: xdr.readInt(),
127 | size: xdr.readHyper(),
128 | used: xdr.readHyper(),
129 | rdev: {
130 | specdata1: xdr.readInt(),
131 | specdata2: xdr.readInt()
132 | },
133 | fsid: xdr.readHyper(),
134 | fileid: xdr.readHyper(),
135 | atime: {
136 | seconds: xdr.readInt(),
137 | nseconds: xdr.readInt()
138 | },
139 | mtime: {
140 | seconds: xdr.readInt(),
141 | nseconds: xdr.readInt()
142 | },
143 | ctime: {
144 | seconds: xdr.readInt(),
145 | nseconds: xdr.readInt()
146 | }
147 | };
148 |
149 | return (fattr3);
150 | }
151 |
152 |
153 | function serialize_fattr3(xdr, fattr3) {
154 | assert.object(xdr, 'xdr');
155 | assert.object(fattr3, 'fattr3');
156 |
157 | xdr.writeInt(fattr3.type);
158 | xdr.writeInt(fattr3.mode);
159 | xdr.writeInt(fattr3.nlink);
160 | xdr.writeInt(fattr3.uid);
161 | xdr.writeInt(fattr3.gid);
162 | xdr.writeHyper(fattr3.size);
163 | xdr.writeHyper(fattr3.used);
164 | xdr.writeInt(fattr3.rdev.specdata1);
165 | xdr.writeInt(fattr3.rdev.specdata2);
166 | xdr.writeHyper(fattr3.fsid);
167 | xdr.writeHyper(fattr3.fileid);
168 | xdr.writeInt(fattr3.atime.seconds);
169 | xdr.writeInt(fattr3.atime.nseconds);
170 | xdr.writeInt(fattr3.mtime.seconds);
171 | xdr.writeInt(fattr3.mtime.nseconds);
172 | xdr.writeInt(fattr3.ctime.seconds);
173 | xdr.writeInt(fattr3.ctime.nseconds);
174 |
175 | return (xdr);
176 | }
177 |
178 |
179 |
180 | ///--- Exports
181 |
182 | module.exports = {
183 | create: create_fattr3,
184 | create_fattr3: create_fattr3,
185 | parse: parse_fattr3,
186 | serialize: serialize_fattr3,
187 | XDR_SIZE: 84
188 | };
189 |
--------------------------------------------------------------------------------
/lib/nfs/fs_stat_call.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.18 Procedure 18: FSSTAT - Get dynamic file system information
8 | //
9 | // SYNOPSIS
10 | //
11 | // FSSTAT3res NFSPROC3_FSSTAT(FSSTAT3args) = 18;
12 | //
13 | // struct FSSTAT3args {
14 | // nfs_fh3 fsroot;
15 | // };
16 | //
17 | // struct FSSTAT3resok {
18 | // post_op_attr obj_attributes;
19 | // size3 tbytes;
20 | // size3 fbytes;
21 | // size3 abytes;
22 | // size3 tfiles;
23 | // size3 ffiles;
24 | // size3 afiles;
25 | // uint32 invarsec;
26 | // };
27 | //
28 | // struct FSSTAT3resfail {
29 | // post_op_attr obj_attributes;
30 | // };
31 | //
32 | // union FSSTAT3res switch (nfsstat3 status) {
33 | // case NFS3_OK:
34 | // FSSTAT3resok resok;
35 | // default:
36 | // FSSTAT3resfail resfail;
37 | // };
38 | //
39 | // DESCRIPTION
40 | //
41 | // Procedure FSSTAT retrieves volatile file system state
42 | // information. On entry, the arguments in FSSTAT3args are:
43 | //
44 | // fsroot
45 | // A file handle identifying a object in the file system.
46 | // This is normally a file handle for a mount point for a
47 | // file system, as originally obtained from the MOUNT
48 | // service on the server.
49 | //
50 | // On successful return, FSSTAT3res.status is NFS3_OK and
51 | // FSSTAT3res.resok contains:
52 | //
53 | // obj_attributes
54 | // The attributes of the file system object specified in
55 | // fsroot.
56 | //
57 | // tbytes
58 | // The total size, in bytes, of the file system.
59 | //
60 | // fbytes
61 | // The amount of free space, in bytes, in the file
62 | // system.
63 | //
64 | // abytes
65 | // The amount of free space, in bytes, available to the
66 | // user identified by the authentication information in
67 | // the RPC. (This reflects space that is reserved by the
68 | // file system; it does not reflect any quota system
69 | // implemented by the server.)
70 | //
71 | // tfiles
72 | // The total number of file slots in the file system. (On
73 | // a UNIX server, this often corresponds to the number of
74 | // inodes configured.)
75 | //
76 | // ffiles
77 | // The number of free file slots in the file system.
78 | //
79 | // afiles
80 | // The number of free file slots that are available to the
81 | // user corresponding to the authentication information in
82 | // the RPC. (This reflects slots that are reserved by the
83 | // file system; it does not reflect any quota system
84 | // implemented by the server.)
85 | //
86 | // invarsec
87 | // A measure of file system volatility: this is the number
88 | // of seconds for which the file system is not expected to
89 | // change. For a volatile, frequently updated file system,
90 | // this will be 0. For an immutable file system, such as a
91 | // CD-ROM, this would be the largest unsigned integer. For
92 | // file systems that are infrequently modified, for
93 | // example, one containing local executable programs and
94 | // on-line documentation, a value corresponding to a few
95 | // hours or days might be used. The client may use this as
96 | // a hint in tuning its cache management. Note however,
97 | // this measure is assumed to be dynamic and may change at
98 | // any time.
99 | //
100 | // Otherwise, FSSTAT3res.status contains the error on failure
101 | // and FSSTAT3res.resfail contains the following:
102 | //
103 | // obj_attributes
104 | // The attributes of the file system object specified in
105 | // fsroot.
106 | //
107 | // IMPLEMENTATION
108 | //
109 | // Not all implementations can support the entire list of
110 | // attributes. It is expected that servers will make a best
111 | // effort at supporting all the attributes.
112 | //
113 | // ERRORS
114 | //
115 | // NFS3ERR_IO
116 | // NFS3ERR_STALE
117 | // NFS3ERR_BADHANDLE
118 | // NFS3ERR_SERVERFAULT
119 | //
120 | // SEE ALSO
121 | //
122 | // FSINFO.
123 |
124 | var util = require('util');
125 |
126 | var assert = require('assert-plus');
127 | var rpc = require('oncrpc');
128 |
129 | var NfsCall = require('./nfs_call').NfsCall;
130 |
131 |
132 |
133 | ///--- Globals
134 |
135 | var XDR = rpc.XDR;
136 |
137 |
138 |
139 | ///--- API
140 |
141 | function FsStatCall(opts) {
142 | NfsCall.call(this, opts, true);
143 |
144 | this.fsroot = opts.fsroot || '';
145 |
146 | this._nfs_fs_stat_call = true; // MDB
147 | }
148 | util.inherits(FsStatCall, NfsCall);
149 | Object.defineProperty(FsStatCall.prototype, 'object', {
150 | get: function object() {
151 | return (this.fsroot);
152 | }
153 | });
154 |
155 |
156 | FsStatCall.prototype._transform = function _transform(chunk, enc, cb) {
157 | if (this.incoming) {
158 | var xdr = new XDR(chunk);
159 | this.fsroot = xdr.readString();
160 | } else {
161 | this.push(chunk);
162 | }
163 |
164 | cb();
165 | };
166 |
167 |
168 | FsStatCall.prototype.writeHead = function writeHead() {
169 | var xdr = this._serialize(XDR.byteLength(this.fsroot));
170 | xdr.writeString(this.fsroot);
171 |
172 | this.write(xdr.buffer());
173 | };
174 |
175 |
176 | FsStatCall.prototype.toString = function toString() {
177 | var fmt = '[object FsStatCall ]';
178 | return (util.format(fmt, this.xid, this.fsroot));
179 | };
180 |
181 |
182 |
183 | ///--- Exports
184 |
185 | module.exports = {
186 | FsStatCall: FsStatCall
187 | };
188 |
--------------------------------------------------------------------------------
/lib/nfs/get_attr_call.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.1 Procedure 1: GETATTR - Get file attributes
8 | //
9 | // SYNOPSIS
10 | //
11 | // GETATTR3res NFSPROC3_GETATTR(GETATTR3args) = 1;
12 | //
13 | // struct GETATTR3args {
14 | // nfs_fh3 object;
15 | // };
16 | //
17 | // struct GETATTR3resok {
18 | // fattr3 obj_attributes;
19 | // };
20 | //
21 | // union GETATTR3res switch (nfsstat3 status) {
22 | // case NFS3_OK:
23 | // GETATTR3resok resok;
24 | // default:
25 | // void;
26 | // };
27 | //
28 | // DESCRIPTION
29 | //
30 | // Procedure GETATTR retrieves the attributes for a specified
31 | // file system object. The object is identified by the file
32 | // handle that the server returned as part of the response
33 | // from a LOOKUP, CREATE, MKDIR, SYMLINK, MKNOD, or
34 | // READDIRPLUS procedure (or from the MOUNT service,
35 | // described elsewhere). On entry, the arguments in
36 | // GETATTR3args are:
37 | //
38 | // object
39 | // The file handle of an object whose attributes are to be
40 | // retrieved.
41 | //
42 | // On successful return, GETATTR3res.status is NFS3_OK and
43 | // GETATTR3res.resok contains:
44 | //
45 | // obj_attributes
46 | // The attributes for the object.
47 | //
48 | // Otherwise, GETATTR3res.status contains the error on failure and
49 | // no other results are returned.
50 | //
51 | // IMPLEMENTATION
52 | //
53 | // The attributes of file system objects is a point of major
54 | // disagreement between different operating systems. Servers
55 | // should make a best attempt to support all of the
56 | // attributes in the fattr3 structure so that clients can
57 | // count on this as a common ground. Some mapping may be
58 | // required to map local attributes to those in the fattr3
59 | // structure.
60 | //
61 | // Today, most client NFS version 3 protocol implementations
62 | // implement a time-bounded attribute caching scheme to
63 | // reduce over-the-wire attribute checks.
64 | //
65 | // ERRORS
66 | //
67 | // NFS3ERR_IO
68 | // NFS3ERR_STALE
69 | // NFS3ERR_BADHANDLE
70 | // NFS3ERR_SERVERFAULT
71 | //
72 | // SEE ALSO
73 | //
74 | // ACCESS.
75 |
76 |
77 | var util = require('util');
78 |
79 | var assert = require('assert-plus');
80 | var rpc = require('oncrpc');
81 |
82 | var NfsCall = require('./nfs_call').NfsCall;
83 |
84 |
85 |
86 | ///--- Globals
87 |
88 | var XDR = rpc.XDR;
89 |
90 |
91 |
92 | ///--- API
93 |
94 | function GetAttrCall(opts) {
95 | NfsCall.call(this, opts, true);
96 |
97 | this._object = opts.object || '';
98 |
99 | this._nfs_get_attr_call = true; // MDB
100 | }
101 | util.inherits(GetAttrCall, NfsCall);
102 | Object.defineProperty(GetAttrCall.prototype, 'object', {
103 | get: function object() {
104 | return (this._object);
105 | }
106 | });
107 |
108 |
109 | GetAttrCall.prototype._transform = function _transform(chunk, enc, cb) {
110 | if (this.incoming) {
111 | var xdr = new XDR(chunk);
112 | this._object = xdr.readString();
113 | } else {
114 | this.push(chunk);
115 | }
116 |
117 | cb();
118 | };
119 |
120 |
121 | GetAttrCall.prototype.writeHead = function writeHead() {
122 | var xdr = this._serialize(XDR.byteLength(this._object));
123 | xdr.writeString(this._object);
124 |
125 | this.write(xdr.buffer());
126 | };
127 |
128 |
129 | GetAttrCall.prototype.toString = function toString() {
130 | var fmt = '[object GetAttrCall ]';
131 | return (util.format(fmt, this.xid, this._object));
132 | };
133 |
134 |
135 |
136 | ///--- Exports
137 |
138 | module.exports = {
139 | GetAttrCall: GetAttrCall
140 | };
141 |
--------------------------------------------------------------------------------
/lib/nfs/get_attr_reply.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.1 Procedure 1: GETATTR - Get file attributes
8 | //
9 | // SYNOPSIS
10 | //
11 | // GETATTR3res NFSPROC3_GETATTR(GETATTR3args) = 1;
12 | //
13 | // struct GETATTR3args {
14 | // nfs_fh3 object;
15 | // };
16 | //
17 | // struct GETATTR3resok {
18 | // fattr3 obj_attributes;
19 | // };
20 | //
21 | // union GETATTR3res switch (nfsstat3 status) {
22 | // case NFS3_OK:
23 | // GETATTR3resok resok;
24 | // default:
25 | // void;
26 | // };
27 | //
28 | // DESCRIPTION
29 | //
30 | // Procedure GETATTR retrieves the attributes for a specified
31 | // file system object. The object is identified by the file
32 | // handle that the server returned as part of the response
33 | // from a LOOKUP, CREATE, MKDIR, SYMLINK, MKNOD, or
34 | // READDIRPLUS procedure (or from the MOUNT service,
35 | // described elsewhere). On entry, the arguments in
36 | // GETATTR3args are:
37 | //
38 | // object
39 | // The file handle of an object whose attributes are to be
40 | // retrieved.
41 | //
42 | // On successful return, GETATTR3res.status is NFS3_OK and
43 | // GETATTR3res.resok contains:
44 | //
45 | // obj_attributes
46 | // The attributes for the object.
47 | //
48 | // Otherwise, GETATTR3res.status contains the error on failure and
49 | // no other results are returned.
50 | //
51 | // IMPLEMENTATION
52 | //
53 | // The attributes of file system objects is a point of major
54 | // disagreement between different operating systems. Servers
55 | // should make a best attempt to support all of the
56 | // attributes in the fattr3 structure so that clients can
57 | // count on this as a common ground. Some mapping may be
58 | // required to map local attributes to those in the fattr3
59 | // structure.
60 | //
61 | // Today, most client NFS version 3 protocol implementations
62 | // implement a time-bounded attribute caching scheme to
63 | // reduce over-the-wire attribute checks.
64 | //
65 | // ERRORS
66 | //
67 | // NFS3ERR_IO
68 | // NFS3ERR_STALE
69 | // NFS3ERR_BADHANDLE
70 | // NFS3ERR_SERVERFAULT
71 | //
72 | // SEE ALSO
73 | //
74 | // ACCESS.
75 |
76 | var fs = require('fs');
77 | var path = require('path');
78 | var util = require('util');
79 |
80 | var assert = require('assert-plus');
81 | var clone = require('clone');
82 | var rpc = require('oncrpc');
83 |
84 | var nfs_err = require('./errors');
85 | var fattr3 = require('./fattr3');
86 | var NfsReply = require('./nfs_reply').NfsReply;
87 |
88 |
89 |
90 | ///--- Globals
91 |
92 | var XDR = rpc.XDR;
93 |
94 |
95 |
96 | ///--- API
97 |
98 | function GetAttrReply(opts) {
99 | NfsReply.call(this, opts);
100 |
101 | this.status = 0;
102 | this.obj_attributes = opts.obj_attributes | {};
103 |
104 | this._nfs_get_attr_reply = true; // MDB
105 | }
106 | util.inherits(GetAttrReply, NfsReply);
107 | GetAttrReply.prototype._allowed_error_codes = [
108 | nfs_err.NFS3ERR_IO,
109 | nfs_err.NFS3ERR_STALE,
110 | nfs_err.NFS3ERR_BADHANDLE,
111 | nfs_err.NFS3ERR_SERVERFAULT
112 | ];
113 |
114 |
115 | GetAttrReply.prototype.setAttributes = function setAttributes(stats) {
116 | assert.ok(stats instanceof fs.Stats, 'fs.Stats');
117 |
118 | this.obj_attributes = fattr3.create(stats);
119 |
120 | return (this.obj_attributes);
121 | };
122 |
123 |
124 | GetAttrReply.prototype._transform = function _transform(chunk, enc, cb) {
125 | if (this.incoming) {
126 | var xdr = new XDR(chunk);
127 |
128 | this.status = xdr.readInt();
129 | if (this.status === 0)
130 | this.obj_attributes = fattr3.parse(xdr);
131 | } else {
132 | this.push(chunk);
133 | }
134 |
135 | cb();
136 | };
137 |
138 |
139 | GetAttrReply.prototype.writeHead = function writeHead() {
140 | var len = 4;
141 | if (this.status === 0)
142 | len += fattr3.XDR_SIZE;
143 |
144 | var xdr = this._serialize(len);
145 |
146 | xdr.writeInt(this.status);
147 | if (this.status === 0)
148 | fattr3.serialize(xdr, this.obj_attributes);
149 |
150 | this.write(xdr.buffer());
151 | };
152 |
153 |
154 | GetAttrReply.prototype.toString = function toString() {
155 | var fmt = '[object GetAttrReply ]';
156 | return (util.format(fmt, this.xid, this.status, this.obj_attributes));
157 | };
158 |
159 |
160 |
161 | ///--- Exports
162 |
163 | module.exports = {
164 | GetAttrReply: GetAttrReply
165 | };
166 |
--------------------------------------------------------------------------------
/lib/nfs/index.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var errors = require('./errors');
8 |
9 | ///--- Helpers
10 |
11 | function _export(obj) {
12 | Object.keys(obj).forEach(function (k) {
13 | module.exports[k] = obj[k];
14 | });
15 | }
16 |
17 |
18 |
19 | ///--- Exports
20 |
21 | module.exports = {
22 | handle_error: function handle_error(err, req, res, next) {
23 | req.log.warn(err, 'stat failed');
24 | switch (err.code) {
25 | case 'EACCESS':
26 | res.error(errors.NFS3ERR_ACCES);
27 | break;
28 |
29 | case 'ENOENT':
30 | res.error(errors.NFS3ERR_NOENT);
31 | break;
32 |
33 | case 'ENOTDIR':
34 | res.error(errors.NFS3ERR_NOTDIR);
35 | break;
36 |
37 | case 'ENOTEMPTY':
38 | res.error(errors.NFS3ERR_NOTEMPTY);
39 | break;
40 |
41 | default:
42 | res.error(errors.NFS3ERR_SERVERFAULT);
43 | break;
44 | }
45 | next(false);
46 | }
47 | };
48 |
49 | _export(errors);
50 | _export(require('./client'));
51 | _export(require('./server'));
52 | _export(require('./access_call'));
53 | _export(require('./access_reply'));
54 | _export(require('./create_call'));
55 | _export(require('./create_reply'));
56 | _export(require('./commit_call'));
57 | _export(require('./commit_reply'));
58 | _export(require('./fattr3'));
59 | _export(require('./fs_info_call'));
60 | _export(require('./fs_info_reply'));
61 | _export(require('./fs_stat_call'));
62 | _export(require('./fs_stat_reply'));
63 | _export(require('./get_attr_call'));
64 | _export(require('./get_attr_reply'));
65 | _export(require('./link_call'));
66 | _export(require('./link_reply'));
67 | _export(require('./lookup_call'));
68 | _export(require('./lookup_reply'));
69 | _export(require('./mkdir_call'));
70 | _export(require('./mkdir_reply'));
71 | _export(require('./mknod_call'));
72 | _export(require('./mknod_reply'));
73 | _export(require('./nfs_call'));
74 | _export(require('./nfs_reply'));
75 | _export(require('./path_conf_call'));
76 | _export(require('./path_conf_reply'));
77 | _export(require('./readdir_call'));
78 | _export(require('./readdir_reply'));
79 | _export(require('./readdirplus_call'));
80 | _export(require('./readdirplus_reply'));
81 | _export(require('./read_call'));
82 | _export(require('./read_reply'));
83 | _export(require('./readlink_call'));
84 | _export(require('./readlink_reply'));
85 | _export(require('./remove_call'));
86 | _export(require('./remove_reply'));
87 | _export(require('./rmdir_call'));
88 | _export(require('./rmdir_reply'));
89 | _export(require('./sattr3'));
90 | _export(require('./set_attr_call'));
91 | _export(require('./set_attr_reply'));
92 | _export(require('./symlink_call'));
93 | _export(require('./symlink_reply'));
94 | _export(require('./write_call'));
95 | _export(require('./write_reply'));
96 |
--------------------------------------------------------------------------------
/lib/nfs/link_call.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.15 Procedure 15: LINK - Create Link to an object
8 | //
9 | // SYNOPSIS
10 | //
11 | // LINK3res NFSPROC3_LINK(LINK3args) = 15;
12 | //
13 | // struct LINK3args {
14 | // nfs_fh3 file;
15 | // diropargs3 link;
16 | // };
17 | //
18 | // struct LINK3resok {
19 | // post_op_attr file_attributes;
20 | // wcc_data linkdir_wcc;
21 | // };
22 | //
23 | // struct LINK3resfail {
24 | // post_op_attr file_attributes;
25 | // wcc_data linkdir_wcc;
26 | // };
27 | //
28 | // union LINK3res switch (nfsstat3 status) {
29 | // case NFS3_OK:
30 | // LINK3resok resok;
31 | // default:
32 | // LINK3resfail resfail;
33 | // };
34 | //
35 | // DESCRIPTION
36 | //
37 | // Procedure LINK creates a hard link from file to link.name,
38 | // in the directory, link.dir. file and link.dir must reside
39 | // on the same file system and server. On entry, the
40 | // arguments in LINK3args are:
41 | //
42 | // file
43 | // The file handle for the existing file system object.
44 | //
45 | // link
46 | // The location of the link to be created:
47 | //
48 | // link.dir
49 | // The file handle for the directory in which the link
50 | // is to be created.
51 | //
52 | // link.name
53 | // The name that is to be associated with the created
54 | // link. Refer to General comments on filenames on page
55 | // 17.
56 | //
57 | // On successful return, LINK3res.status is NFS3_OK and
58 | // LINK3res.resok contains:
59 | //
60 | // file_attributes
61 | // The post-operation attributes of the file system object
62 | // identified by file.
63 | //
64 | // linkdir_wcc
65 | // Weak cache consistency data for the directory,
66 | // link.dir.
67 | //
68 | // Otherwise, LINK3res.status contains the error on failure
69 | // and LINK3res.resfail contains the following:
70 | //
71 | // file_attributes
72 | // The post-operation attributes of the file system object
73 | // identified by file.
74 | //
75 | // linkdir_wcc
76 | // Weak cache consistency data for the directory,
77 | // link.dir.
78 | //
79 | // IMPLEMENTATION
80 | //
81 | // Changes to any property of the hard-linked files are
82 | // reflected in all of the linked files. When a hard link is
83 | // made to a file, the attributes for the file should have a
84 | // value for nlink that is one greater than the value before
85 | // the LINK.
86 | //
87 | // The comments under RENAME regarding object and target
88 | // residing on the same file system apply here as well. The
89 | // comments regarding the target name applies as well. Refer
90 | // to General comments on filenames on page 30.
91 | //
92 | // ERRORS
93 | //
94 | // NFS3ERR_IO
95 | // NFS3ERR_ACCES
96 | // NFS3ERR_EXIST
97 | // NFS3ERR_XDEV
98 | // NFS3ERR_NOTDIR
99 | // NFS3ERR_INVAL
100 | // NFS3ERR_NOSPC
101 | // NFS3ERR_ROFS
102 | // NFS3ERR_MLINK
103 | // NFS3ERR_NAMETOOLONG
104 | // NFS3ERR_DQUOT
105 | // NFS3ERR_STALE
106 | // NFS3ERR_BADHANDLE
107 | // NFS3ERR_NOTSUPP
108 | // NFS3ERR_SERVERFAULT
109 | //
110 | // SEE ALSO
111 | //
112 | // SYMLINK, RENAME and FSINFO.
113 |
114 |
115 | var util = require('util');
116 |
117 | var assert = require('assert-plus');
118 | var rpc = require('oncrpc');
119 |
120 | var NfsCall = require('./nfs_call').NfsCall;
121 |
122 |
123 |
124 | ///--- Globals
125 |
126 | var XDR = rpc.XDR;
127 |
128 |
129 |
130 | ///--- API
131 |
132 | function LinkCall(opts) {
133 | assert.object(opts, 'opts');
134 | assert.optionalString(opts.file, 'options.file');
135 | assert.optionalObject(opts.link, 'opts.link');
136 |
137 | NfsCall.call(this, opts, true);
138 |
139 | this.file = opts.file || '';
140 | this.link = opts.link || {
141 | dir: '',
142 | name: ''
143 | };
144 |
145 | this._nfs_link_call = true; // MDB
146 | }
147 | util.inherits(LinkCall, NfsCall);
148 | Object.defineProperty(LinkCall.prototype, 'object', {
149 | get: function object() {
150 | return (this.file);
151 | }
152 | });
153 |
154 |
155 | LinkCall.prototype._transform = function _transform(chunk, enc, cb) {
156 | if (this.incoming) {
157 | var xdr = new XDR(chunk);
158 |
159 | this.file = xdr.readString();
160 | this.link.dir = xdr.readString();
161 | this.link.name = xdr.readString();
162 | } else {
163 | this.push(chunk);
164 | }
165 |
166 | cb();
167 | };
168 |
169 |
170 | LinkCall.prototype.writeHead = function writeHead() {
171 | var len = XDR.byteLength(this.file) + XDR.byteLength(this.link.dir) +
172 | XDR.byteLength(this.link.name);
173 |
174 | var xdr = this._serialize(len);
175 |
176 | xdr.writeString(this.file);
177 | xdr.writeString(this.link.dir);
178 | xdr.writeString(this.link.name);
179 |
180 | this.write(xdr.buffer());
181 | };
182 |
183 |
184 | LinkCall.prototype.toString = function toString() {
185 | var fmt = '[object LinkCall ]';
186 | return (util.format(fmt, this.xid, this.file, this.link));
187 | };
188 |
189 |
190 |
191 | ///--- Exports
192 |
193 | module.exports = {
194 | LinkCall: LinkCall
195 | };
196 |
--------------------------------------------------------------------------------
/lib/nfs/link_reply.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.15 Procedure 15: LINK - Create Link to an object
8 | //
9 | // SYNOPSIS
10 | //
11 | // LINK3res NFSPROC3_LINK(LINK3args) = 15;
12 | //
13 | // struct LINK3args {
14 | // nfs_fh3 file;
15 | // diropargs3 link;
16 | // };
17 | //
18 | // struct LINK3resok {
19 | // post_op_attr file_attributes;
20 | // wcc_data linkdir_wcc;
21 | // };
22 | //
23 | // struct LINK3resfail {
24 | // post_op_attr file_attributes;
25 | // wcc_data linkdir_wcc;
26 | // };
27 | //
28 | // union LINK3res switch (nfsstat3 status) {
29 | // case NFS3_OK:
30 | // LINK3resok resok;
31 | // default:
32 | // LINK3resfail resfail;
33 | // };
34 | //
35 | // DESCRIPTION
36 | //
37 | // Procedure LINK creates a hard link from file to link.name,
38 | // in the directory, link.dir. file and link.dir must reside
39 | // on the same file system and server. On entry, the
40 | // arguments in LINK3args are:
41 | //
42 | // file
43 | // The file handle for the existing file system object.
44 | //
45 | // link
46 | // The location of the link to be created:
47 | //
48 | // link.dir
49 | // The file handle for the directory in which the link
50 | // is to be created.
51 | //
52 | // link.name
53 | // The name that is to be associated with the created
54 | // link. Refer to General comments on filenames on page
55 | // 17.
56 | //
57 | // On successful return, LINK3res.status is NFS3_OK and
58 | // LINK3res.resok contains:
59 | //
60 | // file_attributes
61 | // The post-operation attributes of the file system object
62 | // identified by file.
63 | //
64 | // linkdir_wcc
65 | // Weak cache consistency data for the directory,
66 | // link.dir.
67 | //
68 | // Otherwise, LINK3res.status contains the error on failure
69 | // and LINK3res.resfail contains the following:
70 | //
71 | // file_attributes
72 | // The post-operation attributes of the file system object
73 | // identified by file.
74 | //
75 | // linkdir_wcc
76 | // Weak cache consistency data for the directory,
77 | // link.dir.
78 | //
79 | // IMPLEMENTATION
80 | //
81 | // Changes to any property of the hard-linked files are
82 | // reflected in all of the linked files. When a hard link is
83 | // made to a file, the attributes for the file should have a
84 | // value for nlink that is one greater than the value before
85 | // the LINK.
86 | //
87 | // The comments under RENAME regarding object and target
88 | // residing on the same file system apply here as well. The
89 | // comments regarding the target name applies as well. Refer
90 | // to General comments on filenames on page 30.
91 | //
92 | // ERRORS
93 | //
94 | // NFS3ERR_IO
95 | // NFS3ERR_ACCES
96 | // NFS3ERR_EXIST
97 | // NFS3ERR_XDEV
98 | // NFS3ERR_NOTDIR
99 | // NFS3ERR_INVAL
100 | // NFS3ERR_NOSPC
101 | // NFS3ERR_ROFS
102 | // NFS3ERR_MLINK
103 | // NFS3ERR_NAMETOOLONG
104 | // NFS3ERR_DQUOT
105 | // NFS3ERR_STALE
106 | // NFS3ERR_BADHANDLE
107 | // NFS3ERR_NOTSUPP
108 | // NFS3ERR_SERVERFAULT
109 | //
110 | // SEE ALSO
111 | //
112 | // SYMLINK, RENAME and FSINFO.
113 |
114 | var fs = require('fs');
115 | var path = require('path');
116 | var util = require('util');
117 |
118 | var assert = require('assert-plus');
119 | var clone = require('clone');
120 | var rpc = require('oncrpc');
121 |
122 | var nfs_err = require('./errors');
123 | var fattr3 = require('./fattr3');
124 | var wcc_data = require('./wcc_data');
125 | var NfsReply = require('./nfs_reply').NfsReply;
126 |
127 |
128 |
129 | ///--- Globals
130 |
131 | var XDR = rpc.XDR;
132 |
133 |
134 |
135 | ///--- API
136 |
137 | function LinkReply(opts) {
138 | NfsReply.call(this, opts);
139 |
140 | this.status = 0;
141 | this.dir_wcc = opts.dir_wcc | null;
142 |
143 | this._nfs_link_reply = true; // MDB
144 | }
145 | util.inherits(LinkReply, NfsReply);
146 | LinkReply.prototype._allowed_error_codes = [
147 | nfs_err.NFS3ERR_IO,
148 | nfs_err.NFS3ERR_ACCES,
149 | nfs_err.NFS3ERR_EXIST,
150 | nfs_err.NFS3ERR_XDEV,
151 | nfs_err.NFS3ERR_NOTDIR,
152 | nfs_err.NFS3ERR_INVAL,
153 | nfs_err.NFS3ERR_NOSPC,
154 | nfs_err.NFS3ERR_ROFS,
155 | nfs_err.NFS3ERR_MLINK,
156 | nfs_err.NFS3ERR_NAMETOOLONG,
157 | nfs_err.NFS3ERR_DQUOT,
158 | nfs_err.NFS3ERR_STALE,
159 | nfs_err.NFS3ERR_BADHANDLE,
160 | nfs_err.NFS3ERR_NOTSUPP,
161 | nfs_err.NFS3ERR_SERVERFAULT
162 | ];
163 |
164 |
165 | LinkReply.prototype.setFileAttributes = function setFileAttributes(stats) {
166 | assert.ok(stats instanceof fs.Stats, 'fs.Stats');
167 |
168 | this.file_attributes = fattr3.create(stats);
169 |
170 | return (this.file_attributes);
171 | };
172 |
173 |
174 | LinkReply.prototype.set_linkdir_wcc = function set_linkdir_wcc() {
175 | this.linkdir_wcc = wcc_data.create();
176 | return (this.linkdir_wcc);
177 | };
178 |
179 |
180 | LinkReply.prototype._transform = function _transform(chunk, enc, cb) {
181 | if (this.incoming) {
182 | var xdr = new XDR(chunk);
183 |
184 | this.status = xdr.readInt();
185 | this.fromdir_wcc = wcc_data.parse(xdr);
186 | this.todir_wcc = wcc_data.parse(xdr);
187 | } else {
188 | this.push(chunk);
189 | }
190 |
191 | cb();
192 | };
193 |
194 |
195 | LinkReply.prototype.writeHead = function writeHead() {
196 | var len = 4;
197 |
198 | if (this.file_attributes) {
199 | len += 4 + fattr3.XDR_SIZE;
200 | } else {
201 | len += 4;
202 | }
203 | len += wcc_data.length(this.linkdir_wcc);
204 |
205 | var xdr = this._serialize(len);
206 |
207 | xdr.writeInt(this.status);
208 |
209 | if (this.file_attributes) {
210 | xdr.writeBool(true);
211 | fattr3.serialize(xdr, this.file_attributes);
212 | } else {
213 | xdr.writeBool(false);
214 | }
215 |
216 | wcc_data.serialize(xdr, this.linkdir_wcc);
217 |
218 | this.write(xdr.buffer());
219 | };
220 |
221 |
222 | LinkReply.prototype.toString = function toString() {
223 | var fmt = '[object LinkReply ]';
225 | return (util.format(fmt, this.xid, this.status, this.file_attributes,
226 | this.linkdir_wcc));
227 | };
228 |
229 |
230 |
231 | ///--- Exports
232 |
233 | module.exports = {
234 | LinkReply: LinkReply
235 | };
236 |
--------------------------------------------------------------------------------
/lib/nfs/lookup_call.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.3 Procedure 3: LOOKUP - Lookup filename
8 | //
9 | // SYNOPSIS
10 | //
11 | // LOOKUP3res NFSPROC3_LOOKUP(LOOKUP3args) = 3;
12 | //
13 | // struct LOOKUP3args {
14 | // diropargs3 what;
15 | // };
16 | //
17 | // struct LOOKUP3resok {
18 | // nfs_fh3 object;
19 | // post_op_attr obj_attributes;
20 | // post_op_attr dir_attributes;
21 | // };
22 | //
23 | // struct LOOKUP3resfail {
24 | // post_op_attr dir_attributes;
25 | // };
26 | //
27 | // union LOOKUP3res switch (nfsstat3 status) {
28 | // case NFS3_OK:
29 | // LOOKUP3resok resok;
30 | // default:
31 | // LOOKUP3resfail resfail;
32 | // };
33 | //
34 | // DESCRIPTION
35 | //
36 | // Procedure LOOKUP searches a directory for a specific name
37 | // and returns the file handle for the corresponding file
38 | // system object. On entry, the arguments in LOOKUP3args
39 | // are:
40 | //
41 | // what
42 | // Object to look up:
43 | //
44 | // dir
45 | // The file handle for the directory to search.
46 | //
47 | // name
48 | // The filename to be searched for. Refer to General
49 | // comments on filenames on page 30.
50 | //
51 | // On successful return, LOOKUP3res.status is NFS3_OK and
52 | // LOOKUP3res.resok contains:
53 | //
54 | // object
55 | // The file handle of the object corresponding to
56 | // what.name.
57 | //
58 | // obj_attributes
59 | // The attributes of the object corresponding to
60 | // what.name.
61 | //
62 | // dir_attributes
63 | // The post-operation attributes of the directory,
64 | // what.dir.
65 | //
66 | // Otherwise, LOOKUP3res.status contains the error on failure and
67 | // LOOKUP3res.resfail contains the following:
68 | //
69 | // dir_attributes
70 | // The post-operation attributes for the directory,
71 | // what.dir.
72 | //
73 | // IMPLEMENTATION
74 | //
75 | // At first glance, in the case where what.name refers to a
76 | // mount point on the server, two different replies seem
77 | // possible. The server can return either the file handle for
78 | // the underlying directory that is mounted on or the file
79 | // handle of the root of the mounted directory. This
80 | // ambiguity is simply resolved. A server will not allow a
81 | // LOOKUP operation to cross a mountpoint to the root of a
82 | // different filesystem, even if the filesystem is exported.
83 | // This does not prevent a client from accessing a hierarchy
84 | // of filesystems exported by a server, but the client must
85 | // mount each of the filesystems individually so that the
86 | // mountpoint crossing takes place on the client. A given
87 | // server implementation may refine these rules given
88 | // capabilities or limitations particular to that
89 | // implementation. Refer to [X/OpenNFS] for a discussion on
90 | // exporting file systems.
91 | //
92 | // Two filenames are distinguished, as in the NFS version 2
93 | // protocol. The name, ".", is an alias for the current
94 | // directory and the name, "..", is an alias for the parent
95 | // directory; that is, the directory that includes the
96 | // specified directory as a member. There is no facility for
97 | // dealing with a multiparented directory and the NFS
98 | // protocol assumes a hierarchical organization, organized as
99 | // a single-rooted tree.
100 | // Note that this procedure does not follow symbolic links.
101 | // The client is responsible for all parsing of filenames
102 | // including filenames that are modified by symbolic links
103 | // encountered during the lookup process.
104 | //
105 | // ERRORS
106 | //
107 | // NFS3ERR_IO
108 | // NFS3ERR_NOENT
109 | // NFS3ERR_ACCES
110 | // NFS3ERR_NOTDIR
111 | // NFS3ERR_NAMETOOLONG
112 | // NFS3ERR_STALE
113 | // NFS3ERR_BADHANDLE
114 | // NFS3ERR_SERVERFAULT
115 | //
116 | // SEE ALSO
117 | //
118 | // CREATE, MKDIR, SYMLINK, MKNOD, READDIRPLUS, and PATHCONF.
119 |
120 | var path = require('path');
121 | var util = require('util');
122 |
123 | var assert = require('assert-plus');
124 | var rpc = require('oncrpc');
125 |
126 | var NfsCall = require('./nfs_call').NfsCall;
127 |
128 |
129 |
130 | ///--- Globals
131 |
132 | var XDR = rpc.XDR;
133 |
134 |
135 |
136 | ///--- API
137 |
138 | function LookupCall(opts) {
139 | assert.object(opts, 'opts');
140 | assert.optionalObject(opts.what, 'opts.what');
141 |
142 | NfsCall.call(this, opts, true);
143 |
144 | this.what = opts.what || {
145 | dir: '',
146 | name: ''
147 | };
148 |
149 | this._nfs_lookup_call = true; // MDB
150 | }
151 | util.inherits(LookupCall, NfsCall);
152 | Object.defineProperty(LookupCall.prototype, 'object', {
153 | get: function object() {
154 | return (this.what.dir);
155 | }
156 | });
157 |
158 |
159 | LookupCall.prototype._transform = function _transform(chunk, enc, cb) {
160 | if (this.incoming) {
161 | var xdr = new XDR(chunk);
162 | this.what.dir = xdr.readString();
163 | this.what.name = xdr.readString();
164 | } else {
165 | this.push(chunk);
166 | }
167 |
168 | cb();
169 | };
170 |
171 |
172 | LookupCall.prototype.writeHead = function writeHead() {
173 | var xdr = this._serialize(XDR.byteLength(this.what.dir) +
174 | XDR.byteLength(this.what.name));
175 | xdr.writeString(this.what.dir);
176 | xdr.writeString(this.what.name);
177 |
178 | this.write(xdr.buffer());
179 | };
180 |
181 |
182 | LookupCall.prototype.toString = function toString() {
183 | var fmt = '[object LookupCall ]';
184 | return (util.format(fmt, this.xid, this.what));
185 | };
186 |
187 |
188 |
189 | ///--- Exports
190 |
191 | module.exports = {
192 | LookupCall: LookupCall
193 | };
194 |
--------------------------------------------------------------------------------
/lib/nfs/mkdir_call.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.9 Procedure 9: MKDIR - Create a directory
8 | //
9 | // SYNOPSIS
10 | //
11 | // MKDIR3res NFSPROC3_MKDIR(MKDIR3args) = 9;
12 | //
13 | // struct MKDIR3args {
14 | // diropargs3 where;
15 | // sattr3 attributes;
16 | // };
17 | //
18 | // struct MKDIR3resok {
19 | // post_op_fh3 obj;
20 | // post_op_attr obj_attributes;
21 | // wcc_data dir_wcc;
22 | // };
23 | //
24 | // struct MKDIR3resfail {
25 | // wcc_data dir_wcc;
26 | // };
27 | //
28 | // union MKDIR3res switch (nfsstat3 status) {
29 | // case NFS3_OK:
30 | // MKDIR3resok resok;
31 | // default:
32 | // MKDIR3resfail resfail;
33 | // };
34 | //
35 | // DESCRIPTION
36 | //
37 | // Procedure MKDIR creates a new subdirectory. On entry, the
38 | // arguments in MKDIR3args are:
39 | //
40 | // where
41 | // The location of the subdirectory to be created:
42 | //
43 | // dir
44 | // The file handle for the directory in which the
45 | // subdirectory is to be created.
46 | //
47 | // name
48 | // The name that is to be associated with the created
49 | // subdirectory. Refer to General comments on filenames
50 | // on page 30.
51 | //
52 | // attributes
53 | // The initial attributes for the subdirectory.
54 | //
55 | // On successful return, MKDIR3res.status is NFS3_OK and the
56 | // results in MKDIR3res.resok are:
57 | //
58 | // obj
59 | // The file handle for the newly created directory.
60 | //
61 | // obj_attributes
62 | // The attributes for the newly created subdirectory.
63 | //
64 | // dir_wcc
65 | // Weak cache consistency data for the directory,
66 | // where.dir. For a client that requires only the
67 | // post-MKDIR directory attributes, these can be found in
68 | // dir_wcc.after.
69 | //
70 | // Otherwise, MKDIR3res.status contains the error on failure
71 | // and MKDIR3res.resfail contains the following:
72 | //
73 | // dir_wcc
74 | // Weak cache consistency data for the directory,
75 | // where.dir. For a client that requires only the
76 | // post-MKDIR directory attributes, these can be found in
77 | // dir_wcc.after. Even though the MKDIR failed, full
78 | // wcc_data is returned to allow the client to determine
79 | // whether the failing MKDIR resulted in any change to the
80 | // directory.
81 | //
82 | // IMPLEMENTATION
83 | //
84 | // Many server implementations will not allow the filenames,
85 | // "." or "..", to be used as targets in a MKDIR operation.
86 | // In this case, the server should return NFS3ERR_EXIST.
87 | // Refer to General comments on filenames on page 30.
88 | //
89 | // ERRORS
90 | //
91 | // NFS3ERR_IO
92 | // NFS3ERR_ACCES
93 | // NFS3ERR_EXIST
94 | // NFS3ERR_NOTDIR
95 | // NFS3ERR_NOSPC
96 | // NFS3ERR_ROFS
97 | // NFS3ERR_NAMETOOLONG
98 | // NFS3ERR_DQUOT
99 | // NFS3ERR_STALE
100 | // NFS3ERR_BADHANDLE
101 | // NFS3ERR_NOTSUPP
102 | // NFS3ERR_SERVERFAULT
103 | //
104 | // SEE ALSO
105 | //
106 | // CREATE, SYMLINK, MKNOD, and PATHCONF.
107 |
108 |
109 | var util = require('util');
110 |
111 | var assert = require('assert-plus');
112 | var rpc = require('oncrpc');
113 |
114 | var sattr3 = require('./sattr3');
115 |
116 | var NfsCall = require('./nfs_call').NfsCall;
117 |
118 |
119 |
120 | ///--- Globals
121 |
122 | var XDR = rpc.XDR;
123 |
124 |
125 |
126 | ///--- API
127 |
128 | function MkdirCall(opts) {
129 | assert.object(opts, 'opts');
130 | assert.optionalObject(opts.where, 'opts.where');
131 | assert.optionalObject(opts.attributes, 'opts.attributes');
132 |
133 | NfsCall.call(this, opts, true);
134 |
135 | this.where = opts.where || {
136 | dir: '',
137 | name: ''
138 | };
139 |
140 | this.attributes = opts.attributes || {
141 | mode: null,
142 | uid: null,
143 | gid: null,
144 | size: null,
145 | how_a_time: 0,
146 | atime: null,
147 | how_m_time: 0,
148 | mtime: null
149 | };
150 |
151 | this._nfs_mkdir_call = true; // MDB
152 | }
153 | util.inherits(MkdirCall, NfsCall);
154 | Object.defineProperty(MkdirCall.prototype, 'object', {
155 | get: function object() {
156 | return (this.where.dir);
157 | }
158 | });
159 |
160 |
161 | MkdirCall.prototype._transform = function _transform(chunk, enc, cb) {
162 | if (this.incoming) {
163 | var xdr = new XDR(chunk);
164 | this.where.dir = xdr.readString();
165 | this.where.name = xdr.readString();
166 | this.attributes = sattr3.parse(xdr);
167 | } else {
168 | this.push(chunk);
169 | }
170 |
171 | cb();
172 | };
173 |
174 |
175 | MkdirCall.prototype.writeHead = function writeHead() {
176 | var len = XDR.byteLength(this.where.dir) + XDR.byteLength(this.where.name);
177 |
178 | len += sattr3.length(this.attributes);
179 |
180 | var xdr = this._serialize(len);
181 |
182 | xdr.writeString(this.where.dir);
183 | xdr.writeString(this.where.name);
184 |
185 | sattr3.serialize(xdr, this.attributes);
186 |
187 | this.write(xdr.buffer());
188 | };
189 |
190 |
191 | MkdirCall.prototype.toString = function toString() {
192 | var fmt = '[object MkdirCall ]';
193 | return (util.format(fmt, this.xid, this.where, this.attributes));
194 | };
195 |
196 |
197 |
198 | ///--- Exports
199 |
200 | module.exports = {
201 | MkdirCall: MkdirCall
202 | };
203 |
--------------------------------------------------------------------------------
/lib/nfs/mkdir_reply.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.9 Procedure 9: MKDIR - Create a directory
8 | //
9 | // SYNOPSIS
10 | //
11 | // MKDIR3res NFSPROC3_MKDIR(MKDIR3args) = 9;
12 | //
13 | // struct MKDIR3args {
14 | // diropargs3 where;
15 | // sattr3 attributes;
16 | // };
17 | //
18 | // struct MKDIR3resok {
19 | // post_op_fh3 obj;
20 | // post_op_attr obj_attributes;
21 | // wcc_data dir_wcc;
22 | // };
23 | //
24 | // struct MKDIR3resfail {
25 | // wcc_data dir_wcc;
26 | // };
27 | //
28 | // union MKDIR3res switch (nfsstat3 status) {
29 | // case NFS3_OK:
30 | // MKDIR3resok resok;
31 | // default:
32 | // MKDIR3resfail resfail;
33 | // };
34 | //
35 | // DESCRIPTION
36 | //
37 | // Procedure MKDIR creates a new subdirectory. On entry, the
38 | // arguments in MKDIR3args are:
39 | //
40 | // where
41 | // The location of the subdirectory to be created:
42 | //
43 | // dir
44 | // The file handle for the directory in which the
45 | // subdirectory is to be created.
46 | //
47 | // name
48 | // The name that is to be associated with the created
49 | // subdirectory. Refer to General comments on filenames
50 | // on page 30.
51 | //
52 | // attributes
53 | // The initial attributes for the subdirectory.
54 | //
55 | // On successful return, MKDIR3res.status is NFS3_OK and the
56 | // results in MKDIR3res.resok are:
57 | //
58 | // obj
59 | // The file handle for the newly created directory.
60 | //
61 | // obj_attributes
62 | // The attributes for the newly created subdirectory.
63 | //
64 | // dir_wcc
65 | // Weak cache consistency data for the directory,
66 | // where.dir. For a client that requires only the
67 | // post-MKDIR directory attributes, these can be found in
68 | // dir_wcc.after.
69 | //
70 | // Otherwise, MKDIR3res.status contains the error on failure
71 | // and MKDIR3res.resfail contains the following:
72 | //
73 | // dir_wcc
74 | // Weak cache consistency data for the directory,
75 | // where.dir. For a client that requires only the
76 | // post-MKDIR directory attributes, these can be found in
77 | // dir_wcc.after. Even though the MKDIR failed, full
78 | // wcc_data is returned to allow the client to determine
79 | // whether the failing MKDIR resulted in any change to the
80 | // directory.
81 | //
82 | // IMPLEMENTATION
83 | //
84 | // Many server implementations will not allow the filenames,
85 | // "." or "..", to be used as targets in a MKDIR operation.
86 | // In this case, the server should return NFS3ERR_EXIST.
87 | // Refer to General comments on filenames on page 30.
88 | //
89 | // ERRORS
90 | //
91 | // NFS3ERR_IO
92 | // NFS3ERR_ACCES
93 | // NFS3ERR_EXIST
94 | // NFS3ERR_NOTDIR
95 | // NFS3ERR_NOSPC
96 | // NFS3ERR_ROFS
97 | // NFS3ERR_NAMETOOLONG
98 | // NFS3ERR_DQUOT
99 | // NFS3ERR_STALE
100 | // NFS3ERR_BADHANDLE
101 | // NFS3ERR_NOTSUPP
102 | // NFS3ERR_SERVERFAULT
103 | //
104 | // SEE ALSO
105 | //
106 | // CREATE, SYMLINK, MKNOD, and PATHCONF.
107 |
108 | var fs = require('fs');
109 | var path = require('path');
110 | var util = require('util');
111 |
112 | var assert = require('assert-plus');
113 | var clone = require('clone');
114 | var rpc = require('oncrpc');
115 |
116 | var nfs_err = require('./errors');
117 | var fattr3 = require('./fattr3');
118 | var wcc_data = require('./wcc_data');
119 | var NfsReply = require('./nfs_reply').NfsReply;
120 |
121 |
122 |
123 | ///--- Globals
124 |
125 | var XDR = rpc.XDR;
126 |
127 |
128 |
129 | ///--- API
130 |
131 | function MkdirReply(opts) {
132 | NfsReply.call(this, opts);
133 |
134 | this.status = 0;
135 | this.obj = '';
136 | this.obj_attributes = opts.obj_attributes | null;
137 | this.dir_wcc = opts.dir_wcc | null;
138 |
139 | this._nfs_mkdir_reply = true; // MDB
140 | }
141 | util.inherits(MkdirReply, NfsReply);
142 | MkdirReply.prototype._allowed_error_codes = [
143 | nfs_err.NFS3ERR_IO,
144 | nfs_err.NFS3ERR_ACCES,
145 | nfs_err.NFS3ERR_EXIST,
146 | nfs_err.NFS3ERR_NOTDIR,
147 | nfs_err.NFS3ERR_NOSPC,
148 | nfs_err.NFS3ERR_ROFS,
149 | nfs_err.NFS3ERR_NAMETOOLONG,
150 | nfs_err.NFS3ERR_DQUOT,
151 | nfs_err.NFS3ERR_STALE,
152 | nfs_err.NFS3ERR_BADHANDLE,
153 | nfs_err.NFS3ERR_NOTSUPP,
154 | nfs_err.NFS3ERR_SERVERFAULT
155 | ];
156 |
157 |
158 | MkdirReply.prototype.setObjAttributes = function setObjAttributes(stats) {
159 | assert.ok(stats instanceof fs.Stats, 'fs.Stats');
160 |
161 | this.obj_attributes = fattr3.create(stats);
162 |
163 | return (this.obj_attributes);
164 | };
165 |
166 |
167 | MkdirReply.prototype.set_dir_wcc = function set_dir_wcc() {
168 | this.dir_wcc = wcc_data.create();
169 | return (this.dir_wcc);
170 | };
171 |
172 |
173 | MkdirReply.prototype._transform = function _transform(chunk, enc, cb) {
174 | if (this.incoming) {
175 | var xdr = new XDR(chunk);
176 |
177 | this.status = xdr.readInt();
178 | if (this.status === 0) {
179 | if (xdr.readBool())
180 | this.obj = xdr.readString();
181 | if (xdr.readBool())
182 | this.obj_attributes = fattr3.parse(xdr);
183 | }
184 |
185 | this.dir_wcc = wcc_data.parse(xdr);
186 | } else {
187 | this.push(chunk);
188 | }
189 |
190 | cb();
191 | };
192 |
193 |
194 | MkdirReply.prototype.writeHead = function writeHead() {
195 | var len = 4;
196 |
197 | if (this.status === 0) {
198 | len += 4 + XDR.byteLength(this.obj);
199 |
200 | len += 4;
201 | if (this.obj_attributes)
202 | len += fattr3.XDR_SIZE;
203 | }
204 |
205 | len += wcc_data.length(this.dir_wcc);
206 |
207 | var xdr = this._serialize(len);
208 |
209 | xdr.writeInt(this.status);
210 |
211 | if (this.status === 0) {
212 | xdr.writeBool(true);
213 | xdr.writeString(this.obj);
214 | if (this.obj_attributes) {
215 | xdr.writeBool(true);
216 | fattr3.serialize(xdr, this.obj_attributes);
217 | } else {
218 | xdr.writeBool(false);
219 | }
220 | }
221 |
222 | wcc_data.serialize(xdr, this.dir_wcc);
223 |
224 | this.write(xdr.buffer());
225 | };
226 |
227 |
228 | MkdirReply.prototype.toString = function toString() {
229 | var fmt = '[object MkdirReply ]';
231 | return (util.format(fmt, this.xid, this.status, this.obj,
232 | this.obj_attributes, this.dir_wcc));
233 | };
234 |
235 |
236 |
237 | ///--- Exports
238 |
239 | module.exports = {
240 | MkdirReply: MkdirReply
241 | };
242 |
--------------------------------------------------------------------------------
/lib/nfs/nfs_call.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var util = require('util');
8 |
9 | var assert = require('assert-plus');
10 | var RpcCall = require('oncrpc').RpcCall;
11 |
12 |
13 |
14 | ///--- API
15 |
16 | function NfsCall(opts) {
17 | assert.object(opts, 'options');
18 |
19 | RpcCall.call(this, opts);
20 |
21 | this._nfs_call = true; // MDB
22 | }
23 | util.inherits(NfsCall, RpcCall);
24 | Object.defineProperty(NfsCall.prototype, 'object', {
25 | get: function object() {
26 | throw new Error('get: object must be defined');
27 | }
28 | });
29 |
30 |
31 |
32 | ///--- Exports
33 |
34 | module.exports = {
35 | NfsCall: NfsCall
36 | };
37 |
--------------------------------------------------------------------------------
/lib/nfs/nfs_reply.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var util = require('util');
8 |
9 | var assert = require('assert-plus');
10 | var RpcReply = require('oncrpc').RpcReply;
11 |
12 |
13 |
14 | ///--- API
15 |
16 | function NfsReply(opts) {
17 | assert.object(opts, 'options');
18 |
19 | RpcReply.call(this, opts);
20 |
21 | this._nfs_reply = true; // MDB
22 | }
23 | util.inherits(NfsReply, RpcReply);
24 |
25 |
26 | NfsReply.prototype.error = function error(status) {
27 | assert.number(status, 'status');
28 |
29 | if (!Array.isArray(this._allowed_error_codes))
30 | throw new Error('this._allowed_error_codes must be defined');
31 |
32 | if (!this._allowed_error_codes.some(function (c) {
33 | return (c === status);
34 | })) {
35 | throw new Error(status + ' is not an allowed status code');
36 | }
37 |
38 | this.status = status;
39 | this.send();
40 | };
41 |
42 |
43 |
44 | ///--- Exports
45 |
46 | module.exports = {
47 | NfsReply: NfsReply
48 | };
49 |
--------------------------------------------------------------------------------
/lib/nfs/path_conf_call.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.20 Procedure 20: PATHCONF - Retrieve POSIX information
8 | //
9 | // SYNOPSIS
10 | //
11 | // PATHCONF3res NFSPROC3_PATHCONF(PATHCONF3args) = 20;
12 | //
13 | // struct PATHCONF3args {
14 | // nfs_fh3 object;
15 | // };
16 | //
17 | // struct PATHCONF3resok {
18 | // post_op_attr obj_attributes;
19 | // uint32 linkmax;
20 | // uint32 name_max;
21 | // bool no_trunc;
22 | // bool chown_restricted;
23 | // bool case_insensitive;
24 | // bool case_preserving;
25 | // };
26 | //
27 | // struct PATHCONF3resfail {
28 | // post_op_attr obj_attributes;
29 | // };
30 | //
31 | // union PATHCONF3res switch (nfsstat3 status) {
32 | // case NFS3_OK:
33 | // PATHCONF3resok resok;
34 | // default:
35 | // PATHCONF3resfail resfail;
36 | // };
37 | //
38 | // DESCRIPTION
39 | //
40 | // Procedure PATHCONF retrieves the pathconf information for
41 | // a file or directory. If the FSF_HOMOGENEOUS bit is set in
42 | // FSFINFO3resok.properties, the pathconf information will be
43 | // the same for all files and directories in the exported
44 | // file system in which this file or directory resides. On
45 | // entry, the arguments in PATHCONF3args are:
46 | //
47 | // object
48 | // The file handle for the file system object.
49 | //
50 | // On successful return, PATHCONF3res.status is NFS3_OK and
51 | // PATHCONF3res.resok contains:
52 | //
53 | // obj_attributes
54 | // The attributes of the object specified by object.
55 | //
56 | // linkmax
57 | // The maximum number of hard links to an object.
58 | //
59 | // name_max
60 | // The maximum length of a component of a filename.
61 | //
62 | // no_trunc
63 | // If TRUE, the server will reject any request that
64 | // includes a name longer than name_max with the error,
65 | // NFS3ERR_NAMETOOLONG. If FALSE, any length name over
66 | // name_max bytes will be silently truncated to name_max
67 | // bytes.
68 | //
69 | // chown_restricted
70 | // If TRUE, the server will reject any request to change
71 | // either the owner or the group associated with a file if
72 | // the caller is not the privileged user. (Uid 0.)
73 | //
74 | // case_insensitive
75 | // If TRUE, the server file system does not distinguish
76 | // case when interpreting filenames.
77 | //
78 | // case_preserving
79 | // If TRUE, the server file system will preserve the case
80 | // of a name during a CREATE, MKDIR, MKNOD, SYMLINK,
81 | // RENAME, or LINK operation.
82 | //
83 | // Otherwise, PATHCONF3res.status contains the error on
84 | // failure and PATHCONF3res.resfail contains the following:
85 | // obj_attributes
86 | // The attributes of the object specified by object.
87 | //
88 | // IMPLEMENTATION
89 | //
90 | // In some implementations of the NFS version 2 protocol,
91 | // pathconf information was obtained at mount time through
92 | // the MOUNT protocol. The proper place to obtain it, is as
93 | // here, in the NFS version 3 protocol itself.
94 | //
95 | // ERRORS
96 | //
97 | // NFS3ERR_STALE
98 | // NFS3ERR_BADHANDLE
99 | // NFS3ERR_SERVERFAULT
100 | //
101 | // SEE ALSO
102 | //
103 | // LOOKUP, CREATE, MKDIR, SYMLINK, MKNOD, RENAME, LINK and FSINFO.
104 |
105 | var util = require('util');
106 |
107 | var assert = require('assert-plus');
108 | var rpc = require('oncrpc');
109 |
110 | var NfsCall = require('./nfs_call').NfsCall;
111 |
112 |
113 |
114 | ///--- Globals
115 |
116 | var XDR = rpc.XDR;
117 |
118 |
119 |
120 | ///--- API
121 |
122 | function PathConfCall(opts) {
123 | NfsCall.call(this, opts, true);
124 |
125 | this._object = '';
126 |
127 | this._nfs_path_conf_call = true; // MDB
128 | }
129 | util.inherits(PathConfCall, NfsCall);
130 | Object.defineProperty(PathConfCall.prototype, 'object', {
131 | get: function object() {
132 | return (this._object);
133 | }
134 | });
135 |
136 |
137 | PathConfCall.prototype._transform = function _transform(chunk, enc, cb) {
138 | if (this.incoming) {
139 | var xdr = new XDR(chunk);
140 | this._object = xdr.readString();
141 | } else {
142 | this.push(chunk);
143 | }
144 |
145 | cb();
146 | };
147 |
148 |
149 | PathConfCall.prototype.writeHead = function writeHead() {
150 | var xdr = this._serialize(XDR.byteLength(this._object));
151 | xdr.writeString(this._object);
152 |
153 | this.write(xdr.buffer());
154 | };
155 |
156 |
157 | PathConfCall.prototype.toString = function toString() {
158 | var fmt = '[object PathConfCall ]';
159 | return (util.format(fmt, this.xid, this._object));
160 | };
161 |
162 |
163 |
164 | ///--- Exports
165 |
166 | module.exports = {
167 | PathConfCall: PathConfCall
168 | };
169 |
--------------------------------------------------------------------------------
/lib/nfs/path_conf_reply.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.20 Procedure 20: PATHCONF - Retrieve POSIX information
8 | //
9 | // SYNOPSIS
10 | //
11 | // PATHCONF3res NFSPROC3_PATHCONF(PATHCONF3args) = 20;
12 | //
13 | // struct PATHCONF3args {
14 | // nfs_fh3 object;
15 | // };
16 | //
17 | // struct PATHCONF3resok {
18 | // post_op_attr obj_attributes;
19 | // uint32 linkmax;
20 | // uint32 name_max;
21 | // bool no_trunc;
22 | // bool chown_restricted;
23 | // bool case_insensitive;
24 | // bool case_preserving;
25 | // };
26 | //
27 | // struct PATHCONF3resfail {
28 | // post_op_attr obj_attributes;
29 | // };
30 | //
31 | // union PATHCONF3res switch (nfsstat3 status) {
32 | // case NFS3_OK:
33 | // PATHCONF3resok resok;
34 | // default:
35 | // PATHCONF3resfail resfail;
36 | // };
37 | //
38 | // DESCRIPTION
39 | //
40 | // Procedure PATHCONF retrieves the pathconf information for
41 | // a file or directory. If the FSF_HOMOGENEOUS bit is set in
42 | // FSFINFO3resok.properties, the pathconf information will be
43 | // the same for all files and directories in the exported
44 | // file system in which this file or directory resides. On
45 | // entry, the arguments in PATHCONF3args are:
46 | //
47 | // object
48 | // The file handle for the file system object.
49 | //
50 | // On successful return, PATHCONF3res.status is NFS3_OK and
51 | // PATHCONF3res.resok contains:
52 | //
53 | // obj_attributes
54 | // The attributes of the object specified by object.
55 | //
56 | // linkmax
57 | // The maximum number of hard links to an object.
58 | //
59 | // name_max
60 | // The maximum length of a component of a filename.
61 | //
62 | // no_trunc
63 | // If TRUE, the server will reject any request that
64 | // includes a name longer than name_max with the error,
65 | // NFS3ERR_NAMETOOLONG. If FALSE, any length name over
66 | // name_max bytes will be silently truncated to name_max
67 | // bytes.
68 | //
69 | // chown_restricted
70 | // If TRUE, the server will reject any request to change
71 | // either the owner or the group associated with a file if
72 | // the caller is not the privileged user. (Uid 0.)
73 | //
74 | // case_insensitive
75 | // If TRUE, the server file system does not distinguish
76 | // case when interpreting filenames.
77 | //
78 | // case_preserving
79 | // If TRUE, the server file system will preserve the case
80 | // of a name during a CREATE, MKDIR, MKNOD, SYMLINK,
81 | // RENAME, or LINK operation.
82 | //
83 | // Otherwise, PATHCONF3res.status contains the error on
84 | // failure and PATHCONF3res.resfail contains the following:
85 | // obj_attributes
86 | // The attributes of the object specified by object.
87 | //
88 | // IMPLEMENTATION
89 | //
90 | // In some implementations of the NFS version 2 protocol,
91 | // pathconf information was obtained at mount time through
92 | // the MOUNT protocol. The proper place to obtain it, is as
93 | // here, in the NFS version 3 protocol itself.
94 | //
95 | // ERRORS
96 | //
97 | // NFS3ERR_STALE
98 | // NFS3ERR_BADHANDLE
99 | // NFS3ERR_SERVERFAULT
100 | //
101 | // SEE ALSO
102 | //
103 | // LOOKUP, CREATE, MKDIR, SYMLINK, MKNOD, RENAME, LINK and FSINFO.
104 |
105 | var fs = require('fs');
106 | var util = require('util');
107 |
108 | var assert = require('assert-plus');
109 | var clone = require('clone');
110 | var rpc = require('oncrpc');
111 |
112 | var nfs_err = require('./errors');
113 | var fattr3 = require('./fattr3');
114 | var NfsReply = require('./nfs_reply').NfsReply;
115 |
116 |
117 |
118 | ///--- Globals
119 |
120 | var XDR = rpc.XDR;
121 |
122 |
123 |
124 | ///--- API
125 |
126 | function PathConfReply(opts) {
127 | NfsReply.call(this, opts);
128 |
129 | this.status = 0;
130 | this.obj_attributes = null;
131 | this.linkmax = 0;
132 | this.name_max = 0;
133 | this.no_trunc = true;
134 | this.chown_restricted = true;
135 | this.case_insensitive = false;
136 | this.case_preserving = true;
137 |
138 | this._nfs_path_conf_reply = true; // MDB
139 | }
140 | util.inherits(PathConfReply, NfsReply);
141 | PathConfReply.prototype._allowed_error_codes = [
142 | nfs_err.NFS3ERR_STALE,
143 | nfs_err.NFS3ERR_BADHANDLE,
144 | nfs_err.NFS3ERR_SERVERFAULT
145 | ];
146 |
147 |
148 | PathConfReply.prototype.setAttributes = function setAttributes(stats) {
149 | assert.ok(stats instanceof fs.Stats, 'fs.Stats');
150 |
151 | this.obj_attributes = fattr3.create(stats);
152 |
153 | return (this.obj_attributes);
154 | };
155 |
156 |
157 | PathConfReply.prototype._transform = function _transform(chunk, enc, cb) {
158 | if (this.incoming) {
159 | var xdr = new XDR(chunk);
160 |
161 | this.status = xdr.readInt();
162 | if (this.status === 0) {
163 | if (xdr.readBool())
164 | this.obj_attributes = fattr3.parse(xdr);
165 |
166 | this.linkmax = xdr.readInt();
167 | this.name_max = xdr.readInt();
168 | this.no_trunc = xdr.readBool();
169 | this.chown_restricted = xdr.readBool();
170 | this.case_insensitive = xdr.readBool();
171 | this.case_preserving = xdr.readBool();
172 | }
173 | } else {
174 | this.push(chunk);
175 | }
176 |
177 | cb();
178 | };
179 |
180 |
181 | PathConfReply.prototype.writeHead = function writeHead() {
182 | var len = 8;
183 | if (this.status === 0)
184 | len += fattr3.XDR_SIZE + 24;
185 |
186 | var xdr = this._serialize(len);
187 |
188 | xdr.writeInt(this.status);
189 |
190 | if (this.obj_attributes) {
191 | xdr.writeBool(true);
192 | fattr3.serialize(xdr, this.obj_attributes);
193 | } else {
194 | xdr.writeBool(false);
195 | }
196 |
197 | if (this.status === 0) {
198 | xdr.writeInt(this.linkmax);
199 | xdr.writeInt(this.name_max);
200 | xdr.writeBool(this.no_trunc);
201 | xdr.writeBool(this.chown_restricted);
202 | xdr.writeBool(this.case_insensitive);
203 | xdr.writeBool(this.case_preserving);
204 | }
205 |
206 | this.write(xdr.buffer());
207 | };
208 |
209 |
210 | PathConfReply.prototype.toString = function toString() {
211 | var fmt = '[object PathConfReply ]';
214 | return (util.format(fmt,
215 | this.xid,
216 | this.status,
217 | this.obj_attributes,
218 | this.linkmax,
219 | this.name_max,
220 | this.no_trunc,
221 | this.chown_restricted,
222 | this.case_insensitive,
223 | this.case_preserving));
224 | };
225 |
226 |
227 |
228 | ///--- Exports
229 |
230 | module.exports = {
231 | PathConfReply: PathConfReply
232 | };
233 |
--------------------------------------------------------------------------------
/lib/nfs/read_call.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.6 Procedure 6: READ - Read From file
8 | //
9 | // SYNOPSIS
10 | //
11 | // READ3res NFSPROC3_READ(READ3args) = 6;
12 | //
13 | // struct READ3args {
14 | // nfs_fh3 file;
15 | // offset3 offset;
16 | // count3 count;
17 | // };
18 | //
19 | // struct READ3resok {
20 | // post_op_attr file_attributes;
21 | // count3 count;
22 | // bool eof;
23 | // opaque data<>;
24 | // };
25 | //
26 | // struct READ3resfail {
27 | // post_op_attr file_attributes;
28 | // };
29 | //
30 | // union READ3res switch (nfsstat3 status) {
31 | // case NFS3_OK:
32 | // READ3resok resok;
33 | // default:
34 | // READ3resfail resfail;
35 | // };
36 | //
37 | // DESCRIPTION
38 | //
39 | // Procedure READ reads data from a file. On entry, the
40 | // arguments in READ3args are:
41 | //
42 | // file
43 | // The file handle of the file from which data is to be
44 | // read. This must identify a file system object of type,
45 | // NF3REG.
46 | //
47 | // offset
48 | // The position within the file at which the read is to
49 | // begin. An offset of 0 means to read data starting at
50 | // the beginning of the file. If offset is greater than or
51 | // equal to the size of the file, the status, NFS3_OK, is
52 | // returned with count set to 0 and eof set to TRUE,
53 | // subject to access permissions checking.
54 | //
55 | // count
56 | // The number of bytes of data that are to be read. If
57 | // count is 0, the READ will succeed and return 0 bytes of
58 | // data, subject to access permissions checking. count
59 | // must be less than or equal to the value of the rtmax
60 | // field in the FSINFO reply structure for the file system
61 | // that contains file. If greater, the server may return
62 | // only rtmax bytes, resulting in a short read.
63 | //
64 | // On successful return, READ3res.status is NFS3_OK and
65 | // READ3res.resok contains:
66 | //
67 | // file_attributes
68 | // The attributes of the file on completion of the read.
69 | //
70 | // count
71 | // The number of bytes of data returned by the read.
72 | //
73 | // eof
74 | // If the read ended at the end-of-file (formally, in a
75 | // correctly formed READ request, if READ3args.offset plus
76 | // READ3resok.count is equal to the size of the file), eof
77 | // is returned as TRUE; otherwise it is FALSE. A
78 | // successful READ of an empty file will always return eof
79 | // as TRUE.
80 | //
81 | // data
82 | // The counted data read from the file.
83 | //
84 | // Otherwise, READ3res.status contains the error on failure
85 | // and READ3res.resfail contains the following:
86 | //
87 | // file_attributes
88 | // The post-operation attributes of the file.
89 | //
90 | // IMPLEMENTATION
91 | //
92 | // The nfsdata type used for the READ and WRITE operations in
93 | // the NFS version 2 protocol defining the data portion of a
94 | // request or reply has been changed to a variable-length
95 | // opaque byte array. The maximum size allowed by the
96 | // protocol is now limited by what XDR and underlying
97 | // transports will allow. There are no artificial limits
98 | // imposed by the NFS version 3 protocol. Consult the FSINFO
99 | // procedure description for details.
100 | //
101 | // It is possible for the server to return fewer than count
102 | // bytes of data. If the server returns less than the count
103 | // requested and eof set to FALSE, the client should issue
104 | // another READ to get the remaining data. A server may
105 | // return less data than requested under several
106 | // circumstances. The file may have been truncated by another
107 | // client or perhaps on the server itself, changing the file
108 | // size from what the requesting client believes to be the
109 | // case. This would reduce the actual amount of data
110 | // available to the client. It is possible that the server
111 | // may back off the transfer size and reduce the read request
112 | // return. Server resource exhaustion may also occur
113 | // necessitating a smaller read return.
114 | //
115 | // Some NFS version 2 protocol client implementations chose
116 | // to interpret a short read response as indicating EOF. The
117 | // addition of the eof flag in the NFS version 3 protocol
118 | // provides a correct way of handling EOF.
119 | //
120 | // Some NFS version 2 protocol server implementations
121 | // incorrectly returned NFSERR_ISDIR if the file system
122 | // object type was not a regular file. The correct return
123 | // value for the NFS version 3 protocol is NFS3ERR_INVAL.
124 | //
125 | // ERRORS
126 | //
127 | // NFS3ERR_IO
128 | // NFS3ERR_NXIO
129 | // NFS3ERR_ACCES
130 | // NFS3ERR_INVAL
131 | // NFS3ERR_STALE
132 | // NFS3ERR_BADHANDLE
133 | // NFS3ERR_SERVERFAULT
134 | //
135 | // SEE ALSO
136 | //
137 | // READLINK.
138 |
139 | var util = require('util');
140 |
141 | var assert = require('assert-plus');
142 | var rpc = require('oncrpc');
143 |
144 | var NfsCall = require('./nfs_call').NfsCall;
145 |
146 |
147 |
148 | ///--- Globals
149 |
150 | var XDR = rpc.XDR;
151 |
152 |
153 |
154 | ///--- API
155 |
156 | function ReadCall(opts) {
157 | assert.object(opts, 'options');
158 | assert.optionalString(opts.file, 'options.file');
159 | assert.optionalNumber(opts.offset, 'options.offset');
160 | assert.optionalNumber(opts.count, 'options.count');
161 |
162 | NfsCall.call(this, opts, true);
163 |
164 | this.file = opts.file || '';
165 | this.offset = opts.offset || 0;
166 | this.count = opts.count || 0;
167 |
168 | this._nfs_read_call = true; // MDB
169 | }
170 | util.inherits(ReadCall, NfsCall);
171 | Object.defineProperty(ReadCall.prototype, 'object', {
172 | get: function object() {
173 | return (this.file);
174 | }
175 | });
176 |
177 |
178 | ReadCall.prototype._transform = function _transform(chunk, enc, cb) {
179 | if (this.incoming) {
180 | var xdr = new XDR(chunk);
181 | this.file = xdr.readString();
182 | this.offset = xdr.readHyper();
183 | this.count = xdr.readInt();
184 | } else {
185 | this.push(chunk);
186 | }
187 |
188 | cb();
189 | };
190 |
191 |
192 | ReadCall.prototype.writeHead = function writeHead() {
193 | var xdr = this._serialize(12 + XDR.byteLength(this.file));
194 | xdr.writeString(this.file);
195 | xdr.writeHyper(this.offset);
196 | xdr.writeInt(this.count);
197 |
198 | this.write(xdr.buffer());
199 | };
200 |
201 |
202 | ReadCall.prototype.toString = function toString() {
203 | var fmt = '[object ReadCall ]';
204 | return (util.format(fmt, this.xid, this.file, this.offset, this.count));
205 | };
206 |
207 |
208 |
209 | ///--- Exports
210 |
211 | module.exports = {
212 | ReadCall: ReadCall
213 | };
214 |
--------------------------------------------------------------------------------
/lib/nfs/readlink_call.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.5 Procedure 5: READLINK - Read from symbolic link
8 | //
9 | // SYNOPSIS
10 | //
11 | // READLINK3res NFSPROC3_READLINK(READLINK3args) = 5;
12 | //
13 | // struct READLINK3args {
14 | // nfs_fh3 symlink;
15 | // };
16 | //
17 | // struct READLINK3resok {
18 | // post_op_attr symlink_attributes;
19 | // nfspath3 data;
20 | // };
21 | //
22 | // struct READLINK3resfail {
23 | // post_op_attr symlink_attributes;
24 | // };
25 | //
26 | // union READLINK3res switch (nfsstat3 status) {
27 | // case NFS3_OK:
28 | // READLINK3resok resok;
29 | // default:
30 | // READLINK3resfail resfail;
31 | // };
32 | //
33 | // DESCRIPTION
34 | //
35 | // Procedure READLINK reads the data associated with a
36 | // symbolic link. The data is an ASCII string that is opaque
37 | // to the server. That is, whether created by the NFS
38 | // version 3 protocol software from a client or created
39 | // locally on the server, the data in a symbolic link is not
40 | // interpreted when created, but is simply stored. On entry,
41 | // the arguments in READLINK3args are:
42 | //
43 | // symlink
44 | // The file handle for a symbolic link (file system object
45 | // of type NF3LNK).
46 | //
47 | // On successful return, READLINK3res.status is NFS3_OK and
48 | // READLINK3res.resok contains:
49 | //
50 | // data
51 | // The data associated with the symbolic link.
52 | //
53 | // symlink_attributes
54 | // The post-operation attributes for the symbolic link.
55 | //
56 | // Otherwise, READLINK3res.status contains the error on
57 | // failure and READLINK3res.resfail contains the following:
58 | //
59 | // symlink_attributes
60 | // The post-operation attributes for the symbolic link.
61 | //
62 | // IMPLEMENTATION
63 | //
64 | // A symbolic link is nominally a pointer to another file.
65 | // The data is not necessarily interpreted by the server,
66 | // just stored in the file. It is possible for a client
67 | // implementation to store a path name that is not meaningful
68 | // to the server operating system in a symbolic link. A
69 | // READLINK operation returns the data to the client for
70 | // interpretation. If different implementations want to share
71 | // access to symbolic links, then they must agree on the
72 | // interpretation of the data in the symbolic link.
73 | //
74 | // The READLINK operation is only allowed on objects of type,
75 | // NF3LNK. The server should return the error,
76 | // NFS3ERR_INVAL, if the object is not of type, NF3LNK.
77 | // (Note: The X/Open XNFS Specification for the NFS version 2
78 | // protocol defined the error status in this case as
79 | // NFSERR_NXIO. This is inconsistent with existing server
80 | // practice.)
81 | //
82 | // ERRORS
83 | //
84 | // NFS3ERR_IO
85 | // NFS3ERR_INVAL
86 | // NFS3ERR_ACCES
87 | // NFS3ERR_STALE
88 | // NFS3ERR_BADHANDLE
89 | // NFS3ERR_NOTSUPP
90 | // NFS3ERR_SERVERFAULT
91 | //
92 | // SEE ALSO
93 | //
94 | // READLINK, SYMLINK.
95 |
96 | var util = require('util');
97 |
98 | var assert = require('assert-plus');
99 | var rpc = require('oncrpc');
100 |
101 | var NfsCall = require('./nfs_call').NfsCall;
102 |
103 |
104 |
105 | ///--- Globals
106 |
107 | var XDR = rpc.XDR;
108 |
109 |
110 |
111 | ///--- API
112 |
113 | function ReadlinkCall(opts) {
114 | NfsCall.call(this, opts, true);
115 |
116 | this.symlink = opts.symlink || '';
117 |
118 | this._nfs_readlink_call = true; // MDB
119 | }
120 | util.inherits(ReadlinkCall, NfsCall);
121 | Object.defineProperty(ReadlinkCall.prototype, 'object', {
122 | get: function object() {
123 | return (this.symlink);
124 | }
125 | });
126 |
127 |
128 | ReadlinkCall.prototype._transform = function _transform(chunk, enc, cb) {
129 | if (this.incoming) {
130 | var xdr = new XDR(chunk);
131 | this.symlink = xdr.readString();
132 | } else {
133 | this.push(chunk);
134 | }
135 |
136 | cb();
137 | };
138 |
139 |
140 | ReadlinkCall.prototype.writeHead = function writeHead() {
141 | var xdr = this._serialize(XDR.byteLength(this.symlink));
142 | xdr.writeString(this.symlink);
143 |
144 | this.write(xdr.buffer());
145 | };
146 |
147 |
148 | ReadlinkCall.prototype.toString = function toString() {
149 | var fmt = '[object ReadlinkCall ]';
150 | return (util.format(fmt, this.xid, this.symlink));
151 | };
152 |
153 |
154 |
155 | ///--- Exports
156 |
157 | module.exports = {
158 | ReadlinkCall: ReadlinkCall
159 | };
160 |
--------------------------------------------------------------------------------
/lib/nfs/readlink_reply.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.5 Procedure 5: READLINK - Read from symbolic link
8 | //
9 | // SYNOPSIS
10 | //
11 | // READLINK3res NFSPROC3_READLINK(READLINK3args) = 5;
12 | //
13 | // struct READLINK3args {
14 | // nfs_fh3 symlink;
15 | // };
16 | //
17 | // struct READLINK3resok {
18 | // post_op_attr symlink_attributes;
19 | // nfspath3 data;
20 | // };
21 | //
22 | // struct READLINK3resfail {
23 | // post_op_attr symlink_attributes;
24 | // };
25 | //
26 | // union READLINK3res switch (nfsstat3 status) {
27 | // case NFS3_OK:
28 | // READLINK3resok resok;
29 | // default:
30 | // READLINK3resfail resfail;
31 | // };
32 | //
33 | // DESCRIPTION
34 | //
35 | // Procedure READLINK reads the data associated with a
36 | // symbolic link. The data is an ASCII string that is opaque
37 | // to the server. That is, whether created by the NFS
38 | // version 3 protocol software from a client or created
39 | // locally on the server, the data in a symbolic link is not
40 | // interpreted when created, but is simply stored. On entry,
41 | // the arguments in READLINK3args are:
42 | //
43 | // symlink
44 | // The file handle for a symbolic link (file system object
45 | // of type NF3LNK).
46 | //
47 | // On successful return, READLINK3res.status is NFS3_OK and
48 | // READLINK3res.resok contains:
49 | //
50 | // data
51 | // The data associated with the symbolic link.
52 | //
53 | // symlink_attributes
54 | // The post-operation attributes for the symbolic link.
55 | //
56 | // Otherwise, READLINK3res.status contains the error on
57 | // failure and READLINK3res.resfail contains the following:
58 | //
59 | // symlink_attributes
60 | // The post-operation attributes for the symbolic link.
61 | //
62 | // IMPLEMENTATION
63 | //
64 | // A symbolic link is nominally a pointer to another file.
65 | // The data is not necessarily interpreted by the server,
66 | // just stored in the file. It is possible for a client
67 | // implementation to store a path name that is not meaningful
68 | // to the server operating system in a symbolic link. A
69 | // READLINK operation returns the data to the client for
70 | // interpretation. If different implementations want to share
71 | // access to symbolic links, then they must agree on the
72 | // interpretation of the data in the symbolic link.
73 | //
74 | // The READLINK operation is only allowed on objects of type,
75 | // NF3LNK. The server should return the error,
76 | // NFS3ERR_INVAL, if the object is not of type, NF3LNK.
77 | // (Note: The X/Open XNFS Specification for the NFS version 2
78 | // protocol defined the error status in this case as
79 | // NFSERR_NXIO. This is inconsistent with existing server
80 | // practice.)
81 | //
82 | // ERRORS
83 | //
84 | // NFS3ERR_IO
85 | // NFS3ERR_INVAL
86 | // NFS3ERR_ACCES
87 | // NFS3ERR_STALE
88 | // NFS3ERR_BADHANDLE
89 | // NFS3ERR_NOTSUPP
90 | // NFS3ERR_SERVERFAULT
91 | //
92 | // SEE ALSO
93 | //
94 | // READLINK, SYMLINK.
95 |
96 | var fs = require('fs');
97 | var path = require('path');
98 | var util = require('util');
99 |
100 | var assert = require('assert-plus');
101 | var clone = require('clone');
102 | var rpc = require('oncrpc');
103 |
104 | var nfs_err = require('./errors');
105 | var fattr3 = require('./fattr3');
106 | var NfsReply = require('./nfs_reply').NfsReply;
107 |
108 |
109 |
110 | ///--- Globals
111 |
112 | var XDR = rpc.XDR;
113 |
114 |
115 |
116 | ///--- API
117 |
118 | function ReadlinkReply(opts) {
119 | NfsReply.call(this, opts);
120 |
121 | this.status = 0;
122 | this.obj_attributes = opts.obj_attributes | {};
123 |
124 | this._nfs_readlink_reply = true; // MDB
125 | }
126 | util.inherits(ReadlinkReply, NfsReply);
127 | ReadlinkReply.prototype._allowed_error_codes = [
128 | nfs_err.NFS3ERR_IO,
129 | nfs_err.NFS3ERR_INVAL,
130 | nfs_err.NFS3ERR_ACCES,
131 | nfs_err.NFS3ERR_STALE,
132 | nfs_err.NFS3ERR_BADHANDLE,
133 | nfs_err.NFS3ERR_NOTSUPP,
134 | nfs_err.NFS3ERR_SERVERFAULT
135 | ];
136 |
137 |
138 | ReadlinkReply.prototype.setAttributes = function setAttributes(stats) {
139 | assert.ok(stats instanceof fs.Stats, 'fs.Stats');
140 |
141 | this.symlink_attributes = fattr3.create(stats);
142 |
143 | return (this.obj_attributes);
144 | };
145 |
146 |
147 | ReadlinkReply.prototype._transform = function _transform(chunk, enc, cb) {
148 | if (this.incoming) {
149 | var xdr = new XDR(chunk);
150 |
151 | this.status = xdr.readInt();
152 | if (xdr.readBool())
153 | this.symlink_attributes = fattr3.parse(xdr);
154 | if (this.status === 0)
155 | this.data = xdr.readString();
156 | } else {
157 | this.push(chunk);
158 | }
159 |
160 | cb();
161 | };
162 |
163 |
164 | ReadlinkReply.prototype.writeHead = function writeHead() {
165 | var len = 4;
166 |
167 | if (this.symlink_attributes)
168 | len += 4 + fattr3.XDR_SIZE;
169 |
170 | if (this.status === 0)
171 | len += XDR.byteLength(this.data);
172 |
173 | var xdr = this._serialize(len);
174 |
175 | xdr.writeInt(this.status);
176 | if (this.symlink_attributes) {
177 | xdr.writeBool(true);
178 | fattr3.serialize(xdr, this.symlink_attributes);
179 | } else {
180 | xdr.writeBool(false);
181 | }
182 |
183 | if (this.status === 0)
184 | xdr.writeString(this.data);
185 |
186 | this.write(xdr.buffer());
187 | };
188 |
189 |
190 | ReadlinkReply.prototype.toString = function toString() {
191 | var fmt = '[object ReadlinkReply ]';
193 | return (util.format(fmt, this.xid, this.status, this.symlink_attributes,
194 | this.data));
195 | };
196 |
197 |
198 |
199 | ///--- Exports
200 |
201 | module.exports = {
202 | ReadlinkReply: ReadlinkReply
203 | };
204 |
--------------------------------------------------------------------------------
/lib/nfs/remove_call.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.12 Procedure 12: REMOVE - Remove a File
8 | //
9 | // SYNOPSIS
10 | //
11 | // REMOVE3res NFSPROC3_REMOVE(REMOVE3args) = 12;
12 | //
13 | // struct REMOVE3args {
14 | // diropargs3 object;
15 | // };
16 | //
17 | // struct REMOVE3resok {
18 | // wcc_data dir_wcc;
19 | // };
20 | //
21 | // struct REMOVE3resfail {
22 | // wcc_data dir_wcc;
23 | // };
24 | //
25 | // union REMOVE3res switch (nfsstat3 status) {
26 | // case NFS3_OK:
27 | // REMOVE3resok resok;
28 | // default:
29 | // REMOVE3resfail resfail;
30 | // };
31 | //
32 | // DESCRIPTION
33 | //
34 | // Procedure REMOVE removes (deletes) an entry from a
35 | // directory. If the entry in the directory was the last
36 | // reference to the corresponding file system object, the
37 | // object may be destroyed. On entry, the arguments in
38 | // REMOVE3args are:
39 | //
40 | // object
41 | // A diropargs3 structure identifying the entry to be
42 | // removed:
43 | //
44 | // dir
45 | // The file handle for the directory from which the entry
46 | // is to be removed.
47 | //
48 | // name
49 | // The name of the entry to be removed. Refer to General
50 | // comments on filenames on page 30.
51 | //
52 | // On successful return, REMOVE3res.status is NFS3_OK and
53 | // REMOVE3res.resok contains:
54 | //
55 | // dir_wcc
56 | // Weak cache consistency data for the directory,
57 | // object.dir. For a client that requires only the
58 | // post-REMOVE directory attributes, these can be found in
59 | // dir_wcc.after.
60 | //
61 | // Otherwise, REMOVE3res.status contains the error on failure
62 | // and REMOVE3res.resfail contains the following:
63 | //
64 | // dir_wcc
65 | // Weak cache consistency data for the directory,
66 | // object.dir. For a client that requires only the
67 | // post-REMOVE directory attributes, these can be found in
68 | // dir_wcc.after. Even though the REMOVE failed, full
69 | // wcc_data is returned to allow the client to determine
70 | // whether the failing REMOVE changed the directory.
71 | //
72 | // IMPLEMENTATION
73 | //
74 | // In general, REMOVE is intended to remove non-directory
75 | // file objects and RMDIR is to be used to remove
76 | // directories. However, REMOVE can be used to remove
77 | // directories, subject to restrictions imposed by either the
78 | // client or server interfaces. This had been a source of
79 | // confusion in the NFS version 2 protocol.
80 | //
81 | // The concept of last reference is server specific. However,
82 | // if the nlink field in the previous attributes of the
83 | // object had the value 1, the client should not rely on
84 | // referring to the object via a file handle. Likewise, the
85 | // client should not rely on the resources (disk space,
86 | // directory entry, and so on.) formerly associated with the
87 | // object becoming immediately available. Thus, if a client
88 | // needs to be able to continue to access a file after using
89 | // REMOVE to remove it, the client should take steps to make
90 | // sure that the file will still be accessible. The usual
91 | // mechanism used is to use RENAME to rename the file from
92 | // its old name to a new hidden name.
93 | //
94 | // Refer to General comments on filenames on page 30.
95 | //
96 | // ERRORS
97 | //
98 | // NFS3ERR_NOENT
99 | // NFS3ERR_IO
100 | // NFS3ERR_ACCES
101 | // NFS3ERR_NOTDIR
102 | // NFS3ERR_NAMETOOLONG
103 | // NFS3ERR_ROFS
104 | // NFS3ERR_STALE
105 | // NFS3ERR_BADHANDLE
106 | // NFS3ERR_SERVERFAULT
107 | //
108 | // SEE ALSO
109 | //
110 | // RMDIR and RENAME.
111 |
112 |
113 | var util = require('util');
114 |
115 | var assert = require('assert-plus');
116 | var rpc = require('oncrpc');
117 |
118 | var NfsCall = require('./nfs_call').NfsCall;
119 |
120 |
121 |
122 | ///--- Globals
123 |
124 | var XDR = rpc.XDR;
125 |
126 |
127 |
128 | ///--- API
129 |
130 | function RemoveCall(opts) {
131 | assert.object(opts, 'opts');
132 | assert.optionalObject(opts.object, 'opts.object');
133 |
134 | NfsCall.call(this, opts, true);
135 |
136 | this._object = opts.object || {
137 | dir: '',
138 | name: ''
139 | };
140 |
141 | this._nfs_remove_call = true; // MDB
142 | }
143 | util.inherits(RemoveCall, NfsCall);
144 | Object.defineProperty(RemoveCall.prototype, 'object', {
145 | get: function object() {
146 | return (this._object.dir);
147 | }
148 | });
149 |
150 |
151 | RemoveCall.prototype._transform = function _transform(chunk, enc, cb) {
152 | if (this.incoming) {
153 | var xdr = new XDR(chunk);
154 | this._object.dir = xdr.readString();
155 | this._object.name = xdr.readString();
156 | } else {
157 | this.push(chunk);
158 | }
159 |
160 | cb();
161 | };
162 |
163 |
164 | RemoveCall.prototype.writeHead = function writeHead() {
165 | var len = XDR.byteLength(this._object.dir) +
166 | XDR.byteLength(this._object.name);
167 |
168 | var xdr = this._serialize(len);
169 |
170 | xdr.writeString(this._object.dir);
171 | xdr.writeString(this._object.name);
172 |
173 | this.write(xdr.buffer());
174 | };
175 |
176 |
177 | RemoveCall.prototype.toString = function toString() {
178 | var fmt = '[object RemoveCall ]';
179 | return (util.format(fmt, this.xid, this._object));
180 | };
181 |
182 |
183 |
184 | ///--- Exports
185 |
186 | module.exports = {
187 | RemoveCall: RemoveCall
188 | };
189 |
--------------------------------------------------------------------------------
/lib/nfs/remove_reply.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.12 Procedure 12: REMOVE - Remove a File
8 | //
9 | // SYNOPSIS
10 | //
11 | // REMOVE3res NFSPROC3_REMOVE(REMOVE3args) = 12;
12 | //
13 | // struct REMOVE3args {
14 | // diropargs3 object;
15 | // };
16 | //
17 | // struct REMOVE3resok {
18 | // wcc_data dir_wcc;
19 | // };
20 | //
21 | // struct REMOVE3resfail {
22 | // wcc_data dir_wcc;
23 | // };
24 | //
25 | // union REMOVE3res switch (nfsstat3 status) {
26 | // case NFS3_OK:
27 | // REMOVE3resok resok;
28 | // default:
29 | // REMOVE3resfail resfail;
30 | // };
31 | //
32 | // DESCRIPTION
33 | //
34 | // Procedure REMOVE removes (deletes) an entry from a
35 | // directory. If the entry in the directory was the last
36 | // reference to the corresponding file system object, the
37 | // object may be destroyed. On entry, the arguments in
38 | // REMOVE3args are:
39 | //
40 | // object
41 | // A diropargs3 structure identifying the entry to be
42 | // removed:
43 | //
44 | // dir
45 | // The file handle for the directory from which the entry
46 | // is to be removed.
47 | //
48 | // name
49 | // The name of the entry to be removed. Refer to General
50 | // comments on filenames on page 30.
51 | //
52 | // On successful return, REMOVE3res.status is NFS3_OK and
53 | // REMOVE3res.resok contains:
54 | //
55 | // dir_wcc
56 | // Weak cache consistency data for the directory,
57 | // object.dir. For a client that requires only the
58 | // post-REMOVE directory attributes, these can be found in
59 | // dir_wcc.after.
60 | //
61 | // Otherwise, REMOVE3res.status contains the error on failure
62 | // and REMOVE3res.resfail contains the following:
63 | //
64 | // dir_wcc
65 | // Weak cache consistency data for the directory,
66 | // object.dir. For a client that requires only the
67 | // post-REMOVE directory attributes, these can be found in
68 | // dir_wcc.after. Even though the REMOVE failed, full
69 | // wcc_data is returned to allow the client to determine
70 | // whether the failing REMOVE changed the directory.
71 | //
72 | // IMPLEMENTATION
73 | //
74 | // In general, REMOVE is intended to remove non-directory
75 | // file objects and RMDIR is to be used to remove
76 | // directories. However, REMOVE can be used to remove
77 | // directories, subject to restrictions imposed by either the
78 | // client or server interfaces. This had been a source of
79 | // confusion in the NFS version 2 protocol.
80 | //
81 | // The concept of last reference is server specific. However,
82 | // if the nlink field in the previous attributes of the
83 | // object had the value 1, the client should not rely on
84 | // referring to the object via a file handle. Likewise, the
85 | // client should not rely on the resources (disk space,
86 | // directory entry, and so on.) formerly associated with the
87 | // object becoming immediately available. Thus, if a client
88 | // needs to be able to continue to access a file after using
89 | // REMOVE to remove it, the client should take steps to make
90 | // sure that the file will still be accessible. The usual
91 | // mechanism used is to use RENAME to rename the file from
92 | // its old name to a new hidden name.
93 | //
94 | // Refer to General comments on filenames on page 30.
95 | //
96 | // ERRORS
97 | //
98 | // NFS3ERR_NOENT
99 | // NFS3ERR_IO
100 | // NFS3ERR_ACCES
101 | // NFS3ERR_NOTDIR
102 | // NFS3ERR_NAMETOOLONG
103 | // NFS3ERR_ROFS
104 | // NFS3ERR_STALE
105 | // NFS3ERR_BADHANDLE
106 | // NFS3ERR_SERVERFAULT
107 | //
108 | // SEE ALSO
109 | //
110 | // RMDIR and RENAME.
111 |
112 | var fs = require('fs');
113 | var path = require('path');
114 | var util = require('util');
115 |
116 | var assert = require('assert-plus');
117 | var clone = require('clone');
118 | var rpc = require('oncrpc');
119 |
120 | var nfs_err = require('./errors');
121 | var wcc_data = require('./wcc_data');
122 | var NfsReply = require('./nfs_reply').NfsReply;
123 |
124 |
125 |
126 | ///--- Globals
127 |
128 | var XDR = rpc.XDR;
129 |
130 |
131 |
132 | ///--- API
133 |
134 | function RemoveReply(opts) {
135 | NfsReply.call(this, opts);
136 |
137 | this.status = 0;
138 | this.dir_wcc = opts.dir_wcc | null;
139 |
140 | this._nfs_remove_reply = true; // MDB
141 | }
142 | util.inherits(RemoveReply, NfsReply);
143 | RemoveReply.prototype._allowed_error_codes = [
144 | nfs_err.NFS3ERR_NOENT,
145 | nfs_err.NFS3ERR_IO,
146 | nfs_err.NFS3ERR_ACCES,
147 | nfs_err.NFS3ERR_NOTDIR,
148 | nfs_err.NFS3ERR_NAMETOOLONG,
149 | nfs_err.NFS3ERR_ROFS,
150 | nfs_err.NFS3ERR_STALE,
151 | nfs_err.NFS3ERR_BADHANDLE,
152 | nfs_err.NFS3ERR_SERVERFAULT
153 | ];
154 |
155 |
156 | RemoveReply.prototype.set_dir_wcc = function set_dir_wcc() {
157 | this.dir_wcc = wcc_data.create();
158 | return (this.dir_wcc);
159 | };
160 |
161 |
162 | RemoveReply.prototype._transform = function _transform(chunk, enc, cb) {
163 | if (this.incoming) {
164 | var xdr = new XDR(chunk);
165 |
166 | this.status = xdr.readInt();
167 | this.dir_wcc = wcc_data.parse(xdr);
168 | } else {
169 | this.push(chunk);
170 | }
171 |
172 | cb();
173 | };
174 |
175 |
176 | RemoveReply.prototype.writeHead = function writeHead() {
177 | var len = 4;
178 |
179 | len += wcc_data.length(this.dir_wcc);
180 |
181 | var xdr = this._serialize(len);
182 |
183 | xdr.writeInt(this.status);
184 |
185 | wcc_data.serialize(xdr, this.dir_wcc);
186 |
187 | this.write(xdr.buffer());
188 | };
189 |
190 |
191 | RemoveReply.prototype.toString = function toString() {
192 | var fmt = '[object RemoveReply ]';
193 | return (util.format(fmt, this.xid, this.status, this.dir_wcc));
194 | };
195 |
196 |
197 |
198 | ///--- Exports
199 |
200 | module.exports = {
201 | RemoveReply: RemoveReply
202 | };
203 |
--------------------------------------------------------------------------------
/lib/nfs/rename_call.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.14 Procedure 14: RENAME - Rename a File or Directory
8 | //
9 | // SYNOPSIS
10 | //
11 | // RENAME3res NFSPROC3_RENAME(RENAME3args) = 14;
12 | //
13 | // struct RENAME3args {
14 | // diropargs3 from;
15 | // diropargs3 to;
16 | // };
17 | //
18 | // struct RENAME3resok {
19 | // wcc_data fromdir_wcc;
20 | // wcc_data todir_wcc;
21 | // };
22 | //
23 | // struct RENAME3resfail {
24 | // wcc_data fromdir_wcc;
25 | // wcc_data todir_wcc;
26 | // };
27 | //
28 | // union RENAME3res switch (nfsstat3 status) {
29 | // case NFS3_OK:
30 | // RENAME3resok resok;
31 | // default:
32 | // RENAME3resfail resfail;
33 | // };
34 | //
35 | // DESCRIPTION
36 | //
37 | // Procedure RENAME renames the file identified by from.name
38 | // in the directory, from.dir, to to.name in the di- rectory,
39 | // to.dir. The operation is required to be atomic to the
40 | // client. To.dir and from.dir must reside on the same file
41 | // system and server. On entry, the arguments in RENAME3args
42 | // are:
43 | //
44 | // from
45 | // A diropargs3 structure identifying the source (the file
46 | // system object to be re-named):
47 | //
48 | // from.dir
49 | // The file handle for the directory from which the
50 | // entry is to be renamed.
51 | //
52 | // from.name
53 | // The name of the entry that identifies the object to
54 | // be renamed. Refer to General comments on filenames
55 | // on page 30.
56 | //
57 | // to
58 | // A diropargs3 structure identifying the target (the new
59 | // name of the object):
60 | //
61 | // to.dir
62 | // The file handle for the directory to which the
63 | // object is to be renamed.
64 | //
65 | // to.name
66 | // The new name for the object. Refer to General
67 | // comments on filenames on page 30.
68 | //
69 | // If the directory, to.dir, already contains an entry with
70 | // the name, to.name, the source object must be compatible
71 | // with the target: either both are non-directories or both
72 | // are directories and the target must be empty. If
73 | // compatible, the existing target is removed before the
74 | // rename occurs. If they are not compatible or if the target
75 | // is a directory but not empty, the server should return the
76 | // error, NFS3ERR_EXIST.
77 | //
78 | // On successful return, RENAME3res.status is NFS3_OK and
79 | // RENAME3res.resok contains:
80 | //
81 | // fromdir_wcc
82 | // Weak cache consistency data for the directory,
83 | // from.dir.
84 | //
85 | // todir_wcc
86 | // Weak cache consistency data for the directory, to.dir.
87 | //
88 | // Otherwise, RENAME3res.status contains the error on failure
89 | // and RENAME3res.resfail contains the following:
90 | //
91 | // fromdir_wcc
92 | // Weak cache consistency data for the directory,
93 | // from.dir.
94 | //
95 | // todir_wcc
96 | // Weak cache consistency data for the directory, to.dir.
97 | //
98 | // IMPLEMENTATION
99 | // The RENAME operation must be atomic to the client. The
100 | // message "to.dir and from.dir must reside on the same file
101 | // system on the server, [or the operation will fail]" means
102 | // that the fsid fields in the attributes for the directories
103 | // are the same. If they reside on different file systems,
104 | // the error, NFS3ERR_XDEV, is returned. Even though the
105 | // operation is atomic, the status, NFS3ERR_MLINK, may be
106 | // returned if the server used a "unlink/link/unlink"
107 | // sequence internally.
108 | //
109 | // A file handle may or may not become stale on a rename.
110 | // However, server implementors are strongly encouraged to
111 | // attempt to keep file handles from becoming stale in this
112 | // fashion.
113 | //
114 | // On some servers, the filenames, "." and "..", are illegal
115 | // as either from.name or to.name. In addition, neither
116 | // from.name nor to.name can be an alias for from.dir. These
117 | // servers will return the error, NFS3ERR_INVAL, in these
118 | // cases.
119 | //
120 | // If from and to both refer to the same file (they might
121 | // be hard links of each other), then RENAME should perform
122 | // no action and return NFS3_OK.
123 | //
124 | // Refer to General comments on filenames on page 30.
125 | //
126 | // ERRORS
127 | //
128 | // NFS3ERR_NOENT
129 | // NFS3ERR_IO
130 | // NFS3ERR_ACCES
131 | // NFS3ERR_EXIST
132 | // NFS3ERR_XDEV
133 | // NFS3ERR_NOTDIR
134 | // NFS3ERR_ISDIR
135 | // NFS3ERR_INVAL
136 | // NFS3ERR_NOSPC
137 | // NFS3ERR_ROFS
138 | // NFS3ERR_MLINK
139 | // NFS3ERR_NAMETOOLONG
140 | // NFS3ERR_NOTEMPTY
141 | // NFS3ERR_DQUOT
142 | // NFS3ERR_STALE
143 | // NFS3ERR_BADHANDLE
144 | // NFS3ERR_NOTSUPP
145 | // NFS3ERR_SERVERFAULT
146 | //
147 | // SEE ALSO
148 | //
149 | // REMOVE and LINK.
150 |
151 |
152 | var util = require('util');
153 |
154 | var assert = require('assert-plus');
155 | var rpc = require('oncrpc');
156 |
157 | var NfsCall = require('./nfs_call').NfsCall;
158 |
159 |
160 |
161 | ///--- Globals
162 |
163 | var XDR = rpc.XDR;
164 |
165 |
166 |
167 | ///--- API
168 |
169 | function RenameCall(opts) {
170 | assert.object(opts, 'opts');
171 | assert.optionalObject(opts.from, 'opts.from');
172 | assert.optionalObject(opts.to, 'opts.to');
173 |
174 | NfsCall.call(this, opts, true);
175 |
176 | this.from = opts.from || {
177 | dir: '',
178 | name: ''
179 | };
180 |
181 | this.to = opts.to || {
182 | dir: '',
183 | name: ''
184 | };
185 |
186 | this._nfs_rename_call = true; // MDB
187 | }
188 | util.inherits(RenameCall, NfsCall);
189 | Object.defineProperty(RenameCall.prototype, 'object', {
190 | get: function object() {
191 | return (this.from.dir);
192 | }
193 | });
194 |
195 |
196 | RenameCall.prototype._transform = function _transform(chunk, enc, cb) {
197 | if (this.incoming) {
198 | var xdr = new XDR(chunk);
199 | this.from.dir = xdr.readString();
200 | this.from.name = xdr.readString();
201 | this.to.dir = xdr.readString();
202 | this.to.name = xdr.readString();
203 | } else {
204 | this.push(chunk);
205 | }
206 |
207 | cb();
208 | };
209 |
210 |
211 | RenameCall.prototype.writeHead = function writeHead() {
212 | var len = XDR.byteLength(this.from.dir) +
213 | XDR.byteLength(this.from.name) +
214 | XDR.byteLength(this.to.dir) +
215 | XDR.byteLength(this.to.name);
216 |
217 | var xdr = this._serialize(len);
218 |
219 | xdr.writeString(this.from.dir);
220 | xdr.writeString(this.from.name);
221 | xdr.writeString(this.to.dir);
222 | xdr.writeString(this.to.name);
223 |
224 | this.write(xdr.buffer());
225 | };
226 |
227 |
228 | RenameCall.prototype.toString = function toString() {
229 | var fmt = '[object RenameCall ]';
230 | return (util.format(fmt, this.xid, this.from, this.to));
231 | };
232 |
233 |
234 |
235 | ///--- Exports
236 |
237 | module.exports = {
238 | RenameCall: RenameCall
239 | };
240 |
--------------------------------------------------------------------------------
/lib/nfs/rmdir_call.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.13 Procedure 13: RMDIR - Remove a Directory
8 | //
9 | // SYNOPSIS
10 | //
11 | // RMDIR3res NFSPROC3_RMDIR(RMDIR3args) = 13;
12 | //
13 | // struct RMDIR3args {
14 | // diropargs3 object;
15 | // };
16 | //
17 | // struct RMDIR3resok {
18 | // wcc_data dir_wcc;
19 | // };
20 | //
21 | // struct RMDIR3resfail {
22 | // wcc_data dir_wcc;
23 | // };
24 | //
25 | // union RMDIR3res switch (nfsstat3 status) {
26 | // case NFS3_OK:
27 | // RMDIR3resok resok;
28 | // default:
29 | // RMDIR3resfail resfail;
30 | // };
31 | //
32 | // DESCRIPTION
33 | //
34 | // Procedure RMDIR removes (deletes) a subdirectory from a
35 | // directory. If the directory entry of the subdirectory is
36 | // the last reference to the subdirectory, the subdirectory
37 | // may be destroyed. On entry, the arguments in RMDIR3args
38 | // are:
39 | //
40 | // object
41 | // A diropargs3 structure identifying the directory entry
42 | // to be removed:
43 | //
44 | // dir
45 | // The file handle for the directory from which the
46 | // subdirectory is to be removed.
47 | //
48 | // name
49 | // The name of the subdirectory to be removed. Refer to
50 | // General comments on filenames on page 30.
51 | //
52 | // On successful return, RMDIR3res.status is NFS3_OK and
53 | // RMDIR3res.resok contains:
54 | //
55 | // dir_wcc
56 | // Weak cache consistency data for the directory,
57 | // object.dir. For a client that requires only the
58 | // post-RMDIR directory attributes, these can be found in
59 | // dir_wcc.after.
60 | //
61 | // Otherwise, RMDIR3res.status contains the error on failure
62 | // and RMDIR3res.resfail contains the following:
63 | //
64 | // dir_wcc
65 | // Weak cache consistency data for the directory,
66 | // object.dir. For a client that requires only the
67 | // post-RMDIR directory attributes, these can be found in
68 | // dir_wcc.after. Note that even though the RMDIR failed,
69 | // full wcc_data is returned to allow the client to
70 | // determine whether the failing RMDIR changed the
71 | // directory.
72 | //
73 | // IMPLEMENTATION
74 | //
75 | // Note that on some servers, removal of a non-empty
76 | // directory is disallowed.
77 | //
78 | // On some servers, the filename, ".", is illegal. These
79 | // servers will return the error, NFS3ERR_INVAL. On some
80 | // servers, the filename, "..", is illegal. These servers
81 | // will return the error, NFS3ERR_EXIST. This would seem
82 | // inconsistent, but allows these servers to comply with
83 | // their own specific interface definitions. Clients should
84 | // be prepared to handle both cases.
85 | //
86 | // The client should not rely on the resources (disk space,
87 | // directory entry, and so on.) formerly associated with the
88 | // directory becoming immediately available.
89 | //
90 | // ERRORS
91 | //
92 | // NFS3ERR_NOENT
93 | // NFS3ERR_IO
94 | // NFS3ERR_ACCES
95 | // NFS3ERR_INVAL
96 | // NFS3ERR_EXIST
97 | // NFS3ERR_NOTDIR
98 | // NFS3ERR_NAMETOOLONG
99 | // NFS3ERR_ROFS
100 | // NFS3ERR_NOTEMPTY
101 | // NFS3ERR_STALE
102 | // NFS3ERR_BADHANDLE
103 | // NFS3ERR_NOTSUPP
104 | // NFS3ERR_SERVERFAULT
105 | //
106 | // SEE ALSO
107 | //
108 | // REMOVE.
109 |
110 |
111 | var util = require('util');
112 |
113 | var assert = require('assert-plus');
114 | var rpc = require('oncrpc');
115 |
116 | var NfsCall = require('./nfs_call').NfsCall;
117 |
118 |
119 |
120 | ///--- Globals
121 |
122 | var XDR = rpc.XDR;
123 |
124 |
125 |
126 | ///--- API
127 |
128 | function RmdirCall(opts) {
129 | assert.object(opts, 'opts');
130 | assert.optionalObject(opts.object, 'opts.object');
131 |
132 | NfsCall.call(this, opts, true);
133 |
134 | this._object = opts.object || {
135 | dir: '',
136 | name: ''
137 | };
138 |
139 | this._nfs_rmdir_call = true; // MDB
140 | }
141 | util.inherits(RmdirCall, NfsCall);
142 | Object.defineProperty(RmdirCall.prototype, 'object', {
143 | get: function object() {
144 | return (this._object.dir);
145 | }
146 | });
147 |
148 |
149 | RmdirCall.prototype._transform = function _transform(chunk, enc, cb) {
150 | if (this.incoming) {
151 | var xdr = new XDR(chunk);
152 | this._object.dir = xdr.readString();
153 | this._object.name = xdr.readString();
154 | } else {
155 | this.push(chunk);
156 | }
157 |
158 | cb();
159 | };
160 |
161 |
162 | RmdirCall.prototype.writeHead = function writeHead() {
163 | var len = XDR.byteLength(this._object.dir) +
164 | XDR.byteLength(this._object.name);
165 |
166 | var xdr = this._serialize(len);
167 |
168 | xdr.writeString(this._object.dir);
169 | xdr.writeString(this._object.name);
170 |
171 | this.write(xdr.buffer());
172 | };
173 |
174 |
175 | RmdirCall.prototype.toString = function toString() {
176 | var fmt = '[object RmdirCall ]';
177 | return (util.format(fmt, this.xid, this._object));
178 | };
179 |
180 |
181 |
182 | ///--- Exports
183 |
184 | module.exports = {
185 | RmdirCall: RmdirCall
186 | };
187 |
--------------------------------------------------------------------------------
/lib/nfs/rmdir_reply.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.13 Procedure 13: RMDIR - Remove a Directory
8 | //
9 | // SYNOPSIS
10 | //
11 | // RMDIR3res NFSPROC3_RMDIR(RMDIR3args) = 13;
12 | //
13 | // struct RMDIR3args {
14 | // diropargs3 object;
15 | // };
16 | //
17 | // struct RMDIR3resok {
18 | // wcc_data dir_wcc;
19 | // };
20 | //
21 | // struct RMDIR3resfail {
22 | // wcc_data dir_wcc;
23 | // };
24 | //
25 | // union RMDIR3res switch (nfsstat3 status) {
26 | // case NFS3_OK:
27 | // RMDIR3resok resok;
28 | // default:
29 | // RMDIR3resfail resfail;
30 | // };
31 | //
32 | // DESCRIPTION
33 | //
34 | // Procedure RMDIR removes (deletes) a subdirectory from a
35 | // directory. If the directory entry of the subdirectory is
36 | // the last reference to the subdirectory, the subdirectory
37 | // may be destroyed. On entry, the arguments in RMDIR3args
38 | // are:
39 | //
40 | // object
41 | // A diropargs3 structure identifying the directory entry
42 | // to be removed:
43 | //
44 | // dir
45 | // The file handle for the directory from which the
46 | // subdirectory is to be removed.
47 | //
48 | // name
49 | // The name of the subdirectory to be removed. Refer to
50 | // General comments on filenames on page 30.
51 | //
52 | // On successful return, RMDIR3res.status is NFS3_OK and
53 | // RMDIR3res.resok contains:
54 | //
55 | // dir_wcc
56 | // Weak cache consistency data for the directory,
57 | // object.dir. For a client that requires only the
58 | // post-RMDIR directory attributes, these can be found in
59 | // dir_wcc.after.
60 | //
61 | // Otherwise, RMDIR3res.status contains the error on failure
62 | // and RMDIR3res.resfail contains the following:
63 | //
64 | // dir_wcc
65 | // Weak cache consistency data for the directory,
66 | // object.dir. For a client that requires only the
67 | // post-RMDIR directory attributes, these can be found in
68 | // dir_wcc.after. Note that even though the RMDIR failed,
69 | // full wcc_data is returned to allow the client to
70 | // determine whether the failing RMDIR changed the
71 | // directory.
72 | //
73 | // IMPLEMENTATION
74 | //
75 | // Note that on some servers, removal of a non-empty
76 | // directory is disallowed.
77 | //
78 | // On some servers, the filename, ".", is illegal. These
79 | // servers will return the error, NFS3ERR_INVAL. On some
80 | // servers, the filename, "..", is illegal. These servers
81 | // will return the error, NFS3ERR_EXIST. This would seem
82 | // inconsistent, but allows these servers to comply with
83 | // their own specific interface definitions. Clients should
84 | // be prepared to handle both cases.
85 | //
86 | // The client should not rely on the resources (disk space,
87 | // directory entry, and so on.) formerly associated with the
88 | // directory becoming immediately available.
89 | //
90 | // ERRORS
91 | //
92 | // NFS3ERR_NOENT
93 | // NFS3ERR_IO
94 | // NFS3ERR_ACCES
95 | // NFS3ERR_INVAL
96 | // NFS3ERR_EXIST
97 | // NFS3ERR_NOTDIR
98 | // NFS3ERR_NAMETOOLONG
99 | // NFS3ERR_ROFS
100 | // NFS3ERR_NOTEMPTY
101 | // NFS3ERR_STALE
102 | // NFS3ERR_BADHANDLE
103 | // NFS3ERR_NOTSUPP
104 | // NFS3ERR_SERVERFAULT
105 | //
106 | // SEE ALSO
107 | //
108 | // REMOVE.
109 |
110 | var fs = require('fs');
111 | var path = require('path');
112 | var util = require('util');
113 |
114 | var assert = require('assert-plus');
115 | var clone = require('clone');
116 | var rpc = require('oncrpc');
117 |
118 | var nfs_err = require('./errors');
119 | var wcc_data = require('./wcc_data');
120 | var NfsReply = require('./nfs_reply').NfsReply;
121 |
122 |
123 |
124 | ///--- Globals
125 |
126 | var XDR = rpc.XDR;
127 |
128 |
129 |
130 | ///--- API
131 |
132 | function RmdirReply(opts) {
133 | NfsReply.call(this, opts);
134 |
135 | this.status = 0;
136 | this.dir_wcc = opts.dir_wcc | null;
137 |
138 | this._nfs_rmdir_reply = true; // MDB
139 | }
140 | util.inherits(RmdirReply, NfsReply);
141 | RmdirReply.prototype._allowed_error_codes = [
142 | nfs_err.NFS3ERR_NOENT,
143 | nfs_err.NFS3ERR_IO,
144 | nfs_err.NFS3ERR_ACCES,
145 | nfs_err.NFS3ERR_INVAL,
146 | nfs_err.NFS3ERR_EXIST,
147 | nfs_err.NFS3ERR_NOTDIR,
148 | nfs_err.NFS3ERR_ROFS,
149 | nfs_err.NFS3ERR_NAMETOOLONG,
150 | nfs_err.NFS3ERR_NOTEMPTY,
151 | nfs_err.NFS3ERR_STALE,
152 | nfs_err.NFS3ERR_BADHANDLE,
153 | nfs_err.NFS3ERR_NOTSUPP,
154 | nfs_err.NFS3ERR_SERVERFAULT
155 | ];
156 |
157 |
158 | RmdirReply.prototype.set_dir_wcc = function set_dir_wcc() {
159 | this.dir_wcc = wcc_data.create();
160 | return (this.dir_wcc);
161 | };
162 |
163 |
164 | RmdirReply.prototype._transform = function _transform(chunk, enc, cb) {
165 | if (this.incoming) {
166 | var xdr = new XDR(chunk);
167 |
168 | this.status = xdr.readInt();
169 | this.dir_wcc = wcc_data.parse(xdr);
170 | } else {
171 | this.push(chunk);
172 | }
173 |
174 | cb();
175 | };
176 |
177 |
178 | RmdirReply.prototype.writeHead = function writeHead() {
179 | var len = 4;
180 |
181 | len += wcc_data.length(this.dir_wcc);
182 |
183 | var xdr = this._serialize(len);
184 |
185 | xdr.writeInt(this.status);
186 |
187 | wcc_data.serialize(xdr, this.dir_wcc);
188 |
189 | this.write(xdr.buffer());
190 | };
191 |
192 |
193 | RmdirReply.prototype.toString = function toString() {
194 | var fmt = '[object RmdirReply ]';
195 | return (util.format(fmt, this.xid, this.status, this.dir_wcc));
196 | };
197 |
198 |
199 |
200 | ///--- Exports
201 |
202 | module.exports = {
203 | RmdirReply: RmdirReply
204 | };
205 |
--------------------------------------------------------------------------------
/lib/nfs/sattr3.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var path = require('path');
8 | var util = require('util');
9 |
10 | var assert = require('assert-plus');
11 | var clone = require('clone');
12 | var rpc = require('oncrpc');
13 |
14 |
15 |
16 | ///--- Globals
17 |
18 | var XDR = rpc.XDR;
19 |
20 | var time_how = {
21 | DONT_CHANGE: 0,
22 | SET_TO_SERVER_TIME: 1,
23 | SET_TO_CLIENT_TIME: 2
24 | };
25 |
26 | // struct nfstime3 {
27 | // uint32 seconds;
28 | // uint32 nseconds;
29 | // };
30 |
31 | // enum time_how {
32 | // DONT_CHANGE = 0,
33 | // SET_TO_SERVER_TIME = 1,
34 | // SET_TO_CLIENT_TIME = 2
35 | // };
36 |
37 | // union set_mode3 switch (bool set_it) {
38 | // case TRUE:
39 | // mode3 mode;
40 | // default:
41 | // void;
42 | // };
43 |
44 | // union set_uid3 switch (bool set_it) {
45 | // case TRUE:
46 | // uid3 uid;
47 | // default:
48 | // void;
49 | // };
50 |
51 | // union set_gid3 switch (bool set_it) {
52 | // case TRUE:
53 | // gid3 gid;
54 | // default:
55 | // void;
56 | // };
57 |
58 | // union set_size3 switch (bool set_it) {
59 | // case TRUE:
60 | // size3 size;
61 | // default:
62 | // void;
63 | // };
64 |
65 | // union set_atime switch (time_how set_it) {
66 | // case SET_TO_CLIENT_TIME:
67 | // nfstime3 atime;
68 | // default:
69 | // void;
70 | // };
71 |
72 | // union set_mtime switch (time_how set_it) {
73 | // case SET_TO_CLIENT_TIME:
74 | // nfstime3 mtime;
75 | // default:
76 | // void;
77 | // };
78 |
79 | // struct sattr3 {
80 | // set_mode3 mode;
81 | // set_uid3 uid;
82 | // set_gid3 gid;
83 | // set_size3 size;
84 | // set_atime atime;
85 | // set_mtime mtime;
86 | // };
87 |
88 |
89 | function parse_sattr3(xdr) {
90 | assert.object(xdr, 'xdr');
91 |
92 | var mode;
93 | var uid;
94 | var gid;
95 | var size;
96 | var a_time;
97 | var m_time;
98 |
99 | if (xdr.readBool())
100 | mode = xdr.readInt();
101 | else
102 | mode = null;
103 |
104 | if (xdr.readBool())
105 | uid = xdr.readInt();
106 | else
107 | uid = null;
108 |
109 | if (xdr.readBool())
110 | gid = xdr.readInt();
111 | else
112 | gid = null;
113 |
114 | if (xdr.readBool())
115 | size = xdr.readHyper();
116 | else
117 | size = null;
118 |
119 | var how_a_time = xdr.readInt();
120 | if (how_a_time === time_how.SET_TO_CLIENT_TIME) {
121 | a_time = {
122 | seconds: xdr.readInt(),
123 | nseconds: xdr.readInt()
124 | };
125 | } else {
126 | a_time = null;
127 | }
128 |
129 | var how_m_time = xdr.readInt();
130 | if (how_m_time === time_how.SET_TO_CLIENT_TIME) {
131 | m_time = {
132 | seconds: xdr.readInt(),
133 | nseconds: xdr.readInt()
134 | };
135 | } else {
136 | m_time = null;
137 | }
138 |
139 | var sattr3 = {
140 | mode: mode,
141 | uid: uid,
142 | gid: gid,
143 | size: size,
144 | how_a_time: how_a_time,
145 | atime: a_time,
146 | how_m_time: how_m_time,
147 | mtime: m_time
148 | };
149 |
150 | return (sattr3);
151 | }
152 |
153 |
154 | function serialize_sattr3(xdr, sattr3) {
155 | assert.object(xdr, 'xdr');
156 | assert.object(sattr3, 'sattr3');
157 |
158 | if (! sattr3.mode) {
159 | xdr.writeBool(false);
160 | } else {
161 | xdr.writeBool(true);
162 | xdr.writeInt(sattr3.mode);
163 | }
164 |
165 | if (! sattr3.uid) {
166 | xdr.writeBool(false);
167 | } else {
168 | xdr.writeBool(true);
169 | xdr.writeInt(sattr3.uid);
170 | }
171 |
172 | if (! sattr3.gid) {
173 | xdr.writeBool(false);
174 | } else {
175 | xdr.writeBool(true);
176 | xdr.writeInt(sattr3.gid);
177 | }
178 |
179 | if (! sattr3.size) {
180 | xdr.writeBool(false);
181 | } else {
182 | xdr.writeBool(true);
183 | xdr.writeHyper(sattr3.size);
184 | }
185 |
186 | xdr.writeInt(sattr3.how_a_time);
187 | if (sattr3.how_a_time === time_how.SET_TO_CLIENT_TIME) {
188 | xdr.writeInt(sattr3.atime.seconds);
189 | xdr.writeInt(sattr3.atime.nseconds);
190 | }
191 |
192 | xdr.writeInt(sattr3.how_m_time);
193 | if (sattr3.how_m_time === time_how.SET_TO_CLIENT_TIME) {
194 | xdr.writeInt(sattr3.mtime.seconds);
195 | xdr.writeInt(sattr3.mtime.nseconds);
196 | }
197 |
198 | return (xdr);
199 | }
200 |
201 |
202 | function XDR_length(sattr3) {
203 | assert.object(sattr3, 'sattr3');
204 |
205 | var len = 0;
206 |
207 | len += 4;
208 | if (sattr3.mode)
209 | len += 4;
210 |
211 | len += 4;
212 | if (sattr3.uid)
213 | len += 4;
214 |
215 | len += 4;
216 | if (sattr3.gid)
217 | len += 4;
218 |
219 | len += 4;
220 | if (sattr3.size)
221 | len += 8;
222 |
223 | len += 4;
224 | if (sattr3.how_a_time === time_how.SET_TO_CLIENT_TIME)
225 | len += 8;
226 |
227 | len += 4;
228 | if (sattr3.how_m_time === time_how.SET_TO_CLIENT_TIME)
229 | len += 8;
230 |
231 | return (len);
232 | }
233 |
234 |
235 | ///--- Exports
236 |
237 | module.exports = {
238 | parse: parse_sattr3,
239 | serialize: serialize_sattr3,
240 | length: XDR_length,
241 | time_how: time_how
242 | };
243 |
--------------------------------------------------------------------------------
/lib/nfs/symlink_call.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.10 Procedure 10: SYMLINK - Create a symbolic link
8 | //
9 | // SYNOPSIS
10 | //
11 | // SYMLINK3res NFSPROC3_SYMLINK(SYMLINK3args) = 10;
12 | //
13 | // struct symlinkdata3 {
14 | // sattr3 symlink_attributes;
15 | // nfspath3 symlink_data;
16 | // };
17 | //
18 | // struct SYMLINK3args {
19 | // diropargs3 where;
20 | // symlinkdata3 symlink;
21 | // };
22 | //
23 | // struct SYMLINK3resok {
24 | // post_op_fh3 obj;
25 | // post_op_attr obj_attributes;
26 | // wcc_data dir_wcc;
27 | // };
28 | //
29 | // struct SYMLINK3resfail {
30 | // wcc_data dir_wcc;
31 | // };
32 | //
33 | // union SYMLINK3res switch (nfsstat3 status) {
34 | // case NFS3_OK:
35 | // SYMLINK3resok resok;
36 | // default:
37 | // SYMLINK3resfail resfail;
38 | // };
39 | //
40 | // DESCRIPTION
41 | //
42 | // Procedure SYMLINK creates a new symbolic link. On entry,
43 | // the arguments in SYMLINK3args are:
44 | //
45 | // where
46 | // The location of the symbolic link to be created:
47 | //
48 | // dir
49 | // The file handle for the directory in which the
50 | // symbolic link is to be created.
51 | //
52 | // name
53 | // The name that is to be associated with the created
54 | // symbolic link. Refer to General comments on
55 | // filenames on page 30.
56 | //
57 | // symlink
58 | // The symbolic link to create:
59 | //
60 | // symlink_attributes
61 | // The initial attributes for the symbolic link.
62 | //
63 | // symlink_data
64 | // The string containing the symbolic link data.
65 | //
66 | // On successful return, SYMLINK3res.status is NFS3_OK and
67 | // SYMLINK3res.resok contains:
68 | //
69 | // obj
70 | // The file handle for the newly created symbolic link.
71 | //
72 | // obj_attributes
73 | // The attributes for the newly created symbolic link.
74 | //
75 | // dir_wcc
76 | // Weak cache consistency data for the directory,
77 | // where.dir. For a client that requires only the
78 | // post-SYMLINK directory attributes, these can be found
79 | // in dir_wcc.after.
80 | //
81 | // Otherwise, SYMLINK3res.status contains the error on
82 | // failure and SYMLINK3res.resfail contains the following:
83 | //
84 | // dir_wcc
85 | // Weak cache consistency data for the directory,
86 | // where.dir. For a client that requires only the
87 | // post-SYMLINK directory attributes, these can be found
88 | // in dir_wcc.after. Even though the SYMLINK failed, full
89 | // wcc_data is returned to allow the client to determine
90 | // whether the failing SYMLINK changed the directory.
91 | //
92 | // IMPLEMENTATION
93 | //
94 | // Refer to General comments on filenames on page 30.
95 | //
96 | // For symbolic links, the actual file system node and its
97 | // contents are expected to be created in a single atomic
98 | // operation. That is, once the symbolic link is visible,
99 | // there must not be a window where a READLINK would fail or
100 | // return incorrect data.
101 | //
102 | // ERRORS
103 | //
104 | // NFS3ERR_IO
105 | // NFS3ERR_ACCES
106 | // NFS3ERR_EXIST
107 | // NFS3ERR_NOTDIR
108 | // NFS3ERR_NOSPC
109 | // NFS3ERR_ROFS
110 | // NFS3ERR_NAMETOOLONG
111 | // NFS3ERR_DQUOT
112 | // NFS3ERR_STALE
113 | // NFS3ERR_BADHANDLE
114 | // NFS3ERR_NOTSUPP
115 | // NFS3ERR_SERVERFAULT
116 | //
117 | // SEE ALSO
118 | //
119 | // READLINK, CREATE, MKDIR, MKNOD, FSINFO, and PATHCONF.
120 |
121 | var util = require('util');
122 |
123 | var assert = require('assert-plus');
124 | var rpc = require('oncrpc');
125 |
126 | var sattr3 = require('./sattr3');
127 |
128 | var NfsCall = require('./nfs_call').NfsCall;
129 |
130 |
131 |
132 | ///--- Globals
133 |
134 | var XDR = rpc.XDR;
135 |
136 |
137 |
138 | ///--- API
139 |
140 | function SymlinkCall(opts) {
141 | assert.object(opts, 'opts');
142 | assert.optionalObject(opts.where, 'opts.where');
143 | assert.optionalObject(opts.symlink_attributes, 'opts.symlink_attributes');
144 | assert.optionalString(opts.symlink_data, 'opts.symlink_data');
145 |
146 | NfsCall.call(this, opts, true);
147 |
148 | this.where = opts.where || {
149 | dir: '',
150 | name: ''
151 | };
152 | this.symlink_attributes = opts.symlink_attributes || {
153 | mode: null,
154 | uid: null,
155 | gid: null,
156 | size: null,
157 | how_a_time: 0,
158 | atime: null,
159 | how_m_time: 0,
160 | mtime: null
161 | };
162 | this.symlink_data = opts.symlink_data || '';
163 |
164 | this._nfs_symlink_call = true; // MDB
165 | }
166 | util.inherits(SymlinkCall, NfsCall);
167 | Object.defineProperty(SymlinkCall.prototype, 'object', {
168 | get: function object() {
169 | return (this.where.dir);
170 | }
171 | });
172 |
173 |
174 | SymlinkCall.prototype._transform = function _transform(chunk, enc, cb) {
175 | if (this.incoming) {
176 | var xdr = new XDR(chunk);
177 | this.where.dir = xdr.readString();
178 | this.where.name = xdr.readString();
179 | this.symlink_attributes = sattr3.parse(xdr);
180 | this.symlink_data = xdr.readString();
181 | } else {
182 | this.push(chunk);
183 | }
184 |
185 | cb();
186 | };
187 |
188 |
189 | SymlinkCall.prototype.writeHead = function writeHead() {
190 | var len = XDR.byteLength(this.where.dir) + XDR.byteLength(this.where.name);
191 |
192 | len += sattr3.length(this.symlink_attributes);
193 | len += XDR.byteLength(this.symlink_data);
194 |
195 | var xdr = this._serialize(len);
196 |
197 | xdr.writeString(this.where.dir);
198 | xdr.writeString(this.where.name);
199 | sattr3.serialize(xdr, this.symlink_attributes);
200 | xdr.writeString(this.symlink_data);
201 |
202 | this.write(xdr.buffer());
203 | };
204 |
205 |
206 | SymlinkCall.prototype.toString = function toString() {
207 | var fmt = '[object SymlinkCall ]';
209 | return (util.format(fmt, this.xid,
210 | this.where, this.symlink_attributes, this.symlink_data));
211 | };
212 |
213 |
214 |
215 | ///--- Exports
216 |
217 | module.exports = {
218 | SymlinkCall: SymlinkCall
219 | };
220 |
--------------------------------------------------------------------------------
/lib/nfs/symlink_reply.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | //
7 | // 3.3.10 Procedure 10: SYMLINK - Create a symbolic link
8 | //
9 | // SYNOPSIS
10 | //
11 | // SYMLINK3res NFSPROC3_SYMLINK(SYMLINK3args) = 10;
12 | //
13 | // struct symlinkdata3 {
14 | // sattr3 symlink_attributes;
15 | // nfspath3 symlink_data;
16 | // };
17 | //
18 | // struct SYMLINK3args {
19 | // diropargs3 where;
20 | // symlinkdata3 symlink;
21 | // };
22 | //
23 | // struct SYMLINK3resok {
24 | // post_op_fh3 obj;
25 | // post_op_attr obj_attributes;
26 | // wcc_data dir_wcc;
27 | // };
28 | //
29 | // struct SYMLINK3resfail {
30 | // wcc_data dir_wcc;
31 | // };
32 | //
33 | // union SYMLINK3res switch (nfsstat3 status) {
34 | // case NFS3_OK:
35 | // SYMLINK3resok resok;
36 | // default:
37 | // SYMLINK3resfail resfail;
38 | // };
39 | //
40 | // DESCRIPTION
41 | //
42 | // Procedure SYMLINK creates a new symbolic link. On entry,
43 | // the arguments in SYMLINK3args are:
44 | //
45 | // where
46 | // The location of the symbolic link to be created:
47 | //
48 | // dir
49 | // The file handle for the directory in which the
50 | // symbolic link is to be created.
51 | //
52 | // name
53 | // The name that is to be associated with the created
54 | // symbolic link. Refer to General comments on
55 | // filenames on page 30.
56 | //
57 | // symlink
58 | // The symbolic link to create:
59 | //
60 | // symlink_attributes
61 | // The initial attributes for the symbolic link.
62 | //
63 | // symlink_data
64 | // The string containing the symbolic link data.
65 | //
66 | // On successful return, SYMLINK3res.status is NFS3_OK and
67 | // SYMLINK3res.resok contains:
68 | //
69 | // obj
70 | // The file handle for the newly created symbolic link.
71 | //
72 | // obj_attributes
73 | // The attributes for the newly created symbolic link.
74 | //
75 | // dir_wcc
76 | // Weak cache consistency data for the directory,
77 | // where.dir. For a client that requires only the
78 | // post-SYMLINK directory attributes, these can be found
79 | // in dir_wcc.after.
80 | //
81 | // Otherwise, SYMLINK3res.status contains the error on
82 | // failure and SYMLINK3res.resfail contains the following:
83 | //
84 | // dir_wcc
85 | // Weak cache consistency data for the directory,
86 | // where.dir. For a client that requires only the
87 | // post-SYMLINK directory attributes, these can be found
88 | // in dir_wcc.after. Even though the SYMLINK failed, full
89 | // wcc_data is returned to allow the client to determine
90 | // whether the failing SYMLINK changed the directory.
91 | //
92 | // IMPLEMENTATION
93 | //
94 | // Refer to General comments on filenames on page 30.
95 | //
96 | // For symbolic links, the actual file system node and its
97 | // contents are expected to be created in a single atomic
98 | // operation. That is, once the symbolic link is visible,
99 | // there must not be a window where a READLINK would fail or
100 | // return incorrect data.
101 | //
102 | // ERRORS
103 | //
104 | // NFS3ERR_IO
105 | // NFS3ERR_ACCES
106 | // NFS3ERR_EXIST
107 | // NFS3ERR_NOTDIR
108 | // NFS3ERR_NOSPC
109 | // NFS3ERR_ROFS
110 | // NFS3ERR_NAMETOOLONG
111 | // NFS3ERR_DQUOT
112 | // NFS3ERR_STALE
113 | // NFS3ERR_BADHANDLE
114 | // NFS3ERR_NOTSUPP
115 | // NFS3ERR_SERVERFAULT
116 | //
117 | // SEE ALSO
118 | //
119 | // READLINK, CREATE, MKDIR, MKNOD, FSINFO, and PATHCONF.
120 |
121 | var fs = require('fs');
122 | var path = require('path');
123 | var util = require('util');
124 |
125 | var assert = require('assert-plus');
126 | var clone = require('clone');
127 | var rpc = require('oncrpc');
128 |
129 | var nfs_err = require('./errors');
130 | var fattr3 = require('./fattr3');
131 | var wcc_data = require('./wcc_data');
132 | var NfsReply = require('./nfs_reply').NfsReply;
133 |
134 |
135 |
136 | ///--- Globals
137 |
138 | var XDR = rpc.XDR;
139 |
140 |
141 |
142 | ///--- API
143 |
144 | function SymlinkReply(opts) {
145 | NfsReply.call(this, opts);
146 |
147 | this.status = 0;
148 | this.wcc_data = opts.wcc_data | {};
149 |
150 | this._nfs_symlink_reply = true; // MDB
151 | }
152 | util.inherits(SymlinkReply, NfsReply);
153 | SymlinkReply.prototype._allowed_error_codes = [
154 | nfs_err.NFS3ERR_IO,
155 | nfs_err.NFS3ERR_ACCES,
156 | nfs_err.NFS3ERR_EXIST,
157 | nfs_err.NFS3ERR_NOTDIR,
158 | nfs_err.NFS3ERR_NOSPC,
159 | nfs_err.NFS3ERR_ROFS,
160 | nfs_err.NFS3ERR_NAMETOOLONG,
161 | nfs_err.NFS3ERR_DQUOT,
162 | nfs_err.NFS3ERR_STALE,
163 | nfs_err.NFS3ERR_BADHANDLE,
164 | nfs_err.NFS3ERR_NOTSUPP,
165 | nfs_err.NFS3ERR_SERVERFAULT
166 | ];
167 |
168 |
169 | SymlinkReply.prototype.setObjAttributes = function setObjAttributes(stats) {
170 | assert.ok(stats instanceof fs.Stats, 'fs.Stats');
171 |
172 | this.obj_attributes = fattr3.create(stats);
173 |
174 | return (this.obj_attributes);
175 | };
176 |
177 |
178 | SymlinkReply.prototype.set_dir_wcc = function set_dir_wcc() {
179 | this.dir_wcc = wcc_data.create();
180 | return (this.dir_wcc);
181 | };
182 |
183 |
184 | SymlinkReply.prototype._transform = function _transform(chunk, enc, cb) {
185 | if (this.incoming) {
186 | var xdr = new XDR(chunk);
187 |
188 | this.status = xdr.readInt();
189 | if (this.status === 0) {
190 | if (xdr.readBool())
191 | this.obj = xdr.readString();
192 | if (xdr.readBool())
193 | this.obj_attributes = fattr3.parse(xdr);
194 | }
195 |
196 | this.dir_wcc = wcc_data.parse(xdr);
197 | } else {
198 | this.push(chunk);
199 | }
200 |
201 | cb();
202 | };
203 |
204 |
205 | SymlinkReply.prototype.writeHead = function writeHead() {
206 | var len = 4;
207 |
208 | if (this.status === 0) {
209 | len += 4 + XDR.byteLength(this.obj);
210 |
211 | len += 4;
212 | if (this.obj_attributes)
213 | len += fattr3.XDR_SIZE;
214 | }
215 |
216 | len += wcc_data.length(this.dir_wcc);
217 |
218 | var xdr = this._serialize(len);
219 |
220 | xdr.writeInt(this.status);
221 |
222 | if (this.status === 0) {
223 | xdr.writeBool(true);
224 | xdr.writeString(this.obj);
225 | if (this.obj_attributes) {
226 | xdr.writeBool(true);
227 | fattr3.serialize(xdr, this.obj_attributes);
228 | } else {
229 | xdr.writeBool(false);
230 | }
231 |
232 | }
233 |
234 | wcc_data.serialize(xdr, this.dir_wcc);
235 |
236 | this.write(xdr.buffer());
237 | };
238 |
239 |
240 | SymlinkReply.prototype.toString = function toString() {
241 | var fmt = '[object SymlinkReply ]';
243 | return (util.format(fmt, this.xid, this.status, this.obj,
244 | this.obj_attributes, this.dir_wcc));
245 | };
246 |
247 |
248 |
249 | ///--- Exports
250 |
251 | module.exports = {
252 | SymlinkReply: SymlinkReply
253 | };
254 |
--------------------------------------------------------------------------------
/lib/nfs/wcc_data.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var path = require('path');
8 | var util = require('util');
9 |
10 | var assert = require('assert-plus');
11 | var clone = require('clone');
12 | var rpc = require('oncrpc');
13 |
14 | var fattr3 = require('./fattr3');
15 |
16 |
17 | ///--- Globals
18 |
19 | var XDR = rpc.XDR;
20 |
21 |
22 |
23 | // struct nfstime3 {
24 | // uint32 seconds;
25 | // uint32 nseconds;
26 | // };
27 |
28 | // struct wcc_attr {
29 | // size3 size; // uint64
30 | // nfstime3 mtime;
31 | // nfstime3 ctime;
32 | // };
33 |
34 | // union pre_op_attr switch (bool attributes_follow) {
35 | // case TRUE:
36 | // wcc_attr attributes;
37 | // case FALSE:
38 | // void;
39 | // };
40 |
41 | // union post_op_attr switch (bool attributes_follow) {
42 | // case TRUE:
43 | // fattr3 attributes;
44 | // case FALSE:
45 | // void;
46 | // };
47 |
48 | // struct wcc_data {
49 | // pre_op_attr before;
50 | // post_op_attr after;
51 | // };
52 |
53 | // To support the weak cache consistency data return object we must be
54 | // able to atomically stat the file before we make any changes, make
55 | // the changes, then stat the file again once we're done.
56 |
57 | function create_wcc_data() {
58 | var wcc_data = {
59 | before: null,
60 | after: null
61 | };
62 |
63 | return (wcc_data);
64 | }
65 |
66 |
67 | function parse_wcc_data(xdr) {
68 | assert.object(xdr, 'xdr');
69 |
70 | var before;
71 | var after;
72 |
73 | if (xdr.readBool()) {
74 | var size = xdr.readHyper();
75 |
76 | var m_time = {
77 | seconds: xdr.readInt(),
78 | nseconds: xdr.readInt()
79 | };
80 |
81 | var c_time = {
82 | seconds: xdr.readInt(),
83 | nseconds: xdr.readInt()
84 | };
85 |
86 | before = {
87 | size: size,
88 | mtime: m_time,
89 | ctime: c_time
90 | };
91 | } else {
92 | before = null;
93 | }
94 |
95 | if (xdr.readBool()) {
96 | after = fattr3.parse(xdr);
97 | } else {
98 | after = null;
99 | }
100 |
101 | var wcc_data = {
102 | before: before,
103 | after: after
104 | };
105 |
106 | return (wcc_data);
107 | }
108 |
109 |
110 | function serialize_wcc_data(xdr, wcc_data) {
111 | if (wcc_data === undefined || wcc_data === null) {
112 | xdr.writeBool(false);
113 | xdr.writeBool(false);
114 | return (xdr);
115 | }
116 |
117 | if (! wcc_data.before) {
118 | xdr.writeBool(false);
119 | } else {
120 | xdr.writeBool(true);
121 | xdr.writeHyper(wcc_data.size);
122 | xdr.writeInt(wcc_data.mtime.seconds);
123 | xdr.writeInt(wcc_data.mtime.nseconds);
124 | xdr.writeInt(wcc_data.ctime.seconds);
125 | xdr.writeInt(wcc_data.ctime.nseconds);
126 | }
127 |
128 | if (! wcc_data.after) {
129 | xdr.writeBool(false);
130 | } else {
131 | xdr.writeBool(true);
132 | fattr3.serialize_fattr3(xdr, wcc_data.after);
133 | }
134 |
135 | return (xdr);
136 | }
137 |
138 |
139 | function XDR_length(wcc_data) {
140 | var len = 0;
141 |
142 | if (wcc_data === undefined || wcc_data === null) {
143 | len = 8;
144 | } else {
145 | len += 4;
146 | if (wcc_data.before)
147 | len += 24;
148 |
149 | len += 4;
150 | if (wcc_data.after)
151 | len += 24;
152 | }
153 |
154 | return (len);
155 | }
156 |
157 |
158 | ///--- Exports
159 |
160 | module.exports = {
161 | create: create_wcc_data,
162 | parse: parse_wcc_data,
163 | serialize: serialize_wcc_data,
164 | length: XDR_length
165 | };
166 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nfs",
3 | "description": "Node.js bindings for NFS",
4 | "version": "0.1.1",
5 | "author": {
6 | "name": "Joyent, Inc.",
7 | "url": "http://joyent.com/"
8 | },
9 | "license": "MPL-2.0",
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/joyent/node-nfs.git"
13 | },
14 | "bugs": {
15 | "url": "https://github.com/joyent/node-nfs/issues"
16 | },
17 | "main": "lib/index.js",
18 | "dependencies": {
19 | "assert-plus": "0.1.4",
20 | "clone": "0.1.10",
21 | "oncrpc": "0.1.0",
22 | "once": "1.2.0"
23 | },
24 | "devDependencies": {
25 | "bunyan": "0.22.0",
26 | "nodeunit": "0.8.1",
27 | "nodeunit-plus": "0.0.1",
28 | "node-uuid": "1.4.1",
29 | "statvfs": "2.1.0",
30 | "vasync": "1.4.0"
31 | },
32 | "scripts": {
33 | "test": "for f in $(ls test/*.test.js) ; do nodeunit $f ; done"
34 | },
35 | "engines": {
36 | "node": ">=0.10.18 <0.12"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/smf/manifests/portmap.xml.in:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Joyent Manta Portmap Daemon
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/test/helper.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var domain = require('domain');
8 |
9 | var bunyan = require('bunyan');
10 | var once = require('once');
11 |
12 |
13 |
14 | ///--- Hacks
15 |
16 | var _require = require.bind(null);
17 | require = function () {
18 | if (require.cache[__dirname + '/helper.js'])
19 | delete require.cache[__dirname + '/helper.js'];
20 |
21 | _require.apply(require, arguments);
22 | };
23 |
24 |
25 |
26 | ///--- Helpers
27 |
28 | function createLogger(name, stream) {
29 | var log = bunyan.createLogger({
30 | level: (process.env.LOG_LEVEL || 'info'),
31 | name: name || process.argv[1],
32 | stream: stream || process.stdout,
33 | src: true
34 | });
35 | return (log);
36 | }
37 |
38 |
39 |
40 | ///--- Exports
41 |
42 | module.exports = {
43 |
44 | after: function after(teardown) {
45 | module.parent.exports.tearDown = function _teardown(callback) {
46 | var d = domain.create();
47 | var self = this;
48 |
49 | d.once('error', function (err) {
50 | console.error('after: uncaught error\n' + err.stack);
51 | process.exit(1);
52 | });
53 |
54 | d.run(function () {
55 | teardown.call(self, once(callback));
56 | });
57 | };
58 | },
59 |
60 | before: function before(setup) {
61 | module.parent.exports.setUp = function _setup(callback) {
62 | var d = domain.create();
63 | var self = this;
64 |
65 | d.once('error', function (err) {
66 | console.error('before: uncaught error\n' + err.stack);
67 | process.exit(1);
68 | });
69 |
70 | d.run(function () {
71 | setup.call(self, once(callback));
72 | });
73 | };
74 | },
75 |
76 | test: function test(name, tester) {
77 | module.parent.exports[name] = function _(t) {
78 | var d = domain.create();
79 | var self = this;
80 |
81 | d.once('error', function (err) {
82 | t.ifError(err);
83 | t.end();
84 | });
85 |
86 | d.add(t);
87 | d.run(function () {
88 | t.end = once(function () {
89 | t.done();
90 | });
91 | t.notOk = function notOk(ok, message) {
92 | return (t.ok(!ok, message));
93 | };
94 |
95 | tester.call(self, t);
96 | });
97 | };
98 | },
99 |
100 | createLogger: createLogger
101 | };
102 |
103 |
104 |
105 | Object.keys(module.exports).forEach(function (k) {
106 | global[k] = module.exports[k];
107 | });
108 |
--------------------------------------------------------------------------------
/test/mount.test.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var util = require('util');
8 |
9 | var assert = require('assert-plus');
10 | var libuuid = require('node-uuid');
11 | require('nodeunit-plus');
12 |
13 | var nfs = require('../lib');
14 |
15 |
16 |
17 | ///--- Setup/Teardown
18 |
19 | before(function (cb) {
20 | var self = this;
21 | var server = nfs.createMountServer({
22 | log: createLogger('MountTestServer')
23 | });
24 |
25 | assert.ok(server, 'server');
26 |
27 | server.mounts = {};
28 |
29 | server.on('uncaughtException', function (req, res, err) {
30 | console.error(err.stack);
31 | process.exit(1);
32 | });
33 |
34 | server.dump(function dump(req, res, next) {
35 | Object.keys(server.mounts).forEach(function (k) {
36 | res.addMapping({
37 | name: server.mounts[k],
38 | dirpath: k
39 | });
40 | });
41 | res.send();
42 | next();
43 | });
44 |
45 | server.mnt(function mount(req, res, next) {
46 | assert.ok(req.dirpath);
47 | var uuid = libuuid.v4();
48 | server.mounts[req.dirpath] = uuid;
49 | res.setFileHandle(uuid);
50 | res.send();
51 | next();
52 | });
53 |
54 | server.umnt(function unmount(req, res, next) {
55 | assert.ok(req.dirpath);
56 | assert.ok(server.mounts[req.dirpath]);
57 | if (server.mounts[req.dirpath])
58 | delete server.mounts[req.dirpath];
59 | res.send();
60 | next();
61 | });
62 |
63 | server.listen(function () {
64 | var addr = server.address();
65 |
66 | var client = nfs.createMountClient({
67 | log: createLogger('MountClient'),
68 | url: util.format('tcp://%s:%d', addr.address, addr.port)
69 | });
70 |
71 | assert.ok(client, 'client');
72 |
73 | client.once('connect', function () {
74 | self.client = client;
75 | self.server = server;
76 | cb();
77 | });
78 | });
79 | });
80 |
81 |
82 | after(function (cb) {
83 | var self = this;
84 | this.client.close(function () {
85 | self.server.close(cb);
86 | });
87 | });
88 |
89 |
90 |
91 | ///--- Tests
92 |
93 | test('dump', function (t) {
94 | this.client.dump(function (err, reply) {
95 | t.ifError(err);
96 | t.ok(reply);
97 | t.ok(reply.mappings);
98 | t.equal((reply.mappings || []).length, 0);
99 | t.end();
100 | });
101 | });
102 |
103 |
104 | test('mount', function (t) {
105 | var self = this;
106 |
107 | this.client.mnt('/tmp', function (err, reply) {
108 | t.ifError(err);
109 | t.ok(reply);
110 | t.ok(reply.mountinfo);
111 | t.ok(reply.mountinfo.fhandle);
112 | t.ok(reply.mountinfo.auth_flavors);
113 | t.deepEqual(reply.mountinfo.auth_flavors, [1]);
114 |
115 | self.client.dump(function (d_err, d_reply) {
116 | t.ifError(d_err);
117 | t.ok(d_reply);
118 | t.equal(d_reply.mappings.length, 1);
119 | t.equal(d_reply.mappings[0].dirpath, '/tmp');
120 | t.ok(d_reply.mappings[0].name);
121 | t.end();
122 | });
123 | });
124 | });
125 |
126 |
127 | test('unmount', function (t) {
128 | var dirpath = '/tmp';
129 | var self = this;
130 |
131 | this.client.mnt(dirpath, function (err, reply) {
132 | t.ifError(err);
133 | t.ok(reply);
134 | t.ok(reply.mountinfo);
135 | t.ok(reply.mountinfo.fhandle);
136 | t.ok(reply.mountinfo.auth_flavors);
137 | t.deepEqual(reply.mountinfo.auth_flavors, [1]);
138 |
139 | self.client.umnt(dirpath, function (u_err, u_reply) {
140 | t.ifError(u_err);
141 | t.ok(u_reply);
142 |
143 | self.client.dump(function (d_err, d_reply) {
144 | t.ifError(d_err);
145 | t.ok(d_reply);
146 | t.equal(d_reply.mappings.length, 0);
147 | t.end();
148 | });
149 | });
150 | });
151 | });
152 |
--------------------------------------------------------------------------------
/tools/bashstyle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /*
4 | * Copyright (c) 2012, Joyent, Inc. All rights reserved.
5 | *
6 | * bashstyle: check bash scripts for adherence to style guidelines, including:
7 | *
8 | * o no lines longer than 80 characters
9 | * o file does not end with a blank line
10 | *
11 | * Future enhancements could include:
12 | * o indents consistent with respect to tabs, spaces
13 | * o indents consistently sized (all are some multiple of the smallest
14 | * indent, which must be a tab or 4 or 8 spaces)
15 | */
16 |
17 | var mod_assert = require('assert');
18 | var mod_fs = require('fs');
19 |
20 | var nerrors = 0;
21 |
22 | main();
23 | process.exit(0);
24 |
25 | function main()
26 | {
27 | var files = process.argv.slice(2);
28 |
29 | if (files.length === 0) {
30 | console.error('usage: %s file1 [...]',
31 | process.argv.slice(0, 2).join(' '));
32 | process.exit(2);
33 | }
34 |
35 | files.forEach(checkFile);
36 |
37 | if (nerrors != 0)
38 | process.exit(1);
39 | }
40 |
41 | function checkFile(filename)
42 | {
43 | var text = mod_fs.readFileSync(filename, 'utf-8');
44 | var lines = text.split('\n');
45 | var i;
46 |
47 | mod_assert.ok(lines.length > 0);
48 |
49 | /*
50 | * Expand tabs in each line and check for long lines.
51 | */
52 | for (i = 1; i <= lines.length; i++) {
53 | var line = expandTabs(lines[i - 1]);
54 |
55 | if (line.length > 80) {
56 | nerrors++;
57 | console.log('%s: %d: line exceeds 80 columns',
58 | filename, i);
59 | }
60 | }
61 |
62 | /*
63 | * No sane editor lets you save a file without a newline at the very end.
64 | */
65 | if (lines[lines.length - 1].length !== 0) {
66 | nerrors++;
67 | console.log('%s: %d: file does not end with newline',
68 | filename, lines.length);
69 | }
70 |
71 | /*
72 | * Since the file will always end with a newline, the last entry of
73 | * "lines" will actually be blank.
74 | */
75 | if (lines.length > 1 && lines[lines.length - 2].length === 0) {
76 | nerrors++;
77 | console.log('%s: %d: file ends with a blank line',
78 | filename, lines.length - 1);
79 | }
80 | }
81 |
82 | function expandTabs(text)
83 | {
84 | var out = '';
85 | var col = 0;
86 | var j, k;
87 |
88 | for (j = 0; j < text.length; j++) {
89 | if (text[j] != '\t') {
90 | out += text[j];
91 | col++;
92 | continue;
93 | }
94 |
95 | k = 8 - (col % 8);
96 | col += k;
97 |
98 | do {
99 | out += ' ';
100 | } while (--k > 0);
101 |
102 | col += k;
103 | }
104 |
105 | return (out);
106 | }
107 |
--------------------------------------------------------------------------------
/tools/jsl.node.conf:
--------------------------------------------------------------------------------
1 | #
2 | # Configuration File for JavaScript Lint
3 | #
4 | # This configuration file can be used to lint a collection of scripts, or to enable
5 | # or disable warnings for scripts that are linted via the command line.
6 | #
7 |
8 | ### Warnings
9 | # Enable or disable warnings based on requirements.
10 | # Use "+WarningName" to display or "-WarningName" to suppress.
11 | #
12 | +ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent
13 | +ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity
14 | +ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement
15 | +anon_no_return_value # anonymous function does not always return value
16 | +assign_to_function_call # assignment to a function call
17 | -block_without_braces # block statement without curly braces
18 | +comma_separated_stmts # multiple statements separated by commas (use semicolons?)
19 | +comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)
20 | +default_not_at_end # the default case is not at the end of the switch statement
21 | +dup_option_explicit # duplicate "option explicit" control comment
22 | +duplicate_case_in_switch # duplicate case in switch statement
23 | +duplicate_formal # duplicate formal argument {name}
24 | +empty_statement # empty statement or extra semicolon
25 | +identifier_hides_another # identifer {name} hides an identifier in a parent scope
26 | -inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement
27 | +incorrect_version # Expected /*jsl:content-type*/ control comment. The script was parsed with the wrong version.
28 | +invalid_fallthru # unexpected "fallthru" control comment
29 | +invalid_pass # unexpected "pass" control comment
30 | +jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax
31 | +leading_decimal_point # leading decimal point may indicate a number or an object member
32 | +legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax
33 | +meaningless_block # meaningless block; curly braces have no impact
34 | +mismatch_ctrl_comments # mismatched control comment; "ignore" and "end" control comments must have a one-to-one correspondence
35 | +misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma
36 | +missing_break # missing break statement
37 | +missing_break_for_last_case # missing break statement for last case in switch
38 | +missing_default_case # missing default case in switch statement
39 | +missing_option_explicit # the "option explicit" control comment is missing
40 | +missing_semicolon # missing semicolon
41 | +missing_semicolon_for_lambda # missing semicolon for lambda assignment
42 | +multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs
43 | +nested_comment # nested comment
44 | +no_return_value # function {name} does not always return a value
45 | +octal_number # leading zeros make an octal number
46 | +parseint_missing_radix # parseInt missing radix parameter
47 | +partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag
48 | +redeclared_var # redeclaration of {name}
49 | +trailing_comma_in_array # extra comma is not recommended in array initializers
50 | +trailing_decimal_point # trailing decimal point may indicate a number or an object member
51 | +undeclared_identifier # undeclared identifier: {name}
52 | +unreachable_code # unreachable code
53 | -unreferenced_argument # argument declared but never referenced: {name}
54 | -unreferenced_function # function is declared but never referenced: {name}
55 | +unreferenced_variable # variable is declared but never referenced: {name}
56 | +unsupported_version # JavaScript {version} is not supported
57 | +use_of_label # use of label
58 | +useless_assign # useless assignment
59 | +useless_comparison # useless comparison; comparing identical expressions
60 | -useless_quotes # the quotation marks are unnecessary
61 | +useless_void # use of the void type may be unnecessary (void is always undefined)
62 | +var_hides_arg # variable {name} hides argument
63 | +want_assign_or_call # expected an assignment or function call
64 | +with_statement # with statement hides undeclared variables; use temporary variable instead
65 |
66 |
67 | ### Output format
68 | # Customize the format of the error message.
69 | # __FILE__ indicates current file path
70 | # __FILENAME__ indicates current file name
71 | # __LINE__ indicates current line
72 | # __COL__ indicates current column
73 | # __ERROR__ indicates error message (__ERROR_PREFIX__: __ERROR_MSG__)
74 | # __ERROR_NAME__ indicates error name (used in configuration file)
75 | # __ERROR_PREFIX__ indicates error prefix
76 | # __ERROR_MSG__ indicates error message
77 | #
78 | # For machine-friendly output, the output format can be prefixed with
79 | # "encode:". If specified, all items will be encoded with C-slashes.
80 | #
81 | # Visual Studio syntax (default):
82 | +output-format __FILE__(__LINE__): __ERROR__
83 | # Alternative syntax:
84 | #+output-format __FILE__:__LINE__: __ERROR__
85 |
86 |
87 | ### Context
88 | # Show the in-line position of the error.
89 | # Use "+context" to display or "-context" to suppress.
90 | #
91 | +context
92 |
93 |
94 | ### Control Comments
95 | # Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for
96 | # the /*@keyword@*/ control comments and JScript conditional comments. (The latter is
97 | # enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason,
98 | # although legacy control comments are enabled by default for backward compatibility.
99 | #
100 | -legacy_control_comments
101 |
102 |
103 | ### Defining identifiers
104 | # By default, "option explicit" is enabled on a per-file basis.
105 | # To enable this for all files, use "+always_use_option_explicit"
106 | -always_use_option_explicit
107 |
108 | # Define certain identifiers of which the lint is not aware.
109 | # (Use this in conjunction with the "undeclared identifier" warning.)
110 | #
111 | # Common uses for webpages might be:
112 | +define __dirname
113 | +define __filename
114 | +define after
115 | +define before
116 | +define test
117 | +define createLogger
118 | +define clearInterval
119 | +define clearTimeout
120 | +define console
121 | +define exports
122 | +define global
123 | +define module
124 | +define process
125 | +define require
126 | +define setInterval
127 | +define setTimeout
128 | +define Buffer
129 | +define JSON
130 | +define Math
131 |
132 | ### JavaScript Version
133 | # To change the default JavaScript version:
134 | #+default-type text/javascript;version=1.5
135 | #+default-type text/javascript;e4x=1
136 |
137 | ### Files
138 | # Specify which files to lint
139 | # Use "+recurse" to enable recursion (disabled by default).
140 | # To add a set of files, use "+process FileName", "+process Folder\Path\*.js",
141 | # or "+process Folder\Path\*.htm".
142 | #
143 |
144 |
--------------------------------------------------------------------------------
/tools/jsl.web.conf:
--------------------------------------------------------------------------------
1 | #
2 | # Configuration File for JavaScript Lint
3 | # Developed by Matthias Miller (http://www.JavaScriptLint.com)
4 | #
5 | # This configuration file can be used to lint a collection of scripts, or to enable
6 | # or disable warnings for scripts that are linted via the command line.
7 | #
8 |
9 | ### Warnings
10 | # Enable or disable warnings based on requirements.
11 | # Use "+WarningName" to display or "-WarningName" to suppress.
12 | #
13 | +ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent
14 | +ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity
15 | +ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement
16 | +anon_no_return_value # anonymous function does not always return value
17 | +assign_to_function_call # assignment to a function call
18 | -block_without_braces # block statement without curly braces
19 | +comma_separated_stmts # multiple statements separated by commas (use semicolons?)
20 | +comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)
21 | +default_not_at_end # the default case is not at the end of the switch statement
22 | +dup_option_explicit # duplicate "option explicit" control comment
23 | +duplicate_case_in_switch # duplicate case in switch statement
24 | +duplicate_formal # duplicate formal argument {name}
25 | +empty_statement # empty statement or extra semicolon
26 | +identifier_hides_another # identifer {name} hides an identifier in a parent scope
27 | +inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement
28 | +incorrect_version # Expected /*jsl:content-type*/ control comment. The script was parsed with the wrong version.
29 | +invalid_fallthru # unexpected "fallthru" control comment
30 | +invalid_pass # unexpected "pass" control comment
31 | +jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax
32 | +leading_decimal_point # leading decimal point may indicate a number or an object member
33 | +legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax
34 | +meaningless_block # meaningless block; curly braces have no impact
35 | +mismatch_ctrl_comments # mismatched control comment; "ignore" and "end" control comments must have a one-to-one correspondence
36 | +misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma
37 | +missing_break # missing break statement
38 | +missing_break_for_last_case # missing break statement for last case in switch
39 | +missing_default_case # missing default case in switch statement
40 | +missing_option_explicit # the "option explicit" control comment is missing
41 | +missing_semicolon # missing semicolon
42 | +missing_semicolon_for_lambda # missing semicolon for lambda assignment
43 | +multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs
44 | +nested_comment # nested comment
45 | +no_return_value # function {name} does not always return a value
46 | +octal_number # leading zeros make an octal number
47 | +parseint_missing_radix # parseInt missing radix parameter
48 | +partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag
49 | +redeclared_var # redeclaration of {name}
50 | +trailing_comma_in_array # extra comma is not recommended in array initializers
51 | +trailing_decimal_point # trailing decimal point may indicate a number or an object member
52 | +undeclared_identifier # undeclared identifier: {name}
53 | +unreachable_code # unreachable code
54 | +unreferenced_argument # argument declared but never referenced: {name}
55 | +unreferenced_function # function is declared but never referenced: {name}
56 | +unreferenced_variable # variable is declared but never referenced: {name}
57 | +unsupported_version # JavaScript {version} is not supported
58 | +use_of_label # use of label
59 | +useless_assign # useless assignment
60 | +useless_comparison # useless comparison; comparing identical expressions
61 | +useless_quotes # the quotation marks are unnecessary
62 | +useless_void # use of the void type may be unnecessary (void is always undefined)
63 | +var_hides_arg # variable {name} hides argument
64 | +want_assign_or_call # expected an assignment or function call
65 | +with_statement # with statement hides undeclared variables; use temporary variable instead
66 |
67 |
68 | ### Output format
69 | # Customize the format of the error message.
70 | # __FILE__ indicates current file path
71 | # __FILENAME__ indicates current file name
72 | # __LINE__ indicates current line
73 | # __COL__ indicates current column
74 | # __ERROR__ indicates error message (__ERROR_PREFIX__: __ERROR_MSG__)
75 | # __ERROR_NAME__ indicates error name (used in configuration file)
76 | # __ERROR_PREFIX__ indicates error prefix
77 | # __ERROR_MSG__ indicates error message
78 | #
79 | # For machine-friendly output, the output format can be prefixed with
80 | # "encode:". If specified, all items will be encoded with C-slashes.
81 | #
82 | # Visual Studio syntax (default):
83 | +output-format __FILE__(__LINE__): __ERROR__
84 | # Alternative syntax:
85 | #+output-format __FILE__:__LINE__: __ERROR__
86 |
87 |
88 | ### Context
89 | # Show the in-line position of the error.
90 | # Use "+context" to display or "-context" to suppress.
91 | #
92 | +context
93 |
94 |
95 | ### Control Comments
96 | # Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for
97 | # the /*@keyword@*/ control comments and JScript conditional comments. (The latter is
98 | # enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason,
99 | # although legacy control comments are enabled by default for backward compatibility.
100 | #
101 | -legacy_control_comments
102 |
103 |
104 | ### Defining identifiers
105 | # By default, "option explicit" is enabled on a per-file basis.
106 | # To enable this for all files, use "+always_use_option_explicit"
107 | +always_use_option_explicit
108 |
109 | # Define certain identifiers of which the lint is not aware.
110 | # (Use this in conjunction with the "undeclared identifier" warning.)
111 | #
112 | # Common uses for webpages might be:
113 | +define JSON
114 | +define Math
115 | +define $
116 | +define XMLHttpRequest
117 | +define alert
118 | +define clearInterval
119 | +define clearTimeout
120 | +define confirm
121 | +define document
122 | +define setInterval
123 | +define setTimeout
124 | +define window
125 |
126 | ### JavaScript Version
127 | # To change the default JavaScript version:
128 | #+default-type text/javascript;version=1.5
129 | #+default-type text/javascript;e4x=1
130 |
131 | ### Files
132 | # Specify which files to lint
133 | # Use "+recurse" to enable recursion (disabled by default).
134 | # To add a set of files, use "+process FileName", "+process Folder\Path\*.js",
135 | # or "+process Folder\Path\*.htm".
136 | #
137 |
138 |
--------------------------------------------------------------------------------
/tools/jsstyle.conf:
--------------------------------------------------------------------------------
1 | indent=2
2 | doxygen
3 | unparenthesized-return=0
4 | blank-after-start-comment=0
5 |
--------------------------------------------------------------------------------
/tools/mk/Makefile.defs:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Makefile.defs: common defines.
6 | #
7 | # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
8 | # into other repos as-is without requiring any modifications. If you find
9 | # yourself changing this file, you should instead update the original copy in
10 | # eng.git and then update your repo to use the new version.
11 | #
12 | # This makefile defines some useful defines. Include it at the top of
13 | # your Makefile.
14 | #
15 | # Definitions in this Makefile:
16 | #
17 | # TOP The absolute path to the project directory. The top dir.
18 | # BRANCH The current git branch.
19 | # TIMESTAMP The timestamp for the build. This can be set via
20 | # the TIMESTAMP envvar (used by MG-based builds).
21 | # STAMP A build stamp to use in built package names.
22 | #
23 |
24 | TOP := $(shell pwd)
25 |
26 | #
27 | # Mountain Gorilla-spec'd versioning.
28 | # See "Package Versioning" in MG's README.md:
29 | #
30 | #
31 | # Need GNU awk for multi-char arg to "-F".
32 | _AWK := $(shell (which gawk >/dev/null && echo gawk) \
33 | || (which nawk >/dev/null && echo nawk) \
34 | || echo awk)
35 | BRANCH := $(shell git symbolic-ref HEAD | $(_AWK) -F/ '{print $$3}')
36 | ifeq ($(TIMESTAMP),)
37 | TIMESTAMP := $(shell date -u "+%Y%m%dT%H%M%SZ")
38 | endif
39 | _GITDESCRIBE := g$(shell git describe --all --long --dirty | $(_AWK) -F'-g' '{print $$NF}')
40 | STAMP := $(BRANCH)-$(TIMESTAMP)-$(_GITDESCRIBE)
41 |
42 | # node-gyp will print build info useful for debugging with V=1
43 | export V=1
44 |
--------------------------------------------------------------------------------
/tools/mk/Makefile.deps:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Makefile.deps: Makefile for including common tools as dependencies
6 | #
7 | # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
8 | # into other repos as-is without requiring any modifications. If you find
9 | # yourself changing this file, you should instead update the original copy in
10 | # eng.git and then update your repo to use the new version.
11 | #
12 | # This file is separate from Makefile.targ so that teams can choose
13 | # independently whether to use the common targets in Makefile.targ and the
14 | # common tools here.
15 | #
16 |
17 | #
18 | # javascriptlint
19 | #
20 | JSL_EXEC ?= deps/javascriptlint/build/install/jsl
21 | JSL ?= $(JSL_EXEC)
22 |
23 | $(JSL_EXEC): | deps/javascriptlint/.git
24 | cd deps/javascriptlint && make install
25 |
26 | distclean::
27 | if [[ -f deps/javascriptlint/Makefile ]]; then \
28 | cd deps/javascriptlint && make clean; \
29 | fi
30 |
31 | #
32 | # jsstyle
33 | #
34 | JSSTYLE_EXEC ?= deps/jsstyle/jsstyle
35 | JSSTYLE ?= $(JSSTYLE_EXEC)
36 |
37 | $(JSSTYLE_EXEC): | deps/jsstyle/.git
38 |
39 | #
40 | # restdown
41 | #
42 | RESTDOWN_EXEC ?= deps/restdown/bin/restdown
43 | RESTDOWN ?= python $(RESTDOWN_EXEC)
44 | $(RESTDOWN_EXEC): | deps/restdown/.git
45 |
--------------------------------------------------------------------------------
/tools/mk/Makefile.node_deps.defs:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Makefile.node_deps.defs: Makefile for including npm modules whose sources
6 | # reside inside the repo. This should NOT be used for modules in the npm
7 | # public repo or modules that could be specified with git SHAs.
8 | #
9 | # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
10 | # into other repos as-is without requiring any modifications. If you find
11 | # yourself changing this file, you should instead update the original copy in
12 | # eng.git and then update your repo to use the new version.
13 | #
14 |
15 | #
16 | # This Makefile takes as input the following make variable:
17 | #
18 | # REPO_MODULES List of relative paths to node modules (i.e., npm
19 | # packages) inside this repo. For example:
20 | # src/node-canative, where there's a binary npm package
21 | # in src/node-canative.
22 | #
23 | # Based on the above, this Makefile defines the following new variables:
24 | #
25 | # REPO_DEPS List of relative paths to the installed modules. For
26 | # example: "node_modules/canative".
27 | #
28 | # The accompanying Makefile.node_deps.targ defines a target that will install
29 | # each of REPO_MODULES into REPO_DEPS and remove REPO_DEPS with "make clean".
30 | # The top-level Makefile is responsible for depending on REPO_DEPS where
31 | # appropriate (usually the "deps" or "all" target).
32 | #
33 |
34 | REPO_DEPS = $(REPO_MODULES:src/node-%=node_modules/%)
35 | CLEAN_FILES += $(REPO_DEPS)
36 |
--------------------------------------------------------------------------------
/tools/mk/Makefile.node_deps.targ:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Makefile.node_deps.targ: targets for Makefile.node_deps.defs.
6 | #
7 | # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
8 | # into other repos as-is without requiring any modifications. If you find
9 | # yourself changing this file, you should instead update the original copy in
10 | # eng.git and then update your repo to use the new version.
11 | #
12 |
13 | NPM_EXEC ?= $(error NPM_EXEC must be defined for Makefile.node_deps.targ)
14 |
15 | node_modules/%: src/node-% | $(NPM_EXEC)
16 | $(NPM) install $<
17 |
--------------------------------------------------------------------------------
/tools/mk/Makefile.smf.defs:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Makefile.smf.defs: common targets for SMF manifests
6 | #
7 | # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
8 | # into other repos as-is without requiring any modifications. If you find
9 | # yourself changing this file, you should instead update the original copy in
10 | # eng.git and then update your repo to use the new version.
11 | #
12 | # This Makefile uses the following definitions:
13 | #
14 | # SMF_MANIFESTS_IN Source files for SMF manifests. The following
15 | # substitutions will be made on these files:
16 | #
17 | # @@NODE@@ path to installed node
18 | #
19 | # It updates SMF_MANIFESTS with the set of files generated by SMF_MANIFESTS_IN.
20 | # It also updates the "check" target to check the XML syntax of all manifests,
21 | # generated or otherwise.
22 | #
23 | # To use this file, be sure to also include Makefile.smf.targ after defining
24 | # targets.
25 | #
26 |
27 | SED ?= sed
28 | SMF_DTD ?= tools/service_bundle.dtd.1
29 | XMLLINT ?= xmllint --noout
30 |
31 | SMF_MANIFESTS += $(SMF_MANIFESTS_IN:%.in=%)
32 | CLEAN_FILES += $(SMF_MANIFESTS_IN:%.in=%)
33 |
--------------------------------------------------------------------------------
/tools/mk/Makefile.smf.targ:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Makefile.smf.targ: see Makefile.smf.defs.
6 | #
7 | # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
8 | # into other repos as-is without requiring any modifications. If you find
9 | # yourself changing this file, you should instead update the original copy in
10 | # eng.git and then update your repo to use the new version.
11 | #
12 | .PHONY: check-manifests
13 | check-manifests: $(SMF_MANIFESTS:%=%.smfchk)
14 |
15 | %.smfchk: %
16 | $(XMLLINT) --path $(dir $(SMF_DTD)) --dtdvalid $(SMF_DTD) $^
17 |
18 | check: check-manifests
19 |
20 | $(SMF_MANIFESTS): %: %.in
21 | $(SED) -e 's#@@NODE@@#@@PREFIX@@/$(NODE_INSTALL)/bin/node#' $< > $@
22 |
--------------------------------------------------------------------------------
/tools/mkrepo:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | // -*- mode: js -*-
3 | // Copyright 2012 Joyent, Inc. All rights reserved.
4 |
5 | var child_process = require('child_process');
6 | var fs = require('fs');
7 | var path = require('path');
8 |
9 |
10 |
11 | ///--- Globals
12 |
13 | var DIRS = [
14 | 'deps',
15 | 'docs',
16 | 'docs/media',
17 | 'lib',
18 | 'smf',
19 | 'smf/manifests',
20 | 'test',
21 | 'tools',
22 | 'tools/mk'
23 | ];
24 |
25 | var SUBMODULES = {
26 | 'javascriptlint': 'git://github.com/davepacheco/javascriptlint.git',
27 | 'jsstyle': 'git://github.com/davepacheco/jsstyle.git',
28 | 'restdown': 'git://github.com/trentm/restdown.git'
29 | };
30 |
31 |
32 |
33 | ///--- Internal Functions
34 |
35 | function usage(code, message) {
36 | if (message)
37 | console.error(message);
38 |
39 | console.error('usage: %s [repo ...]', path.basename(process.argv[1]));
40 | process.exit(code);
41 | }
42 |
43 |
44 | function ensureDirectoryNotExists(dir) {
45 | try {
46 | var stats = fs.statSync(dir);
47 | usage(1, dir + ' already exists');
48 | } catch (e) {
49 | return false;
50 | }
51 | }
52 |
53 |
54 | function cp(src, dest) {
55 | fs.createReadStream(src).pipe(fs.createWriteStream(dest));
56 | }
57 |
58 |
59 | function exec(cmd, dir, cb) {
60 | child_process.exec(cmd, {cwd: dir}, function (err, stdout, stderr) {
61 | if (err)
62 | process.exit(err.code || 1);
63 |
64 | if (typeof (cb) === 'function')
65 | return cb(null);
66 | });
67 | }
68 |
69 |
70 | function mkdir(d) {
71 | fs.mkdirSync(d, '0750');
72 | }
73 |
74 | function gitify(dir, repo) {
75 | exec('git init', dir, function () {
76 | exec('git remote add origin git@git.joyent.com:' + repo + '.git', dir);
77 |
78 | Object.keys(SUBMODULES).forEach(function (k) {
79 | // stub out the git submodule call
80 | console.error('Cloning into deps/' + k + '...');
81 | exec('git submodule add ' + SUBMODULES[k] + ' ./deps/' + k, dir);
82 | });
83 | });
84 | }
85 |
86 |
87 |
88 | ///--- Mainline
89 |
90 | if (process.argv.length < 3)
91 | usage(1, 'repo required');
92 |
93 | process.argv.slice(2).forEach(function (arg) {
94 | var repo = path.resolve(arg);
95 | ensureDirectoryNotExists(repo);
96 | mkdir(repo);
97 | DIRS.concat('.').forEach(function (d) {
98 | var dir = repo + '/' + d;
99 | if (d != '.')
100 | mkdir(dir);
101 |
102 | fs.readdirSync('./' + d).forEach(function (f) {
103 | var src = './' + d + '/' + f;
104 | var dest = dir + '/' + f;
105 | if (fs.statSync(src).isFile() && !/^\..*/.test(f))
106 | cp(src, dest);
107 | });
108 | });
109 |
110 | cp('./.gitignore', repo + '/.gitignore');
111 | gitify(repo, arg);
112 | });
113 |
--------------------------------------------------------------------------------
/tools/runtests.in:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Run the TODONAME tests.
6 | # Run `./runtests -h` for usage info.
7 | #
8 |
9 | if [ "$TRACE" != "" ]; then
10 | export PS4='${BASH_SOURCE}:${LINENO}: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
11 | set -o xtrace
12 | fi
13 | set -o errexit
14 | set -o pipefail
15 |
16 |
17 |
18 | #---- guard
19 |
20 | if [[ ! -f "/lib/sdc/.sdc-test-no-production-data" ]]; then
21 | cat <