Merge pull request #373 from humphd/9p-filer
Update Filer to support Plan 9 virtio filesystem API in v86
This commit is contained in:
commit
2e90fdae0c
107
README.md
107
README.md
|
@ -294,6 +294,10 @@ var fs = new Filer.FileSystem();
|
|||
* [fs.close(fd, callback)](#close)
|
||||
* [fs.open(path, flags, [mode], callback)](#open)
|
||||
* [fs.utimes(path, atime, mtime, callback)](#utimes)
|
||||
* [fs.chown(path, uid, gid, callback)](#chown)
|
||||
* [fs.fchown(fd, uid, gid, callback)](#fchown)
|
||||
* [fs.chmod(path, mode, callback)](#chmod)
|
||||
* [fs.fchmod(fd, mode, callback)](#fchmod)
|
||||
* [fs.futimes(fd, atime, mtime, callback)](#fsutimes)
|
||||
* [fs.fsync(fd, callback)](#fsync)
|
||||
* [fs.write(fd, buffer, offset, length, position, callback)](#write)
|
||||
|
@ -399,12 +403,17 @@ Callback gets `(error, stats)`, where `stats` is an object with the following pr
|
|||
{
|
||||
node: <string> // internal node id (unique)
|
||||
dev: <string> // file system name
|
||||
name: <string> // the entry's name (basename)
|
||||
size: <number> // file size in bytes
|
||||
nlinks: <number> // number of links
|
||||
atime: <number> // last access time
|
||||
mtime: <number> // last modified time
|
||||
ctime: <number> // creation time
|
||||
type: <string> // file type (FILE, DIRECTORY, SYMLINK)
|
||||
type: <string> // file type (FILE, DIRECTORY, SYMLINK),
|
||||
gid: <number> // group name
|
||||
uid: <number> // owner name
|
||||
mode: <number> // permissions
|
||||
version: <number> // version of the node
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -749,6 +758,89 @@ fs.open('/myfile.txt', function(err, fd) {
|
|||
});
|
||||
```
|
||||
|
||||
#### fs.chown(path, uid, gid, callback)<a name="chown"></a>
|
||||
|
||||
Changes the owner and group of a file. Asynchronous [chown(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/chown.html). Callback gets no additional arguments. Both `uid` (user id) and `gid` (group id) arguments should be a JavaScript Number. By default, `0x0` is used (i.e., `root:root` ownership).
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
fs.chown('/myfile.txt', 500, 500, function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
// /myfile.txt is now owned by user with id 500, group 500
|
||||
});
|
||||
```
|
||||
|
||||
#### fs.fchown(fd, uid, gid, callback)<a name="fchown"></a>
|
||||
|
||||
Changes the owner and group of a file. Asynchronous [chown(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/chown.html). Callback gets no additional arguments. Both `uid` (user id) and `gid` (group id) arguments should be a JavaScript Number. By default, `0x0` is used (i.e., `root:root` ownership).
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
fs.open('/myfile.txt', function(err, fd) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.fchown(fd, 500, 500, function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
// /myfile.txt is now owned by user with id 500, group 500
|
||||
|
||||
fs.close(fd);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
#### fs.chmod(path, mode, callback)<a name="chmod"></a>
|
||||
|
||||
Changes the mode of a file. Asynchronous [chmod(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/chmod.html). Callback gets no additional arguments. The `mode` argument should be a JavaScript Number, which combines file type and permission information. Here are a list of common values useful for setting the `mode`:
|
||||
|
||||
* File type `S_IFREG=0x8000`
|
||||
* Dir type `S_IFDIR=0x4000`
|
||||
* Link type `S_IFLNK=0xA000`
|
||||
|
||||
* Permissions `755=0x1ED`
|
||||
* Permissions `644=0x1A4`
|
||||
* Permissions `777=0x1FF`
|
||||
* Permissions `666=0x1B6`
|
||||
|
||||
By default, directories use `(0x4000 | 0x1ED)` and files use `(0x8000 | 0x1A4)`.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
// S_IFREG | 0o777
|
||||
var mode = 0x8000 | 0x1FF
|
||||
fs.chmod('/myfile.txt', mode, function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
// /myfile.txt is a regular file with permissions 777
|
||||
});
|
||||
```
|
||||
|
||||
#### fs.fchmod(fd, mode, callback)<a name="fchmod"></a>
|
||||
|
||||
Changes the mode of a file. Asynchronous [chmod(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/chmod.html). Callback gets no additional arguments. The `mode` argument should be a JavaScript Number, which combines file type and permission information. By default, `755` (dir) and `644` (file) are used.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
fs.open('/myfile.txt', function(err, fd) {
|
||||
if(err) throw err;
|
||||
|
||||
// S_IFREG | 0o777
|
||||
var mode = 0x8000 | 0x1FF
|
||||
fs.fchmod(fd, mode, function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
// /myfile.txt is a regular file with permissions 777
|
||||
|
||||
fs.close(fd);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
#### fs.fsync(fd, callback)<a name="fsync"></a>
|
||||
|
||||
NOTE: Not yet implemented, see https://github.com/filerjs/filer/issues/87
|
||||
|
@ -1263,17 +1355,8 @@ sh.find('/app/user', {
|
|||
#### sh.ls(dir, [options], callback)<a name="ls"></a>
|
||||
|
||||
Get the listing of a directory, returning an array of directory entries
|
||||
in the following form:
|
||||
```
|
||||
{
|
||||
path: <String> the basename of the directory entry
|
||||
links: <Number> the number of links to the entry
|
||||
size: <Number> the size in bytes of the entry
|
||||
modified: <Number> the last modified date/time
|
||||
type: <String> the type of the entry
|
||||
contents: <Array> an optional array of child entries, if this entry is itself a directory
|
||||
}
|
||||
```
|
||||
in the same form as [fs.stat()](#stat), with the exception that a new Array named
|
||||
`contents` is added for directory entries, containing child entries.
|
||||
|
||||
By default `sh.ls()` gives a shallow listing. If you want to follow
|
||||
directories as they are encountered, use the `recursive=true` option. NOTE:
|
||||
|
|
|
@ -1,21 +1,150 @@
|
|||
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.FilerBuffer = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||||
var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
|
||||
;(function (exports) {
|
||||
'use strict';
|
||||
|
||||
var Arr = (typeof Uint8Array !== 'undefined')
|
||||
? Uint8Array
|
||||
: Array
|
||||
|
||||
var PLUS = '+'.charCodeAt(0)
|
||||
var SLASH = '/'.charCodeAt(0)
|
||||
var NUMBER = '0'.charCodeAt(0)
|
||||
var LOWER = 'a'.charCodeAt(0)
|
||||
var UPPER = 'A'.charCodeAt(0)
|
||||
var PLUS_URL_SAFE = '-'.charCodeAt(0)
|
||||
var SLASH_URL_SAFE = '_'.charCodeAt(0)
|
||||
|
||||
function decode (elt) {
|
||||
var code = elt.charCodeAt(0)
|
||||
if (code === PLUS ||
|
||||
code === PLUS_URL_SAFE)
|
||||
return 62 // '+'
|
||||
if (code === SLASH ||
|
||||
code === SLASH_URL_SAFE)
|
||||
return 63 // '/'
|
||||
if (code < NUMBER)
|
||||
return -1 //no match
|
||||
if (code < NUMBER + 10)
|
||||
return code - NUMBER + 26 + 26
|
||||
if (code < UPPER + 26)
|
||||
return code - UPPER
|
||||
if (code < LOWER + 26)
|
||||
return code - LOWER + 26
|
||||
}
|
||||
|
||||
function b64ToByteArray (b64) {
|
||||
var i, j, l, tmp, placeHolders, arr
|
||||
|
||||
if (b64.length % 4 > 0) {
|
||||
throw new Error('Invalid string. Length must be a multiple of 4')
|
||||
}
|
||||
|
||||
// the number of equal signs (place holders)
|
||||
// if there are two placeholders, than the two characters before it
|
||||
// represent one byte
|
||||
// if there is only one, then the three characters before it represent 2 bytes
|
||||
// this is just a cheap hack to not do indexOf twice
|
||||
var len = b64.length
|
||||
placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0
|
||||
|
||||
// base64 is 4/3 + up to two characters of the original data
|
||||
arr = new Arr(b64.length * 3 / 4 - placeHolders)
|
||||
|
||||
// if there are placeholders, only get up to the last complete 4 chars
|
||||
l = placeHolders > 0 ? b64.length - 4 : b64.length
|
||||
|
||||
var L = 0
|
||||
|
||||
function push (v) {
|
||||
arr[L++] = v
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; i < l; i += 4, j += 3) {
|
||||
tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))
|
||||
push((tmp & 0xFF0000) >> 16)
|
||||
push((tmp & 0xFF00) >> 8)
|
||||
push(tmp & 0xFF)
|
||||
}
|
||||
|
||||
if (placeHolders === 2) {
|
||||
tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)
|
||||
push(tmp & 0xFF)
|
||||
} else if (placeHolders === 1) {
|
||||
tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)
|
||||
push((tmp >> 8) & 0xFF)
|
||||
push(tmp & 0xFF)
|
||||
}
|
||||
|
||||
return arr
|
||||
}
|
||||
|
||||
function uint8ToBase64 (uint8) {
|
||||
var i,
|
||||
extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
|
||||
output = "",
|
||||
temp, length
|
||||
|
||||
function encode (num) {
|
||||
return lookup.charAt(num)
|
||||
}
|
||||
|
||||
function tripletToBase64 (num) {
|
||||
return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)
|
||||
}
|
||||
|
||||
// go through the array every three bytes, we'll deal with trailing stuff later
|
||||
for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
|
||||
temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
|
||||
output += tripletToBase64(temp)
|
||||
}
|
||||
|
||||
// pad the end with zeros, but make sure to not forget the extra bytes
|
||||
switch (extraBytes) {
|
||||
case 1:
|
||||
temp = uint8[uint8.length - 1]
|
||||
output += encode(temp >> 2)
|
||||
output += encode((temp << 4) & 0x3F)
|
||||
output += '=='
|
||||
break
|
||||
case 2:
|
||||
temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])
|
||||
output += encode(temp >> 10)
|
||||
output += encode((temp >> 4) & 0x3F)
|
||||
output += encode((temp << 2) & 0x3F)
|
||||
output += '='
|
||||
break
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
exports.toByteArray = b64ToByteArray
|
||||
exports.fromByteArray = uint8ToBase64
|
||||
}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))
|
||||
|
||||
},{}],2:[function(require,module,exports){
|
||||
(function (global){
|
||||
/*!
|
||||
* The buffer module from node.js, for the browser.
|
||||
*
|
||||
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
|
||||
* @license MIT
|
||||
*/
|
||||
/* eslint-disable no-proto */
|
||||
|
||||
'use strict'
|
||||
|
||||
var base64 = require('base64-js')
|
||||
var ieee754 = require('ieee754')
|
||||
var isArray = require('is-array')
|
||||
var isArray = require('isarray')
|
||||
|
||||
exports.Buffer = Buffer
|
||||
exports.SlowBuffer = SlowBuffer
|
||||
exports.INSPECT_MAX_BYTES = 50
|
||||
Buffer.poolSize = 8192 // not used by this implementation
|
||||
|
||||
var kMaxLength = 0x3fffffff
|
||||
var rootParent = {}
|
||||
|
||||
/**
|
||||
|
@ -26,32 +155,49 @@ var rootParent = {}
|
|||
* Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
|
||||
* Opera 11.6+, iOS 4.2+.
|
||||
*
|
||||
* Due to various browser bugs, sometimes the Object implementation will be used even
|
||||
* when the browser supports typed arrays.
|
||||
*
|
||||
* Note:
|
||||
*
|
||||
* - Implementation must support adding new properties to `Uint8Array` instances.
|
||||
* Firefox 4-29 lacked support, fixed in Firefox 30+.
|
||||
* - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,
|
||||
* See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.
|
||||
*
|
||||
* - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property
|
||||
* on objects.
|
||||
*
|
||||
* - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.
|
||||
*
|
||||
* - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of
|
||||
* incorrect length in some situations.
|
||||
*
|
||||
* We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they will
|
||||
* get the Object implementation, which is slower but will work correctly.
|
||||
|
||||
* We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they
|
||||
* get the Object implementation, which is slower but behaves correctly.
|
||||
*/
|
||||
Buffer.TYPED_ARRAY_SUPPORT = (function () {
|
||||
Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined
|
||||
? global.TYPED_ARRAY_SUPPORT
|
||||
: typedArraySupport()
|
||||
|
||||
function typedArraySupport () {
|
||||
function Bar () {}
|
||||
try {
|
||||
var buf = new ArrayBuffer(0)
|
||||
var arr = new Uint8Array(buf)
|
||||
var arr = new Uint8Array(1)
|
||||
arr.foo = function () { return 42 }
|
||||
arr.constructor = Bar
|
||||
return arr.foo() === 42 && // typed array instances can be augmented
|
||||
arr.constructor === Bar && // constructor can be set
|
||||
typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`
|
||||
new Uint8Array(1).subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`
|
||||
arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
})()
|
||||
}
|
||||
|
||||
function kMaxLength () {
|
||||
return Buffer.TYPED_ARRAY_SUPPORT
|
||||
? 0x7fffffff
|
||||
: 0x3fffffff
|
||||
}
|
||||
|
||||
/**
|
||||
* Class: Buffer
|
||||
|
@ -72,8 +218,10 @@ function Buffer (arg) {
|
|||
return new Buffer(arg)
|
||||
}
|
||||
|
||||
if (!Buffer.TYPED_ARRAY_SUPPORT) {
|
||||
this.length = 0
|
||||
this.parent = undefined
|
||||
}
|
||||
|
||||
// Common case.
|
||||
if (typeof arg === 'number') {
|
||||
|
@ -119,9 +267,14 @@ function fromObject (that, object) {
|
|||
throw new TypeError('must start with number, buffer, array or string')
|
||||
}
|
||||
|
||||
if (typeof ArrayBuffer !== 'undefined' && object.buffer instanceof ArrayBuffer) {
|
||||
if (typeof ArrayBuffer !== 'undefined') {
|
||||
if (object.buffer instanceof ArrayBuffer) {
|
||||
return fromTypedArray(that, object)
|
||||
}
|
||||
if (object instanceof ArrayBuffer) {
|
||||
return fromArrayBuffer(that, object)
|
||||
}
|
||||
}
|
||||
|
||||
if (object.length) return fromArrayLike(that, object)
|
||||
|
||||
|
@ -157,6 +310,18 @@ function fromTypedArray (that, array) {
|
|||
return that
|
||||
}
|
||||
|
||||
function fromArrayBuffer (that, array) {
|
||||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||||
// Return an augmented `Uint8Array` instance, for best performance
|
||||
array.byteLength
|
||||
that = Buffer._augment(new Uint8Array(array))
|
||||
} else {
|
||||
// Fallback: Return an object instance of the Buffer class
|
||||
that = fromTypedArray(that, new Uint8Array(array))
|
||||
}
|
||||
return that
|
||||
}
|
||||
|
||||
function fromArrayLike (that, array) {
|
||||
var length = checked(array.length) | 0
|
||||
that = allocate(that, length)
|
||||
|
@ -184,10 +349,20 @@ function fromJsonObject (that, object) {
|
|||
return that
|
||||
}
|
||||
|
||||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||||
Buffer.prototype.__proto__ = Uint8Array.prototype
|
||||
Buffer.__proto__ = Uint8Array
|
||||
} else {
|
||||
// pre-set for values that may exist in the future
|
||||
Buffer.prototype.length = undefined
|
||||
Buffer.prototype.parent = undefined
|
||||
}
|
||||
|
||||
function allocate (that, length) {
|
||||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||||
// Return an augmented `Uint8Array` instance, for best performance
|
||||
that = Buffer._augment(new Uint8Array(length))
|
||||
that.__proto__ = Buffer.prototype
|
||||
} else {
|
||||
// Fallback: Return an object instance of the Buffer class
|
||||
that.length = length
|
||||
|
@ -203,9 +378,9 @@ function allocate (that, length) {
|
|||
function checked (length) {
|
||||
// Note: cannot use `length < kMaxLength` here because that fails when
|
||||
// length is NaN (which is otherwise coerced to zero.)
|
||||
if (length >= kMaxLength) {
|
||||
if (length >= kMaxLength()) {
|
||||
throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
|
||||
'size: 0x' + kMaxLength.toString(16) + ' bytes')
|
||||
'size: 0x' + kMaxLength().toString(16) + ' bytes')
|
||||
}
|
||||
return length | 0
|
||||
}
|
||||
|
@ -274,8 +449,6 @@ Buffer.concat = function concat (list, length) {
|
|||
|
||||
if (list.length === 0) {
|
||||
return new Buffer(0)
|
||||
} else if (list.length === 1) {
|
||||
return list[0]
|
||||
}
|
||||
|
||||
var i
|
||||
|
@ -297,39 +470,43 @@ Buffer.concat = function concat (list, length) {
|
|||
}
|
||||
|
||||
function byteLength (string, encoding) {
|
||||
if (typeof string !== 'string') string = String(string)
|
||||
if (typeof string !== 'string') string = '' + string
|
||||
|
||||
if (string.length === 0) return 0
|
||||
var len = string.length
|
||||
if (len === 0) return 0
|
||||
|
||||
switch (encoding || 'utf8') {
|
||||
// Use a for loop to avoid recursion
|
||||
var loweredCase = false
|
||||
for (;;) {
|
||||
switch (encoding) {
|
||||
case 'ascii':
|
||||
case 'binary':
|
||||
// Deprecated
|
||||
case 'raw':
|
||||
return string.length
|
||||
case 'raws':
|
||||
return len
|
||||
case 'utf8':
|
||||
case 'utf-8':
|
||||
return utf8ToBytes(string).length
|
||||
case 'ucs2':
|
||||
case 'ucs-2':
|
||||
case 'utf16le':
|
||||
case 'utf-16le':
|
||||
return string.length * 2
|
||||
return len * 2
|
||||
case 'hex':
|
||||
return string.length >>> 1
|
||||
case 'utf8':
|
||||
case 'utf-8':
|
||||
return utf8ToBytes(string).length
|
||||
return len >>> 1
|
||||
case 'base64':
|
||||
return base64ToBytes(string).length
|
||||
default:
|
||||
return string.length
|
||||
if (loweredCase) return utf8ToBytes(string).length // assume utf8
|
||||
encoding = ('' + encoding).toLowerCase()
|
||||
loweredCase = true
|
||||
}
|
||||
}
|
||||
}
|
||||
Buffer.byteLength = byteLength
|
||||
|
||||
// pre-set for values that may exist in the future
|
||||
Buffer.prototype.length = undefined
|
||||
Buffer.prototype.parent = undefined
|
||||
|
||||
// toString(encoding, start=0, end=buffer.length)
|
||||
Buffer.prototype.toString = function toString (encoding, start, end) {
|
||||
function slowToString (encoding, start, end) {
|
||||
var loweredCase = false
|
||||
|
||||
start = start | 0
|
||||
|
@ -372,6 +549,13 @@ Buffer.prototype.toString = function toString (encoding, start, end) {
|
|||
}
|
||||
}
|
||||
|
||||
Buffer.prototype.toString = function toString () {
|
||||
var length = this.length | 0
|
||||
if (length === 0) return ''
|
||||
if (arguments.length === 0) return utf8Slice(this, 0, length)
|
||||
return slowToString.apply(this, arguments)
|
||||
}
|
||||
|
||||
Buffer.prototype.equals = function equals (b) {
|
||||
if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
|
||||
if (this === b) return true
|
||||
|
@ -435,13 +619,13 @@ Buffer.prototype.indexOf = function indexOf (val, byteOffset) {
|
|||
throw new TypeError('val must be string, number or Buffer')
|
||||
}
|
||||
|
||||
// `get` will be removed in Node 0.13+
|
||||
// `get` is deprecated
|
||||
Buffer.prototype.get = function get (offset) {
|
||||
console.log('.get() is deprecated. Access using array indexes instead.')
|
||||
return this.readUInt8(offset)
|
||||
}
|
||||
|
||||
// `set` will be removed in Node 0.13+
|
||||
// `set` is deprecated
|
||||
Buffer.prototype.set = function set (v, offset) {
|
||||
console.log('.set() is deprecated. Access using array indexes instead.')
|
||||
return this.writeUInt8(v, offset)
|
||||
|
@ -582,20 +766,99 @@ function base64Slice (buf, start, end) {
|
|||
}
|
||||
|
||||
function utf8Slice (buf, start, end) {
|
||||
var res = ''
|
||||
var tmp = ''
|
||||
end = Math.min(buf.length, end)
|
||||
var res = []
|
||||
|
||||
for (var i = start; i < end; i++) {
|
||||
if (buf[i] <= 0x7F) {
|
||||
res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i])
|
||||
tmp = ''
|
||||
} else {
|
||||
tmp += '%' + buf[i].toString(16)
|
||||
var i = start
|
||||
while (i < end) {
|
||||
var firstByte = buf[i]
|
||||
var codePoint = null
|
||||
var bytesPerSequence = (firstByte > 0xEF) ? 4
|
||||
: (firstByte > 0xDF) ? 3
|
||||
: (firstByte > 0xBF) ? 2
|
||||
: 1
|
||||
|
||||
if (i + bytesPerSequence <= end) {
|
||||
var secondByte, thirdByte, fourthByte, tempCodePoint
|
||||
|
||||
switch (bytesPerSequence) {
|
||||
case 1:
|
||||
if (firstByte < 0x80) {
|
||||
codePoint = firstByte
|
||||
}
|
||||
break
|
||||
case 2:
|
||||
secondByte = buf[i + 1]
|
||||
if ((secondByte & 0xC0) === 0x80) {
|
||||
tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)
|
||||
if (tempCodePoint > 0x7F) {
|
||||
codePoint = tempCodePoint
|
||||
}
|
||||
}
|
||||
break
|
||||
case 3:
|
||||
secondByte = buf[i + 1]
|
||||
thirdByte = buf[i + 2]
|
||||
if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
|
||||
tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)
|
||||
if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
|
||||
codePoint = tempCodePoint
|
||||
}
|
||||
}
|
||||
break
|
||||
case 4:
|
||||
secondByte = buf[i + 1]
|
||||
thirdByte = buf[i + 2]
|
||||
fourthByte = buf[i + 3]
|
||||
if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
|
||||
tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)
|
||||
if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
|
||||
codePoint = tempCodePoint
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res + decodeUtf8Char(tmp)
|
||||
if (codePoint === null) {
|
||||
// we did not generate a valid codePoint so insert a
|
||||
// replacement char (U+FFFD) and advance only 1 byte
|
||||
codePoint = 0xFFFD
|
||||
bytesPerSequence = 1
|
||||
} else if (codePoint > 0xFFFF) {
|
||||
// encode to utf16 (surrogate pair dance)
|
||||
codePoint -= 0x10000
|
||||
res.push(codePoint >>> 10 & 0x3FF | 0xD800)
|
||||
codePoint = 0xDC00 | codePoint & 0x3FF
|
||||
}
|
||||
|
||||
res.push(codePoint)
|
||||
i += bytesPerSequence
|
||||
}
|
||||
|
||||
return decodeCodePointsArray(res)
|
||||
}
|
||||
|
||||
// Based on http://stackoverflow.com/a/22747272/680742, the browser with
|
||||
// the lowest limit is Chrome, with 0x10000 args.
|
||||
// We go 1 magnitude less, for safety
|
||||
var MAX_ARGUMENTS_LENGTH = 0x1000
|
||||
|
||||
function decodeCodePointsArray (codePoints) {
|
||||
var len = codePoints.length
|
||||
if (len <= MAX_ARGUMENTS_LENGTH) {
|
||||
return String.fromCharCode.apply(String, codePoints) // avoid extra slice()
|
||||
}
|
||||
|
||||
// Decode in chunks to avoid "call stack size exceeded".
|
||||
var res = ''
|
||||
var i = 0
|
||||
while (i < len) {
|
||||
res += String.fromCharCode.apply(
|
||||
String,
|
||||
codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)
|
||||
)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
function asciiSlice (buf, start, end) {
|
||||
|
@ -884,7 +1147,7 @@ Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {
|
|||
offset = offset | 0
|
||||
if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)
|
||||
if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
|
||||
this[offset] = value
|
||||
this[offset] = (value & 0xff)
|
||||
return offset + 1
|
||||
}
|
||||
|
||||
|
@ -901,7 +1164,7 @@ Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert
|
|||
offset = offset | 0
|
||||
if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
|
||||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||||
this[offset] = value
|
||||
this[offset] = (value & 0xff)
|
||||
this[offset + 1] = (value >>> 8)
|
||||
} else {
|
||||
objectWriteUInt16(this, value, offset, true)
|
||||
|
@ -915,7 +1178,7 @@ Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert
|
|||
if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
|
||||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||||
this[offset] = (value >>> 8)
|
||||
this[offset + 1] = value
|
||||
this[offset + 1] = (value & 0xff)
|
||||
} else {
|
||||
objectWriteUInt16(this, value, offset, false)
|
||||
}
|
||||
|
@ -937,7 +1200,7 @@ Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert
|
|||
this[offset + 3] = (value >>> 24)
|
||||
this[offset + 2] = (value >>> 16)
|
||||
this[offset + 1] = (value >>> 8)
|
||||
this[offset] = value
|
||||
this[offset] = (value & 0xff)
|
||||
} else {
|
||||
objectWriteUInt32(this, value, offset, true)
|
||||
}
|
||||
|
@ -952,7 +1215,7 @@ Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert
|
|||
this[offset] = (value >>> 24)
|
||||
this[offset + 1] = (value >>> 16)
|
||||
this[offset + 2] = (value >>> 8)
|
||||
this[offset + 3] = value
|
||||
this[offset + 3] = (value & 0xff)
|
||||
} else {
|
||||
objectWriteUInt32(this, value, offset, false)
|
||||
}
|
||||
|
@ -1005,7 +1268,7 @@ Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {
|
|||
if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)
|
||||
if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
|
||||
if (value < 0) value = 0xff + value + 1
|
||||
this[offset] = value
|
||||
this[offset] = (value & 0xff)
|
||||
return offset + 1
|
||||
}
|
||||
|
||||
|
@ -1014,7 +1277,7 @@ Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert)
|
|||
offset = offset | 0
|
||||
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
|
||||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||||
this[offset] = value
|
||||
this[offset] = (value & 0xff)
|
||||
this[offset + 1] = (value >>> 8)
|
||||
} else {
|
||||
objectWriteUInt16(this, value, offset, true)
|
||||
|
@ -1028,7 +1291,7 @@ Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert)
|
|||
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
|
||||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||||
this[offset] = (value >>> 8)
|
||||
this[offset + 1] = value
|
||||
this[offset + 1] = (value & 0xff)
|
||||
} else {
|
||||
objectWriteUInt16(this, value, offset, false)
|
||||
}
|
||||
|
@ -1040,7 +1303,7 @@ Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert)
|
|||
offset = offset | 0
|
||||
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
|
||||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||||
this[offset] = value
|
||||
this[offset] = (value & 0xff)
|
||||
this[offset + 1] = (value >>> 8)
|
||||
this[offset + 2] = (value >>> 16)
|
||||
this[offset + 3] = (value >>> 24)
|
||||
|
@ -1059,7 +1322,7 @@ Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert)
|
|||
this[offset] = (value >>> 24)
|
||||
this[offset + 1] = (value >>> 16)
|
||||
this[offset + 2] = (value >>> 8)
|
||||
this[offset + 3] = value
|
||||
this[offset + 3] = (value & 0xff)
|
||||
} else {
|
||||
objectWriteUInt32(this, value, offset, false)
|
||||
}
|
||||
|
@ -1130,9 +1393,16 @@ Buffer.prototype.copy = function copy (target, targetStart, start, end) {
|
|||
}
|
||||
|
||||
var len = end - start
|
||||
var i
|
||||
|
||||
if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (this === target && start < targetStart && targetStart < end) {
|
||||
// descending copy from end
|
||||
for (i = len - 1; i >= 0; i--) {
|
||||
target[i + targetStart] = this[i + start]
|
||||
}
|
||||
} else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {
|
||||
// ascending copy from start
|
||||
for (i = 0; i < len; i++) {
|
||||
target[i + targetStart] = this[i + start]
|
||||
}
|
||||
} else {
|
||||
|
@ -1208,7 +1478,7 @@ Buffer._augment = function _augment (arr) {
|
|||
// save reference to original Uint8Array set method before overwriting
|
||||
arr._set = arr.set
|
||||
|
||||
// deprecated, will be removed in node 0.13+
|
||||
// deprecated
|
||||
arr.get = BP.get
|
||||
arr.set = BP.set
|
||||
|
||||
|
@ -1264,7 +1534,7 @@ Buffer._augment = function _augment (arr) {
|
|||
return arr
|
||||
}
|
||||
|
||||
var INVALID_BASE64_RE = /[^+\/0-9A-z\-]/g
|
||||
var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g
|
||||
|
||||
function base64clean (str) {
|
||||
// Node strips out invalid characters like \n and \t from the string, base64-js does not
|
||||
|
@ -1294,28 +1564,15 @@ function utf8ToBytes (string, units) {
|
|||
var length = string.length
|
||||
var leadSurrogate = null
|
||||
var bytes = []
|
||||
var i = 0
|
||||
|
||||
for (; i < length; i++) {
|
||||
for (var i = 0; i < length; i++) {
|
||||
codePoint = string.charCodeAt(i)
|
||||
|
||||
// is surrogate component
|
||||
if (codePoint > 0xD7FF && codePoint < 0xE000) {
|
||||
// last char was a lead
|
||||
if (leadSurrogate) {
|
||||
// 2 leads in a row
|
||||
if (codePoint < 0xDC00) {
|
||||
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
|
||||
leadSurrogate = codePoint
|
||||
continue
|
||||
} else {
|
||||
// valid surrogate pair
|
||||
codePoint = leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00 | 0x10000
|
||||
leadSurrogate = null
|
||||
}
|
||||
} else {
|
||||
if (!leadSurrogate) {
|
||||
// no lead yet
|
||||
|
||||
if (codePoint > 0xDBFF) {
|
||||
// unexpected trail
|
||||
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
|
||||
|
@ -1324,18 +1581,30 @@ function utf8ToBytes (string, units) {
|
|||
// unpaired lead
|
||||
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
|
||||
continue
|
||||
} else {
|
||||
}
|
||||
|
||||
// valid lead
|
||||
leadSurrogate = codePoint
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// 2 leads in a row
|
||||
if (codePoint < 0xDC00) {
|
||||
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
|
||||
leadSurrogate = codePoint
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// valid surrogate pair
|
||||
codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000
|
||||
} else if (leadSurrogate) {
|
||||
// valid bmp char, but last char was a lead
|
||||
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
|
||||
leadSurrogate = null
|
||||
}
|
||||
|
||||
leadSurrogate = null
|
||||
|
||||
// encode utf8
|
||||
if (codePoint < 0x80) {
|
||||
if ((units -= 1) < 0) break
|
||||
|
@ -1353,7 +1622,7 @@ function utf8ToBytes (string, units) {
|
|||
codePoint >> 0x6 & 0x3F | 0x80,
|
||||
codePoint & 0x3F | 0x80
|
||||
)
|
||||
} else if (codePoint < 0x200000) {
|
||||
} else if (codePoint < 0x110000) {
|
||||
if ((units -= 4) < 0) break
|
||||
bytes.push(
|
||||
codePoint >> 0x12 | 0xF0,
|
||||
|
@ -1406,144 +1675,18 @@ function blitBuffer (src, dst, offset, length) {
|
|||
return i
|
||||
}
|
||||
|
||||
function decodeUtf8Char (str) {
|
||||
try {
|
||||
return decodeURIComponent(str)
|
||||
} catch (err) {
|
||||
return String.fromCharCode(0xFFFD) // UTF 8 invalid char
|
||||
}
|
||||
}
|
||||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||||
},{"base64-js":1,"ieee754":4,"isarray":3}],3:[function(require,module,exports){
|
||||
var toString = {}.toString;
|
||||
|
||||
},{"base64-js":2,"ieee754":3,"is-array":4}],2:[function(require,module,exports){
|
||||
var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
module.exports = Array.isArray || function (arr) {
|
||||
return toString.call(arr) == '[object Array]';
|
||||
};
|
||||
|
||||
;(function (exports) {
|
||||
'use strict';
|
||||
|
||||
var Arr = (typeof Uint8Array !== 'undefined')
|
||||
? Uint8Array
|
||||
: Array
|
||||
|
||||
var PLUS = '+'.charCodeAt(0)
|
||||
var SLASH = '/'.charCodeAt(0)
|
||||
var NUMBER = '0'.charCodeAt(0)
|
||||
var LOWER = 'a'.charCodeAt(0)
|
||||
var UPPER = 'A'.charCodeAt(0)
|
||||
var PLUS_URL_SAFE = '-'.charCodeAt(0)
|
||||
var SLASH_URL_SAFE = '_'.charCodeAt(0)
|
||||
|
||||
function decode (elt) {
|
||||
var code = elt.charCodeAt(0)
|
||||
if (code === PLUS ||
|
||||
code === PLUS_URL_SAFE)
|
||||
return 62 // '+'
|
||||
if (code === SLASH ||
|
||||
code === SLASH_URL_SAFE)
|
||||
return 63 // '/'
|
||||
if (code < NUMBER)
|
||||
return -1 //no match
|
||||
if (code < NUMBER + 10)
|
||||
return code - NUMBER + 26 + 26
|
||||
if (code < UPPER + 26)
|
||||
return code - UPPER
|
||||
if (code < LOWER + 26)
|
||||
return code - LOWER + 26
|
||||
}
|
||||
|
||||
function b64ToByteArray (b64) {
|
||||
var i, j, l, tmp, placeHolders, arr
|
||||
|
||||
if (b64.length % 4 > 0) {
|
||||
throw new Error('Invalid string. Length must be a multiple of 4')
|
||||
}
|
||||
|
||||
// the number of equal signs (place holders)
|
||||
// if there are two placeholders, than the two characters before it
|
||||
// represent one byte
|
||||
// if there is only one, then the three characters before it represent 2 bytes
|
||||
// this is just a cheap hack to not do indexOf twice
|
||||
var len = b64.length
|
||||
placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0
|
||||
|
||||
// base64 is 4/3 + up to two characters of the original data
|
||||
arr = new Arr(b64.length * 3 / 4 - placeHolders)
|
||||
|
||||
// if there are placeholders, only get up to the last complete 4 chars
|
||||
l = placeHolders > 0 ? b64.length - 4 : b64.length
|
||||
|
||||
var L = 0
|
||||
|
||||
function push (v) {
|
||||
arr[L++] = v
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; i < l; i += 4, j += 3) {
|
||||
tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))
|
||||
push((tmp & 0xFF0000) >> 16)
|
||||
push((tmp & 0xFF00) >> 8)
|
||||
push(tmp & 0xFF)
|
||||
}
|
||||
|
||||
if (placeHolders === 2) {
|
||||
tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)
|
||||
push(tmp & 0xFF)
|
||||
} else if (placeHolders === 1) {
|
||||
tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)
|
||||
push((tmp >> 8) & 0xFF)
|
||||
push(tmp & 0xFF)
|
||||
}
|
||||
|
||||
return arr
|
||||
}
|
||||
|
||||
function uint8ToBase64 (uint8) {
|
||||
var i,
|
||||
extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
|
||||
output = "",
|
||||
temp, length
|
||||
|
||||
function encode (num) {
|
||||
return lookup.charAt(num)
|
||||
}
|
||||
|
||||
function tripletToBase64 (num) {
|
||||
return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)
|
||||
}
|
||||
|
||||
// go through the array every three bytes, we'll deal with trailing stuff later
|
||||
for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
|
||||
temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
|
||||
output += tripletToBase64(temp)
|
||||
}
|
||||
|
||||
// pad the end with zeros, but make sure to not forget the extra bytes
|
||||
switch (extraBytes) {
|
||||
case 1:
|
||||
temp = uint8[uint8.length - 1]
|
||||
output += encode(temp >> 2)
|
||||
output += encode((temp << 4) & 0x3F)
|
||||
output += '=='
|
||||
break
|
||||
case 2:
|
||||
temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])
|
||||
output += encode(temp >> 10)
|
||||
output += encode((temp >> 4) & 0x3F)
|
||||
output += encode((temp << 2) & 0x3F)
|
||||
output += '='
|
||||
break
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
exports.toByteArray = b64ToByteArray
|
||||
exports.fromByteArray = uint8ToBase64
|
||||
}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))
|
||||
|
||||
},{}],3:[function(require,module,exports){
|
||||
},{}],4:[function(require,module,exports){
|
||||
exports.read = function (buffer, offset, isLE, mLen, nBytes) {
|
||||
var e, m
|
||||
var eLen = nBytes * 8 - mLen - 1
|
||||
var eLen = (nBytes * 8) - mLen - 1
|
||||
var eMax = (1 << eLen) - 1
|
||||
var eBias = eMax >> 1
|
||||
var nBits = -7
|
||||
|
@ -1556,12 +1699,12 @@ exports.read = function (buffer, offset, isLE, mLen, nBytes) {
|
|||
e = s & ((1 << (-nBits)) - 1)
|
||||
s >>= (-nBits)
|
||||
nBits += eLen
|
||||
for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
|
||||
for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {}
|
||||
|
||||
m = e & ((1 << (-nBits)) - 1)
|
||||
e >>= (-nBits)
|
||||
nBits += mLen
|
||||
for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
|
||||
for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {}
|
||||
|
||||
if (e === 0) {
|
||||
e = 1 - eBias
|
||||
|
@ -1576,7 +1719,7 @@ exports.read = function (buffer, offset, isLE, mLen, nBytes) {
|
|||
|
||||
exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
|
||||
var e, m, c
|
||||
var eLen = nBytes * 8 - mLen - 1
|
||||
var eLen = (nBytes * 8) - mLen - 1
|
||||
var eMax = (1 << eLen) - 1
|
||||
var eBias = eMax >> 1
|
||||
var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
|
||||
|
@ -1609,7 +1752,7 @@ exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
|
|||
m = 0
|
||||
e = eMax
|
||||
} else if (e + eBias >= 1) {
|
||||
m = (value * c - 1) * Math.pow(2, mLen)
|
||||
m = ((value * c) - 1) * Math.pow(2, mLen)
|
||||
e = e + eBias
|
||||
} else {
|
||||
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
|
||||
|
@ -1626,41 +1769,6 @@ exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
|
|||
buffer[offset + i - d] |= s * 128
|
||||
}
|
||||
|
||||
},{}],4:[function(require,module,exports){
|
||||
|
||||
/**
|
||||
* isArray
|
||||
*/
|
||||
|
||||
var isArray = Array.isArray;
|
||||
|
||||
/**
|
||||
* toString
|
||||
*/
|
||||
|
||||
var str = Object.prototype.toString;
|
||||
|
||||
/**
|
||||
* Whether or not the given `val`
|
||||
* is an array.
|
||||
*
|
||||
* example:
|
||||
*
|
||||
* isArray([]);
|
||||
* // > true
|
||||
* isArray(arguments);
|
||||
* // > false
|
||||
* isArray('');
|
||||
* // > false
|
||||
*
|
||||
* @param {mixed} val
|
||||
* @return {bool}
|
||||
*/
|
||||
|
||||
module.exports = isArray || function (val) {
|
||||
return !! val && '[object Array]' == str.call(val);
|
||||
};
|
||||
|
||||
},{}],5:[function(require,module,exports){
|
||||
(function (Buffer){
|
||||
function FilerBuffer (subject, encoding, nonZero) {
|
||||
|
@ -1688,5 +1796,5 @@ Object.keys(Buffer).forEach(function (p) {
|
|||
module.exports = FilerBuffer;
|
||||
|
||||
}).call(this,require("buffer").Buffer)
|
||||
},{"buffer":1}]},{},[5])(5)
|
||||
},{"buffer":2}]},{},[5])(5)
|
||||
});
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -1,2 +1,2 @@
|
|||
/*! filer 0.0.44 2017-05-25 */
|
||||
!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.Path=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b,c){function d(a,b){for(var c=0,d=a.length-1;d>=0;d--){var e=a[d];"."===e?a.splice(d,1):".."===e?(a.splice(d,1),c++):c&&(a.splice(d,1),c--)}if(b)for(;c--;c)a.unshift("..");return a}function e(){for(var a="",b=!1,c=arguments.length-1;c>=-1&&!b;c--){var e=c>=0?arguments[c]:"/";"string"==typeof e&&e&&(a=e+"/"+a,b="/"===e.charAt(0))}return a=d(a.split("/").filter(function(a){return!!a}),!b).join("/"),(b?"/":"")+a||"."}function f(a){var b="/"===a.charAt(0);"/"===a.substr(-1);return a=d(a.split("/").filter(function(a){return!!a}),!b).join("/"),a||b||(a="."),(b?"/":"")+a}function g(){var a=Array.prototype.slice.call(arguments,0);return f(a.filter(function(a,b){return a&&"string"==typeof a}).join("/"))}function h(a,b){function c(a){for(var b=0;b<a.length&&""===a[b];b++);for(var c=a.length-1;c>=0&&""===a[c];c--);return b>c?[]:a.slice(b,c-b+1)}a=e(a).substr(1),b=e(b).substr(1);for(var d=c(a.split("/")),f=c(b.split("/")),g=Math.min(d.length,f.length),h=g,i=0;g>i;i++)if(d[i]!==f[i]){h=i;break}for(var j=[],i=h;i<d.length;i++)j.push("..");return j=j.concat(f.slice(h)),j.join("/")}function i(a){var b=q(a),c=b[0],d=b[1];return c||d?(d&&(d=d.substr(0,d.length-1)),c+d):"."}function j(a,b){var c=q(a)[2];return b&&c.substr(-1*b.length)===b&&(c=c.substr(0,c.length-b.length)),""===c?"/":c}function k(a){return q(a)[3]}function l(a){return"/"===a.charAt(0)?!0:!1}function m(a){return-1!==(""+a).indexOf("\x00")?!0:!1}function n(a){return a.replace(/\/*$/,"/")}function o(a){return a=a.replace(/\/*$/,""),""===a?"/":a}var p=/^(\/?)([\s\S]+\/(?!$)|\/)?((?:\.{1,2}$|[\s\S]+?)?(\.[^.\/]*)?)$/,q=function(a){var b=p.exec(a);return[b[1]||"",b[2]||"",b[3]||"",b[4]||""]};b.exports={normalize:f,resolve:e,join:g,relative:h,sep:"/",delimiter:":",dirname:i,basename:j,extname:k,isAbsolute:l,isNull:m,addTrailing:n,removeTrailing:o}},{}]},{},[1])(1)});
|
||||
/*! filer 0.0.44 2018-06-25 */
|
||||
!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.Path=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c||a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b,c){function d(a,b){for(var c=0,d=a.length-1;d>=0;d--){var e=a[d];"."===e?a.splice(d,1):".."===e?(a.splice(d,1),c++):c&&(a.splice(d,1),c--)}if(b)for(;c--;c)a.unshift("..");return a}function e(){for(var a="",b=!1,c=arguments.length-1;c>=-1&&!b;c--){var e=c>=0?arguments[c]:"/";"string"==typeof e&&e&&(a=e+"/"+a,b="/"===e.charAt(0))}return a=d(a.split("/").filter(function(a){return!!a}),!b).join("/"),(b?"/":"")+a||"."}function f(a){var b="/"===a.charAt(0);a.substr(-1);return a=d(a.split("/").filter(function(a){return!!a}),!b).join("/"),a||b||(a="."),(b?"/":"")+a}function g(){return f(Array.prototype.slice.call(arguments,0).filter(function(a,b){return a&&"string"==typeof a}).join("/"))}function h(a,b){function c(a){for(var b=0;b<a.length&&""===a[b];b++);for(var c=a.length-1;c>=0&&""===a[c];c--);return b>c?[]:a.slice(b,c-b+1)}a=e(a).substr(1),b=e(b).substr(1);for(var d=c(a.split("/")),f=c(b.split("/")),g=Math.min(d.length,f.length),h=g,i=0;i<g;i++)if(d[i]!==f[i]){h=i;break}for(var j=[],i=h;i<d.length;i++)j.push("..");return j=j.concat(f.slice(h)),j.join("/")}function i(a){var b=q(a),c=b[0],d=b[1];return c||d?(d&&(d=d.substr(0,d.length-1)),c+d):"."}function j(a,b){var c=q(a)[2];return b&&c.substr(-1*b.length)===b&&(c=c.substr(0,c.length-b.length)),""===c?"/":c}function k(a){return q(a)[3]}function l(a){return"/"===a.charAt(0)}function m(a){return-1!==(""+a).indexOf("\0")}function n(a){return a.replace(/\/*$/,"/")}function o(a){return a=a.replace(/\/*$/,""),""===a?"/":a}var p=/^(\/?)([\s\S]+\/(?!$)|\/)?((?:\.{1,2}$|[\s\S]+?)?(\.[^.\/]*)?)$/,q=function(a){var b=p.exec(a);return[b[1]||"",b[2]||"",b[3]||"",b[4]||""]};b.exports={normalize:f,resolve:e,join:g,relative:h,sep:"/",delimiter:":",dirname:i,basename:j,extname:k,isAbsolute:l,isNull:m,addTrailing:n,removeTrailing:o}},{}]},{},[1])(1)});
|
File diff suppressed because it is too large
Load Diff
|
@ -19,10 +19,19 @@ module.exports = {
|
|||
WSQL_SIZE: 5 * 1024 * 1024,
|
||||
WSQL_DESC: "FileSystem Storage",
|
||||
|
||||
MODE_FILE: 'FILE',
|
||||
MODE_DIRECTORY: 'DIRECTORY',
|
||||
MODE_SYMBOLIC_LINK: 'SYMLINK',
|
||||
MODE_META: 'META',
|
||||
NODE_TYPE_FILE: 'FILE',
|
||||
NODE_TYPE_DIRECTORY: 'DIRECTORY',
|
||||
NODE_TYPE_SYMBOLIC_LINK: 'SYMLINK',
|
||||
NODE_TYPE_META: 'META',
|
||||
|
||||
S_IFREG: 0x8000,
|
||||
S_IFDIR: 0x4000,
|
||||
S_IFLNK: 0xA000,
|
||||
|
||||
DEFAULT_DIR_PERMISSIONS: 0x1ED, // 755
|
||||
DEFAULT_FILE_PERMISSIONS: 0x1A4, // 644
|
||||
FULL_READ_WRITE_EXEC_PERMISSIONS: 0x1FF, // 777
|
||||
READ_WRITE_PERMISSIONS: 0x1B6, /// 666
|
||||
|
||||
SYMLOOP_MAX: 10,
|
||||
|
||||
|
@ -76,5 +85,49 @@ module.exports = {
|
|||
ENVIRONMENT: {
|
||||
TMP: '/tmp',
|
||||
PATH: ''
|
||||
},
|
||||
|
||||
// Duplicate Node's fs.constants
|
||||
fsConstants: {
|
||||
O_RDONLY: 0,
|
||||
O_WRONLY: 1,
|
||||
O_RDWR: 2,
|
||||
S_IFMT: 61440,
|
||||
S_IFREG: 32768,
|
||||
S_IFDIR: 16384,
|
||||
S_IFCHR: 8192,
|
||||
S_IFBLK: 24576,
|
||||
S_IFIFO: 4096,
|
||||
S_IFLNK: 40960,
|
||||
S_IFSOCK: 49152,
|
||||
O_CREAT: 512,
|
||||
O_EXCL: 2048,
|
||||
O_NOCTTY: 131072,
|
||||
O_TRUNC: 1024,
|
||||
O_APPEND: 8,
|
||||
O_DIRECTORY: 1048576,
|
||||
O_NOFOLLOW: 256,
|
||||
O_SYNC: 128,
|
||||
O_DSYNC: 4194304,
|
||||
O_SYMLINK: 2097152,
|
||||
O_NONBLOCK: 4,
|
||||
S_IRWXU: 448,
|
||||
S_IRUSR: 256,
|
||||
S_IWUSR: 128,
|
||||
S_IXUSR: 64,
|
||||
S_IRWXG: 56,
|
||||
S_IRGRP: 32,
|
||||
S_IWGRP: 16,
|
||||
S_IXGRP: 8,
|
||||
S_IRWXO: 7,
|
||||
S_IROTH: 4,
|
||||
S_IWOTH: 2,
|
||||
S_IXOTH: 1,
|
||||
F_OK: 0,
|
||||
R_OK: 4,
|
||||
W_OK: 2,
|
||||
X_OK: 1,
|
||||
UV_FS_COPYFILE_EXCL: 1,
|
||||
COPYFILE_EXCL: 1
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
var MODE_FILE = require('./constants.js').MODE_FILE;
|
||||
var NODE_TYPE_FILE = require('./constants.js').NODE_TYPE_FILE;
|
||||
|
||||
module.exports = function DirectoryEntry(id, type) {
|
||||
this.id = id;
|
||||
this.type = type || MODE_FILE;
|
||||
this.type = type || NODE_TYPE_FILE;
|
||||
};
|
||||
|
|
|
@ -8,10 +8,14 @@ var isAbsolutePath = Path.isAbsolute;
|
|||
var isNullPath = Path.isNull;
|
||||
|
||||
var Constants = require('../constants.js');
|
||||
var MODE_FILE = Constants.MODE_FILE;
|
||||
var MODE_DIRECTORY = Constants.MODE_DIRECTORY;
|
||||
var MODE_SYMBOLIC_LINK = Constants.MODE_SYMBOLIC_LINK;
|
||||
var MODE_META = Constants.MODE_META;
|
||||
var NODE_TYPE_FILE = Constants.NODE_TYPE_FILE;
|
||||
var NODE_TYPE_DIRECTORY = Constants.NODE_TYPE_DIRECTORY;
|
||||
var NODE_TYPE_SYMBOLIC_LINK = Constants.NODE_TYPE_SYMBOLIC_LINK;
|
||||
var NODE_TYPE_META = Constants.NODE_TYPE_META;
|
||||
|
||||
var DEFAULT_FILE_PERMISSIONS = Constants.DEFAULT_FILE_PERMISSIONS;
|
||||
var DEFAULT_DIR_PERMISSIONS = Constants.DEFAULT_DIR_PERMISSIONS;
|
||||
var FULL_READ_WRITE_EXEC_PERMISSIONS = Constants.FULL_READ_WRITE_EXEC_PERMISSIONS;
|
||||
|
||||
var ROOT_DIRECTORY_NAME = Constants.ROOT_DIRECTORY_NAME;
|
||||
var SUPER_NODE_ID = Constants.SUPER_NODE_ID;
|
||||
|
@ -91,9 +95,9 @@ function update_node_times(context, path, node, times, callback) {
|
|||
*/
|
||||
// in: file or directory path
|
||||
// out: new node representing file/directory
|
||||
function make_node(context, path, mode, callback) {
|
||||
if(mode !== MODE_DIRECTORY && mode !== MODE_FILE) {
|
||||
return callback(new Errors.EINVAL('mode must be a directory or file', path));
|
||||
function make_node(context, path, type, callback) {
|
||||
if(type !== NODE_TYPE_DIRECTORY && type !== NODE_TYPE_FILE) {
|
||||
return callback(new Errors.EINVAL('type must be a directory or file', path));
|
||||
}
|
||||
|
||||
path = normalize(path);
|
||||
|
@ -108,7 +112,7 @@ function make_node(context, path, mode, callback) {
|
|||
function create_node_in_parent(error, parentDirectoryNode) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
} else if(parentDirectoryNode.mode !== MODE_DIRECTORY) {
|
||||
} else if(parentDirectoryNode.type !== NODE_TYPE_DIRECTORY) {
|
||||
callback(new Errors.ENOTDIR('a component of the path prefix is not a directory', path));
|
||||
} else {
|
||||
parentNode = parentDirectoryNode;
|
||||
|
@ -133,7 +137,10 @@ function make_node(context, path, mode, callback) {
|
|||
callback(error);
|
||||
} else {
|
||||
parentNodeData = result;
|
||||
Node.create({guid: context.guid, mode: mode}, function(error, result) {
|
||||
Node.create({
|
||||
guid: context.guid,
|
||||
type: type
|
||||
}, function(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
return;
|
||||
|
@ -160,7 +167,7 @@ function make_node(context, path, mode, callback) {
|
|||
if(error) {
|
||||
callback(error);
|
||||
} else {
|
||||
parentNodeData[name] = new DirectoryEntry(node.id, mode);
|
||||
parentNodeData[name] = new DirectoryEntry(node.id, type);
|
||||
context.putObject(parentNode.data, parentNodeData, update_time);
|
||||
}
|
||||
}
|
||||
|
@ -186,7 +193,7 @@ function find_node(context, path, callback) {
|
|||
function read_root_directory_node(error, superNode) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
} else if(!superNode || superNode.mode !== MODE_META || !superNode.rnode) {
|
||||
} else if(!superNode || superNode.type !== NODE_TYPE_META || !superNode.rnode) {
|
||||
callback(new Errors.EFILESYSTEMERROR());
|
||||
} else {
|
||||
context.getObject(superNode.rnode, check_root_directory_node);
|
||||
|
@ -208,7 +215,7 @@ function find_node(context, path, callback) {
|
|||
function read_parent_directory_data(error, parentDirectoryNode) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
} else if(parentDirectoryNode.mode !== MODE_DIRECTORY || !parentDirectoryNode.data) {
|
||||
} else if(parentDirectoryNode.type !== NODE_TYPE_DIRECTORY || !parentDirectoryNode.data) {
|
||||
callback(new Errors.ENOTDIR('a component of the path prefix is not a directory', path));
|
||||
} else {
|
||||
context.getObject(parentDirectoryNode.data, get_node_from_parent_directory_data);
|
||||
|
@ -234,7 +241,7 @@ function find_node(context, path, callback) {
|
|||
if(error) {
|
||||
callback(error);
|
||||
} else {
|
||||
if(node.mode == MODE_SYMBOLIC_LINK) {
|
||||
if(node.type === NODE_TYPE_SYMBOLIC_LINK) {
|
||||
followedCount++;
|
||||
if(followedCount > SYMLOOP_MAX){
|
||||
callback(new Errors.ELOOP(null, path));
|
||||
|
@ -251,14 +258,14 @@ function find_node(context, path, callback) {
|
|||
data = normalize(data);
|
||||
parentPath = dirname(data);
|
||||
name = basename(data);
|
||||
if(ROOT_DIRECTORY_NAME == name) {
|
||||
if(ROOT_DIRECTORY_NAME === name) {
|
||||
context.getObject(SUPER_NODE_ID, read_root_directory_node);
|
||||
} else {
|
||||
find_node(context, parentPath, read_parent_directory_data);
|
||||
}
|
||||
}
|
||||
|
||||
if(ROOT_DIRECTORY_NAME == name) {
|
||||
if(ROOT_DIRECTORY_NAME === name) {
|
||||
context.getObject(SUPER_NODE_ID, read_root_directory_node);
|
||||
} else {
|
||||
find_node(context, parentPath, read_parent_directory_data);
|
||||
|
@ -326,7 +333,11 @@ function ensure_root_directory(context, callback) {
|
|||
if(error) {
|
||||
callback(error);
|
||||
} else {
|
||||
Node.create({guid: context.guid, id: superNode.rnode, mode: MODE_DIRECTORY}, function(error, result) {
|
||||
Node.create({
|
||||
guid: context.guid,
|
||||
id: superNode.rnode,
|
||||
type: NODE_TYPE_DIRECTORY
|
||||
}, function(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
return;
|
||||
|
@ -387,7 +398,10 @@ function make_directory(context, path, callback) {
|
|||
callback(error);
|
||||
} else {
|
||||
parentDirectoryData = result;
|
||||
Node.create({guid: context.guid, mode: MODE_DIRECTORY}, function(error, result) {
|
||||
Node.create({
|
||||
guid: context.guid,
|
||||
type: NODE_TYPE_DIRECTORY
|
||||
}, function(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
return;
|
||||
|
@ -421,7 +435,7 @@ function make_directory(context, path, callback) {
|
|||
if(error) {
|
||||
callback(error);
|
||||
} else {
|
||||
parentDirectoryData[name] = new DirectoryEntry(directoryNode.id, MODE_DIRECTORY);
|
||||
parentDirectoryData[name] = new DirectoryEntry(directoryNode.id, NODE_TYPE_DIRECTORY);
|
||||
context.putObject(parentDirectoryNode.data, parentDirectoryData, update_time);
|
||||
}
|
||||
}
|
||||
|
@ -454,7 +468,7 @@ function remove_directory(context, path, callback) {
|
|||
function check_if_node_exists(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
} else if(ROOT_DIRECTORY_NAME == name) {
|
||||
} else if(ROOT_DIRECTORY_NAME === name) {
|
||||
callback(new Errors.EBUSY(null, path));
|
||||
} else if(!_(result).has(name)) {
|
||||
callback(new Errors.ENOENT(null, path));
|
||||
|
@ -468,7 +482,7 @@ function remove_directory(context, path, callback) {
|
|||
function check_if_node_is_directory(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
} else if(result.mode != MODE_DIRECTORY) {
|
||||
} else if(result.type !== NODE_TYPE_DIRECTORY) {
|
||||
callback(new Errors.ENOTDIR(null, path));
|
||||
} else {
|
||||
directoryNode = result;
|
||||
|
@ -535,7 +549,7 @@ function open_file(context, path, flags, callback) {
|
|||
|
||||
var followedCount = 0;
|
||||
|
||||
if(ROOT_DIRECTORY_NAME == name) {
|
||||
if(ROOT_DIRECTORY_NAME === name) {
|
||||
if(_(flags).contains(O_WRITE)) {
|
||||
callback(new Errors.EISDIR('the named file is a directory and O_WRITE is set', path));
|
||||
} else {
|
||||
|
@ -548,7 +562,7 @@ function open_file(context, path, flags, callback) {
|
|||
function read_directory_data(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
} else if(result.mode !== MODE_DIRECTORY) {
|
||||
} else if(result.type !== NODE_TYPE_DIRECTORY) {
|
||||
callback(new Errors.ENOENT(null, path));
|
||||
} else {
|
||||
directoryNode = result;
|
||||
|
@ -566,7 +580,7 @@ function open_file(context, path, flags, callback) {
|
|||
callback(new Errors.ENOENT('O_CREATE and O_EXCLUSIVE are set, and the named file exists', path));
|
||||
} else {
|
||||
directoryEntry = directoryData[name];
|
||||
if(directoryEntry.type == MODE_DIRECTORY && _(flags).contains(O_WRITE)) {
|
||||
if(directoryEntry.type === NODE_TYPE_DIRECTORY && _(flags).contains(O_WRITE)) {
|
||||
callback(new Errors.EISDIR('the named file is a directory and O_WRITE is set', path));
|
||||
} else {
|
||||
context.getObject(directoryEntry.id, check_if_symbolic_link);
|
||||
|
@ -587,7 +601,7 @@ function open_file(context, path, flags, callback) {
|
|||
callback(error);
|
||||
} else {
|
||||
var node = result;
|
||||
if(node.mode == MODE_SYMBOLIC_LINK) {
|
||||
if(node.type === NODE_TYPE_SYMBOLIC_LINK) {
|
||||
followedCount++;
|
||||
if(followedCount > SYMLOOP_MAX){
|
||||
callback(new Errors.ELOOP(null, path));
|
||||
|
@ -604,7 +618,7 @@ function open_file(context, path, flags, callback) {
|
|||
data = normalize(data);
|
||||
parentPath = dirname(data);
|
||||
name = basename(data);
|
||||
if(ROOT_DIRECTORY_NAME == name) {
|
||||
if(ROOT_DIRECTORY_NAME === name) {
|
||||
if(_(flags).contains(O_WRITE)) {
|
||||
callback(new Errors.EISDIR('the named file is a directory and O_WRITE is set', path));
|
||||
} else {
|
||||
|
@ -624,7 +638,10 @@ function open_file(context, path, flags, callback) {
|
|||
}
|
||||
|
||||
function write_file_node() {
|
||||
Node.create({guid: context.guid, mode: MODE_FILE}, function(error, result) {
|
||||
Node.create({
|
||||
guid: context.guid,
|
||||
type: NODE_TYPE_FILE
|
||||
}, function(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
return;
|
||||
|
@ -658,7 +675,7 @@ function open_file(context, path, flags, callback) {
|
|||
if(error) {
|
||||
callback(error);
|
||||
} else {
|
||||
directoryData[name] = new DirectoryEntry(fileNode.id, MODE_FILE);
|
||||
directoryData[name] = new DirectoryEntry(fileNode.id, NODE_TYPE_FILE);
|
||||
context.putObject(directoryNode.data, directoryData, update_time);
|
||||
}
|
||||
}
|
||||
|
@ -813,7 +830,7 @@ function read_data(context, ofd, buffer, offset, length, position, callback) {
|
|||
function read_file_data(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
} else if(result.mode === 'DIRECTORY') {
|
||||
} else if(result.type === NODE_TYPE_DIRECTORY) {
|
||||
callback(new Errors.EISDIR('the named file is a directory', ofd.path));
|
||||
} else {
|
||||
fileNode = result;
|
||||
|
@ -842,7 +859,7 @@ function lstat_file(context, path, callback) {
|
|||
var directoryNode;
|
||||
var directoryData;
|
||||
|
||||
if(ROOT_DIRECTORY_NAME == name) {
|
||||
if(ROOT_DIRECTORY_NAME === name) {
|
||||
find_node(context, path, callback);
|
||||
} else {
|
||||
find_node(context, parentPath, read_directory_data);
|
||||
|
@ -879,18 +896,20 @@ function link_node(context, oldpath, newpath, callback) {
|
|||
newpath = normalize(newpath);
|
||||
var newname = basename(newpath);
|
||||
var newParentPath = dirname(newpath);
|
||||
var ctime = Date.now();
|
||||
|
||||
var oldDirectoryNode;
|
||||
var oldDirectoryData;
|
||||
var newDirectoryNode;
|
||||
var newDirectoryData;
|
||||
var fileNodeID;
|
||||
var fileNode;
|
||||
|
||||
function update_time(error) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
} else {
|
||||
update_node_times(context, newpath, fileNode, { ctime: Date.now() }, callback);
|
||||
update_node_times(context, newpath, fileNode, { ctime: ctime }, callback);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -904,11 +923,11 @@ function link_node(context, oldpath, newpath, callback) {
|
|||
}
|
||||
}
|
||||
|
||||
function read_directory_entry(error, result) {
|
||||
function read_file_node(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
} else {
|
||||
context.getObject(newDirectoryData[newname].id, update_file_node);
|
||||
context.getObject(fileNodeID, update_file_node);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -921,7 +940,8 @@ function link_node(context, oldpath, newpath, callback) {
|
|||
callback(new Errors.EEXIST('newpath resolves to an existing file', newname));
|
||||
} else {
|
||||
newDirectoryData[newname] = oldDirectoryData[oldname];
|
||||
context.putObject(newDirectoryNode.data, newDirectoryData, read_directory_entry);
|
||||
fileNodeID = newDirectoryData[newname].id;
|
||||
context.putObject(newDirectoryNode.data, newDirectoryData, read_file_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -942,7 +962,7 @@ function link_node(context, oldpath, newpath, callback) {
|
|||
oldDirectoryData = result;
|
||||
if(!_(oldDirectoryData).has(oldname)) {
|
||||
callback(new Errors.ENOENT('a component of either path prefix does not exist', oldname));
|
||||
} else if(oldDirectoryData[oldname].type === 'DIRECTORY') {
|
||||
} else if(oldDirectoryData[oldname].type === NODE_TYPE_DIRECTORY) {
|
||||
callback(new Errors.EPERM('oldpath refers to a directory'));
|
||||
} else {
|
||||
find_node(context, newParentPath, read_new_directory_data);
|
||||
|
@ -1010,7 +1030,7 @@ function unlink_node(context, path, callback) {
|
|||
function check_if_node_is_directory(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
} else if(result.mode === 'DIRECTORY') {
|
||||
} else if(result.type === NODE_TYPE_DIRECTORY) {
|
||||
callback(new Errors.EPERM('unlink not permitted on directories', name));
|
||||
} else {
|
||||
update_file_node(null, result);
|
||||
|
@ -1062,7 +1082,7 @@ function read_directory(context, path, callback) {
|
|||
function read_directory_data(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
} else if(result.mode !== MODE_DIRECTORY) {
|
||||
} else if(result.type !== NODE_TYPE_DIRECTORY) {
|
||||
callback(new Errors.ENOTDIR(null, path));
|
||||
} else {
|
||||
directoryNode = result;
|
||||
|
@ -1082,7 +1102,7 @@ function make_symbolic_link(context, srcpath, dstpath, callback) {
|
|||
var directoryData;
|
||||
var fileNode;
|
||||
|
||||
if(ROOT_DIRECTORY_NAME == name) {
|
||||
if(ROOT_DIRECTORY_NAME === name) {
|
||||
callback(new Errors.EEXIST(null, name));
|
||||
} else {
|
||||
find_node(context, parentPath, read_directory_data);
|
||||
|
@ -1111,15 +1131,27 @@ function make_symbolic_link(context, srcpath, dstpath, callback) {
|
|||
}
|
||||
|
||||
function write_file_node() {
|
||||
Node.create({guid: context.guid, mode: MODE_SYMBOLIC_LINK}, function(error, result) {
|
||||
Node.create({
|
||||
guid: context.guid,
|
||||
type: NODE_TYPE_SYMBOLIC_LINK
|
||||
}, function(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
return;
|
||||
}
|
||||
fileNode = result;
|
||||
fileNode.nlinks += 1;
|
||||
|
||||
// If the srcpath isn't absolute, resolve it relative to the dstpath
|
||||
// but store both versions, since we'll use the relative one in readlink().
|
||||
if(!isAbsolutePath(srcpath)) {
|
||||
fileNode.symlink_relpath = srcpath;
|
||||
srcpath = Path.resolve(parentPath, srcpath);
|
||||
}
|
||||
|
||||
fileNode.size = srcpath.length;
|
||||
fileNode.data = srcpath;
|
||||
|
||||
context.putObject(fileNode.id, fileNode, update_directory_data);
|
||||
});
|
||||
}
|
||||
|
@ -1137,7 +1169,7 @@ function make_symbolic_link(context, srcpath, dstpath, callback) {
|
|||
if(error) {
|
||||
callback(error);
|
||||
} else {
|
||||
directoryData[name] = new DirectoryEntry(fileNode.id, MODE_SYMBOLIC_LINK);
|
||||
directoryData[name] = new DirectoryEntry(fileNode.id, NODE_TYPE_SYMBOLIC_LINK);
|
||||
context.putObject(directoryNode.data, directoryData, update_time);
|
||||
}
|
||||
}
|
||||
|
@ -1175,14 +1207,17 @@ function read_link(context, path, callback) {
|
|||
}
|
||||
}
|
||||
|
||||
function check_if_symbolic(error, result) {
|
||||
function check_if_symbolic(error, fileNode) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
} else {
|
||||
if(result.mode != MODE_SYMBOLIC_LINK) {
|
||||
if(fileNode.type !== NODE_TYPE_SYMBOLIC_LINK) {
|
||||
callback(new Errors.EINVAL('path not a symbolic link', path));
|
||||
} else {
|
||||
callback(null, result.data);
|
||||
// If we were originally given a relative path, return that now vs. the
|
||||
// absolute path we've generated and use elsewhere internally.
|
||||
var target = fileNode.symlink_relpath ? fileNode.symlink_relpath : fileNode.data;
|
||||
callback(null, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1196,7 +1231,7 @@ function truncate_file(context, path, length, callback) {
|
|||
function read_file_data (error, node) {
|
||||
if (error) {
|
||||
callback(error);
|
||||
} else if(node.mode == MODE_DIRECTORY ) {
|
||||
} else if(node.type === NODE_TYPE_DIRECTORY ) {
|
||||
callback(new Errors.EISDIR(null, path));
|
||||
} else{
|
||||
fileNode = node;
|
||||
|
@ -1252,7 +1287,7 @@ function ftruncate_file(context, ofd, length, callback) {
|
|||
function read_file_data (error, node) {
|
||||
if (error) {
|
||||
callback(error);
|
||||
} else if(node.mode == MODE_DIRECTORY ) {
|
||||
} else if(node.type === NODE_TYPE_DIRECTORY ) {
|
||||
callback(new Errors.EISDIR());
|
||||
} else{
|
||||
fileNode = node;
|
||||
|
@ -1315,7 +1350,7 @@ function utimes_file(context, path, atime, mtime, callback) {
|
|||
}
|
||||
}
|
||||
|
||||
if (typeof atime != 'number' || typeof mtime != 'number') {
|
||||
if (typeof atime !== 'number' || typeof mtime !== 'number') {
|
||||
callback(new Errors.EINVAL('atime and mtime must be number', path));
|
||||
}
|
||||
else if (atime < 0 || mtime < 0) {
|
||||
|
@ -1336,7 +1371,7 @@ function futimes_file(context, ofd, atime, mtime, callback) {
|
|||
}
|
||||
}
|
||||
|
||||
if (typeof atime != 'number' || typeof mtime != 'number') {
|
||||
if (typeof atime !== 'number' || typeof mtime !== 'number') {
|
||||
callback(new Errors.EINVAL('atime and mtime must be a number'));
|
||||
}
|
||||
else if (atime < 0 || mtime < 0) {
|
||||
|
@ -1357,7 +1392,7 @@ function setxattr_file(context, path, name, value, flag, callback) {
|
|||
set_extended_attribute(context, path, node, name, value, flag, callback);
|
||||
}
|
||||
|
||||
if (typeof name != 'string') {
|
||||
if (typeof name !== 'string') {
|
||||
callback(new Errors.EINVAL('attribute name must be a string', path));
|
||||
}
|
||||
else if (!name) {
|
||||
|
@ -1413,7 +1448,7 @@ function getxattr_file (context, path, name, callback) {
|
|||
}
|
||||
}
|
||||
|
||||
if (typeof name != 'string') {
|
||||
if (typeof name !== 'string') {
|
||||
callback(new Errors.EINVAL('attribute name must be a string', path));
|
||||
}
|
||||
else if (!name) {
|
||||
|
@ -1441,7 +1476,7 @@ function fgetxattr_file (context, ofd, name, callback) {
|
|||
}
|
||||
}
|
||||
|
||||
if (typeof name != 'string') {
|
||||
if (typeof name !== 'string') {
|
||||
callback(new Errors.EINVAL());
|
||||
}
|
||||
else if (!name) {
|
||||
|
@ -1516,7 +1551,7 @@ function fremovexattr_file (context, ofd, name, callback) {
|
|||
}
|
||||
}
|
||||
|
||||
if (typeof name != 'string') {
|
||||
if (typeof name !== 'string') {
|
||||
callback(new Errors.EINVAL('attribute name must be a string'));
|
||||
}
|
||||
else if (!name) {
|
||||
|
@ -1545,14 +1580,19 @@ function validate_file_options(options, enc, fileMode){
|
|||
return options;
|
||||
}
|
||||
|
||||
function pathCheck(path, callback) {
|
||||
function pathCheck(path, allowRelative, callback) {
|
||||
var err;
|
||||
|
||||
if(typeof allowRelative === 'function') {
|
||||
callback = allowRelative;
|
||||
allowRelative = false;
|
||||
}
|
||||
|
||||
if(!path) {
|
||||
err = new Errors.EINVAL('Path must be a string', path);
|
||||
} else if(isNullPath(path)) {
|
||||
err = new Errors.EINVAL('Path must be a string without null bytes.', path);
|
||||
} else if(!isAbsolutePath(path)) {
|
||||
} else if(!allowRelative && !isAbsolutePath(path)) {
|
||||
err = new Errors.EINVAL('Path must be absolute.', path);
|
||||
}
|
||||
|
||||
|
@ -1565,8 +1605,22 @@ function pathCheck(path, callback) {
|
|||
|
||||
|
||||
function open(fs, context, path, flags, mode, callback) {
|
||||
// NOTE: we support the same signature as node with a `mode` arg,
|
||||
// but ignore it.
|
||||
/**
|
||||
* NOTE: we support the same signature as node with a `mode` arg,
|
||||
* but ignore it. We need to add it. Here is what node.js does:
|
||||
* function open(path, flags, mode, callback) {
|
||||
* path = getPathFromURL(path);
|
||||
* validatePath(path);
|
||||
* const flagsNumber = stringToFlags(flags);
|
||||
* if (arguments.length < 4) {
|
||||
* callback = makeCallback(mode);
|
||||
* mode = 0o666;
|
||||
* } else {
|
||||
* mode = validateAndMaskMode(mode, 'mode', 0o666);
|
||||
* callback = makeCallback(callback);
|
||||
* }
|
||||
*/
|
||||
|
||||
callback = arguments[arguments.length - 1];
|
||||
if(!pathCheck(path, callback)) return;
|
||||
|
||||
|
@ -1603,14 +1657,20 @@ function close(fs, context, fd, callback) {
|
|||
}
|
||||
}
|
||||
|
||||
function mknod(fs, context, path, mode, callback) {
|
||||
function mknod(fs, context, path, type, callback) {
|
||||
if(!pathCheck(path, callback)) return;
|
||||
make_node(context, path, mode, callback);
|
||||
make_node(context, path, type, callback);
|
||||
}
|
||||
|
||||
function mkdir(fs, context, path, mode, callback) {
|
||||
// NOTE: we support passing a mode arg, but we ignore it internally for now.
|
||||
callback = arguments[arguments.length - 1];
|
||||
if (arguments.length < 5) {
|
||||
callback = mode;
|
||||
mode = FULL_READ_WRITE_EXEC_PERMISSIONS;
|
||||
} else {
|
||||
mode = validateAndMaskMode(mode, FULL_READ_WRITE_EXEC_PERMISSIONS, callback);
|
||||
if(!mode) return;
|
||||
}
|
||||
|
||||
if(!pathCheck(path, callback)) return;
|
||||
make_directory(context, path, callback);
|
||||
}
|
||||
|
@ -1627,7 +1687,7 @@ function stat(fs, context, path, callback) {
|
|||
if(error) {
|
||||
callback(error);
|
||||
} else {
|
||||
var stats = new Stats(result, fs.name);
|
||||
var stats = new Stats(path, result, fs.name);
|
||||
callback(null, stats);
|
||||
}
|
||||
}
|
||||
|
@ -1640,7 +1700,7 @@ function fstat(fs, context, fd, callback) {
|
|||
if(error) {
|
||||
callback(error);
|
||||
} else {
|
||||
var stats = new Stats(result, fs.name);
|
||||
var stats = new Stats(ofd.path, result, fs.name);
|
||||
callback(null, stats);
|
||||
}
|
||||
}
|
||||
|
@ -1713,7 +1773,7 @@ function readFile(fs, context, path, options, callback) {
|
|||
return callback(err);
|
||||
}
|
||||
|
||||
var stats = new Stats(fstatResult, fs.name);
|
||||
var stats = new Stats(ofd.path, fstatResult, fs.name);
|
||||
|
||||
if(stats.isDirectory()) {
|
||||
cleanup();
|
||||
|
@ -1841,6 +1901,121 @@ function exists(fs, context, path, callback) {
|
|||
stat(fs, context, path, cb);
|
||||
}
|
||||
|
||||
// Based on https://github.com/nodejs/node/blob/c700cc42da9cf73af9fec2098520a6c0a631d901/lib/internal/validators.js#L21
|
||||
var octalReg = /^[0-7]+$/;
|
||||
var modeDesc = 'must be a 32-bit unsigned integer or an octal string';
|
||||
function isUint32(value) {
|
||||
return value === (value >>> 0);
|
||||
}
|
||||
// Validator for mode_t (the S_* constants). Valid numbers or octal strings
|
||||
// will be masked with 0o777 to be consistent with the behavior in POSIX APIs.
|
||||
function validateAndMaskMode(value, def, callback) {
|
||||
if(typeof def === 'function') {
|
||||
callback = def;
|
||||
def = undefined;
|
||||
}
|
||||
|
||||
if (isUint32(value)) {
|
||||
return value & FULL_READ_WRITE_EXEC_PERMISSIONS;
|
||||
}
|
||||
|
||||
if (typeof value === 'number') {
|
||||
if (!Number.isInteger(value)) {
|
||||
callback(new Errors.EINVAL('mode not a valid an integer value', value));
|
||||
return false;
|
||||
} else {
|
||||
// 2 ** 32 === 4294967296
|
||||
callback(new Errors.EINVAL('mode not a valid an integer value', value));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
if (!octalReg.test(value)) {
|
||||
callback(new Errors.EINVAL('mode not a valid octal string', value));
|
||||
return false;
|
||||
}
|
||||
var parsed = parseInt(value, 8);
|
||||
return parsed & FULL_READ_WRITE_EXEC_PERMISSIONS;
|
||||
}
|
||||
|
||||
// TODO(BridgeAR): Only return `def` in case `value === null`
|
||||
if (def !== undefined) {
|
||||
return def;
|
||||
}
|
||||
|
||||
callback(new Errors.EINVAL('mode not valid', value));
|
||||
return false;
|
||||
}
|
||||
|
||||
function chmod_file(context, path, mode, callback) {
|
||||
path = normalize(path);
|
||||
|
||||
function update_mode(error, node) {
|
||||
if (error) {
|
||||
callback(error);
|
||||
} else {
|
||||
Node.setMode(mode, node);
|
||||
update_node_times(context, path, node, { mtime: Date.now() }, callback);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof mode !== 'number') {
|
||||
callback(new Errors.EINVAL('mode must be number', path));
|
||||
}
|
||||
else {
|
||||
find_node(context, path, update_mode);
|
||||
}
|
||||
}
|
||||
|
||||
function fchmod_file(context, ofd, mode, callback) {
|
||||
function update_mode(error, node) {
|
||||
if (error) {
|
||||
callback(error);
|
||||
} else {
|
||||
node.mode = mode;
|
||||
update_node_times(context, ofd.path, node, { mtime: Date.now() }, callback);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof mode !== 'number') {
|
||||
callback(new Errors.EINVAL('mode must be a number'));
|
||||
}
|
||||
else {
|
||||
ofd.getNode(context, update_mode);
|
||||
}
|
||||
}
|
||||
|
||||
function chown_file(context, path, uid, gid, callback) {
|
||||
path = normalize(path);
|
||||
|
||||
function update_owner(error, node) {
|
||||
if (error) {
|
||||
callback(error);
|
||||
} else {
|
||||
node.uid = uid;
|
||||
node.gid = gid;
|
||||
update_node_times(context, path, node, { mtime: Date.now() }, callback);
|
||||
}
|
||||
}
|
||||
|
||||
find_node(context, path, update_owner);
|
||||
}
|
||||
|
||||
function fchown_file(context, ofd, uid, gid, callback) {
|
||||
function update_owner(error, node) {
|
||||
if (error) {
|
||||
callback(error);
|
||||
} else {
|
||||
node.uid = uid;
|
||||
node.gid = gid;
|
||||
update_node_times(context, ofd.path, node, { mtime: Date.now() }, callback);
|
||||
}
|
||||
}
|
||||
|
||||
ofd.getNode(context, update_owner);
|
||||
}
|
||||
|
||||
function getxattr(fs, context, path, name, callback) {
|
||||
if (!pathCheck(path, callback)) return;
|
||||
getxattr_file(context, path, name, callback);
|
||||
|
@ -1972,6 +2147,58 @@ function futimes(fs, context, fd, atime, mtime, callback) {
|
|||
}
|
||||
}
|
||||
|
||||
function chmod(fs, context, path, mode, callback) {
|
||||
if(!pathCheck(path, callback)) return;
|
||||
mode = validateAndMaskMode(mode, 'mode');
|
||||
if(!mode) return;
|
||||
|
||||
chmod_file(context, path, mode, callback);
|
||||
}
|
||||
|
||||
function fchmod(fs, context, fd, mode, callback) {
|
||||
mode = validateAndMaskMode(mode, 'mode');
|
||||
if(!mode) return;
|
||||
|
||||
var ofd = fs.openFiles[fd];
|
||||
if(!ofd) {
|
||||
callback(new Errors.EBADF());
|
||||
} else if(!_(ofd.flags).contains(O_WRITE)) {
|
||||
callback(new Errors.EBADF('descriptor does not permit writing'));
|
||||
} else {
|
||||
fchmod_file(context, ofd, mode, callback);
|
||||
}
|
||||
}
|
||||
|
||||
function chown(fs, context, path, uid, gid, callback) {
|
||||
if(!pathCheck(path, callback)) return;
|
||||
if(!isUint32(uid)) {
|
||||
return callback(new Errors.EINVAL('uid must be a valid integer', uid));
|
||||
}
|
||||
if(!isUint32(gid)) {
|
||||
return callback(new Errors.EINVAL('gid must be a valid integer', gid));
|
||||
}
|
||||
|
||||
chown_file(context, path, uid, gid, callback);
|
||||
}
|
||||
|
||||
function fchown(fs, context, fd, uid, gid, callback) {
|
||||
if(!isUint32(uid)) {
|
||||
return callback(new Errors.EINVAL('uid must be a valid integer', uid));
|
||||
}
|
||||
if(!isUint32(gid)) {
|
||||
return callback(new Errors.EINVAL('gid must be a valid integer', gid));
|
||||
}
|
||||
|
||||
var ofd = fs.openFiles[fd];
|
||||
if(!ofd) {
|
||||
callback(new Errors.EBADF());
|
||||
} else if(!_(ofd.flags).contains(O_WRITE)) {
|
||||
callback(new Errors.EBADF('descriptor does not permit writing'));
|
||||
} else {
|
||||
fchown_file(context, ofd, uid, gid, callback);
|
||||
}
|
||||
}
|
||||
|
||||
function rename(fs, context, oldpath, newpath, callback) {
|
||||
if(!pathCheck(oldpath, callback)) return;
|
||||
if(!pathCheck(newpath, callback)) return;
|
||||
|
@ -1985,12 +2212,15 @@ function rename(fs, context, oldpath, newpath, callback) {
|
|||
var newName = Path.basename(newpath);
|
||||
var oldParentDirectory, oldParentData;
|
||||
var newParentDirectory, newParentData;
|
||||
var ctime = Date.now();
|
||||
var fileNode;
|
||||
|
||||
function update_times(error, newNode) {
|
||||
function update_times(error, result) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
} else {
|
||||
update_node_times(context, newpath, newNode, { ctime: Date.now() }, callback);
|
||||
fileNode = result;
|
||||
update_node_times(context, newpath, fileNode, { ctime: ctime }, callback);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2074,7 +2304,7 @@ function rename(fs, context, oldpath, newpath, callback) {
|
|||
function check_node_type(error, node) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
} else if(node.mode === 'DIRECTORY') {
|
||||
} else if(node.type === NODE_TYPE_DIRECTORY) {
|
||||
find_node(context, oldParentPath, read_parent_directory_data);
|
||||
} else {
|
||||
link_node(context, oldpath, newpath, unlink_old_file);
|
||||
|
@ -2087,8 +2317,13 @@ function rename(fs, context, oldpath, newpath, callback) {
|
|||
function symlink(fs, context, srcpath, dstpath, type, callback) {
|
||||
// NOTE: we support passing the `type` arg, but ignore it.
|
||||
callback = arguments[arguments.length - 1];
|
||||
if(!pathCheck(srcpath, callback)) return;
|
||||
|
||||
// Special Case: allow srcpath to be relative, which we normally don't permit.
|
||||
// If the srcpath is relative, we assume it's relative to the dirpath of
|
||||
// dstpath.
|
||||
if(!pathCheck(srcpath, true, callback)) return;
|
||||
if(!pathCheck(dstpath, callback)) return;
|
||||
|
||||
make_symbolic_link(context, srcpath, dstpath, callback);
|
||||
}
|
||||
|
||||
|
@ -2104,7 +2339,7 @@ function lstat(fs, context, path, callback) {
|
|||
if(error) {
|
||||
callback(error);
|
||||
} else {
|
||||
var stats = new Stats(result, fs.name);
|
||||
var stats = new Stats(path, result, fs.name);
|
||||
callback(null, stats);
|
||||
}
|
||||
}
|
||||
|
@ -2139,6 +2374,10 @@ function ftruncate(fs, context, fd, length, callback) {
|
|||
module.exports = {
|
||||
ensureRootDirectory: ensure_root_directory,
|
||||
open: open,
|
||||
chmod: chmod,
|
||||
fchmod: fchmod,
|
||||
chown: chown,
|
||||
fchown: fchown,
|
||||
close: close,
|
||||
mknod: mknod,
|
||||
mkdir: mkdir,
|
||||
|
|
|
@ -94,6 +94,9 @@ function FileSystem(options, callback) {
|
|||
fs.stdout = STDOUT;
|
||||
fs.stderr = STDERR;
|
||||
|
||||
// Expose Node's fs.constants to users
|
||||
fs.constants = Constants.fsConstants;
|
||||
|
||||
// Expose Shell constructor
|
||||
this.Shell = Shell.bind(undefined, this);
|
||||
|
||||
|
@ -268,6 +271,10 @@ FileSystem.providers = providers;
|
|||
*/
|
||||
[
|
||||
'open',
|
||||
'chmod',
|
||||
'fchmod',
|
||||
'chown',
|
||||
'fchown',
|
||||
'close',
|
||||
'mknod',
|
||||
'mkdir',
|
||||
|
|
44
src/node.js
44
src/node.js
|
@ -1,10 +1,36 @@
|
|||
var MODE_FILE = require('./constants.js').MODE_FILE;
|
||||
var NODE_TYPE_FILE = require('./constants.js').NODE_TYPE_FILE;
|
||||
var NODE_TYPE_DIRECTORY = require('./constants.js').NODE_TYPE_DIRECTORY;
|
||||
var NODE_TYPE_SYMBOLIC_LINK = require('./constants.js').NODE_TYPE_SYMBOLIC_LINK;
|
||||
var NODE_TYPE_META = require('./constants.js').NODE_TYPE_META;
|
||||
|
||||
var ROOT_DIRECTORY_NAME = require('./constants.js').ROOT_DIRECTORY_NAME;
|
||||
|
||||
var S_IFREG = require('./constants.js').S_IFREG;
|
||||
var S_IFDIR = require('./constants.js').S_IFDIR;
|
||||
var S_IFLNK = require('./constants.js').S_IFLNK;
|
||||
|
||||
var DEFAULT_FILE_PERMISSIONS = require('./constants.js').DEFAULT_FILE_PERMISSIONS;
|
||||
var DEFAULT_DIR_PERMISSIONS = require('./constants.js').DEFAULT_DIR_PERMISSIONS;
|
||||
|
||||
function getMode(type, mode) {
|
||||
switch(type) {
|
||||
case NODE_TYPE_DIRECTORY:
|
||||
return (mode || DEFAULT_DIR_PERMISSIONS) | S_IFDIR;
|
||||
case NODE_TYPE_SYMBOLIC_LINK:
|
||||
return (mode || DEFAULT_FILE_PERMISSIONS) | S_IFLNK;
|
||||
/* jshint -W086 */
|
||||
case NODE_TYPE_FILE:
|
||||
// falls through
|
||||
default:
|
||||
return (mode || DEFAULT_FILE_PERMISSIONS) | S_IFREG;
|
||||
}
|
||||
}
|
||||
|
||||
function Node(options) {
|
||||
var now = Date.now();
|
||||
|
||||
this.id = options.id;
|
||||
this.mode = options.mode || MODE_FILE; // node type (file, directory, etc)
|
||||
this.type = options.type || NODE_TYPE_FILE; // node type (file, directory, etc)
|
||||
this.size = options.size || 0; // size (bytes for files, entries for directories)
|
||||
this.atime = options.atime || now; // access time (will mirror ctime after creation)
|
||||
this.ctime = options.ctime || now; // creation/change time
|
||||
|
@ -12,10 +38,13 @@ function Node(options) {
|
|||
this.flags = options.flags || []; // file flags
|
||||
this.xattrs = options.xattrs || {}; // extended attributes
|
||||
this.nlinks = options.nlinks || 0; // links count
|
||||
this.version = options.version || 0; // node version
|
||||
this.blksize = undefined; // block size
|
||||
this.nblocks = 1; // blocks count
|
||||
this.data = options.data; // id for data object
|
||||
this.version = options.version || 1;
|
||||
|
||||
// permissions and flags
|
||||
this.mode = options.mode || (getMode(this.type));
|
||||
this.uid = options.uid || 0x0; // owner name
|
||||
this.gid = options.gid || 0x0; // group name
|
||||
}
|
||||
|
||||
// Make sure the options object has an id on property,
|
||||
|
@ -50,4 +79,9 @@ Node.create = function(options, callback) {
|
|||
});
|
||||
};
|
||||
|
||||
// Update the node's mode (permissions), taking file type bits into account.
|
||||
Node.setMode = function(mode, node) {
|
||||
node.mode = getMode(node.type, mode);
|
||||
};
|
||||
|
||||
module.exports = Node;
|
||||
|
|
|
@ -89,12 +89,7 @@ IndexedDBContext.prototype.putObject = function(key, value, callback) {
|
|||
this._put(key, value, callback);
|
||||
};
|
||||
IndexedDBContext.prototype.putBuffer = function(key, uint8BackedBuffer, callback) {
|
||||
var buf;
|
||||
if(!Buffer._useTypedArrays) { // workaround for fxos 1.3
|
||||
buf = uint8BackedBuffer.toArrayBuffer();
|
||||
} else {
|
||||
buf = uint8BackedBuffer.buffer;
|
||||
}
|
||||
var buf = uint8BackedBuffer.buffer;
|
||||
this._put(key, buf, callback);
|
||||
};
|
||||
|
||||
|
|
|
@ -233,16 +233,10 @@ Shell.prototype.ls = function(dir, options, callback) {
|
|||
callback(error);
|
||||
return;
|
||||
}
|
||||
var entry = {
|
||||
path: Path.basename(name),
|
||||
links: stats.nlinks,
|
||||
size: stats.size,
|
||||
modified: stats.mtime,
|
||||
type: stats.type
|
||||
};
|
||||
var entry = stats;
|
||||
|
||||
if(options.recursive && stats.type === 'DIRECTORY') {
|
||||
list(Path.join(pathname, entry.path), function(error, items) {
|
||||
list(Path.join(pathname, entry.name), function(error, items) {
|
||||
if(error) {
|
||||
callback(error);
|
||||
return;
|
||||
|
|
18
src/stats.js
18
src/stats.js
|
@ -1,26 +1,32 @@
|
|||
var Constants = require('./constants.js');
|
||||
var Path = require('./path.js');
|
||||
|
||||
function Stats(fileNode, devName) {
|
||||
this.node = fileNode.id;
|
||||
function Stats(path, fileNode, devName) {
|
||||
this.dev = devName;
|
||||
this.node = fileNode.id;
|
||||
this.type = fileNode.type;
|
||||
this.size = fileNode.size;
|
||||
this.nlinks = fileNode.nlinks;
|
||||
this.atime = fileNode.atime;
|
||||
this.mtime = fileNode.mtime;
|
||||
this.ctime = fileNode.ctime;
|
||||
this.type = fileNode.mode;
|
||||
this.version = fileNode.version;
|
||||
this.mode = fileNode.mode;
|
||||
this.uid = fileNode.uid;
|
||||
this.gid = fileNode.gid;
|
||||
this.name = Path.basename(path);
|
||||
}
|
||||
|
||||
Stats.prototype.isFile = function() {
|
||||
return this.type === Constants.MODE_FILE;
|
||||
return this.type === Constants.NODE_TYPE_FILE;
|
||||
};
|
||||
|
||||
Stats.prototype.isDirectory = function() {
|
||||
return this.type === Constants.MODE_DIRECTORY;
|
||||
return this.type === Constants.NODE_TYPE_DIRECTORY;
|
||||
};
|
||||
|
||||
Stats.prototype.isSymbolicLink = function() {
|
||||
return this.type === Constants.MODE_SYMBOLIC_LINK;
|
||||
return this.type === Constants.NODE_TYPE_SYMBOLIC_LINK;
|
||||
};
|
||||
|
||||
// These will always be false in Filer.
|
||||
|
|
|
@ -4,7 +4,7 @@ function SuperNode(options) {
|
|||
var now = Date.now();
|
||||
|
||||
this.id = Constants.SUPER_NODE_ID;
|
||||
this.mode = Constants.MODE_META;
|
||||
this.type = Constants.NODE_TYPE_META;
|
||||
this.atime = options.atime || now;
|
||||
this.ctime = options.ctime || now;
|
||||
this.mtime = options.mtime || now;
|
||||
|
|
|
@ -39,6 +39,8 @@ require("./spec/time-flags.spec");
|
|||
require("./spec/fs.watch.spec");
|
||||
require("./spec/errors.spec");
|
||||
require("./spec/fs.shell.spec");
|
||||
require("./spec/fs.chmod.spec");
|
||||
require("./spec/fs.chown.spec")
|
||||
|
||||
// Filer.FileSystem.providers.*
|
||||
require("./spec/providers/providers.spec");
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
var Filer = require('../..');
|
||||
var util = require('../lib/test-utils.js');
|
||||
var expect = require('chai').expect;
|
||||
|
||||
describe('fs.chmod, fs.fchmod', function() {
|
||||
beforeEach(util.setup);
|
||||
afterEach(util.cleanup);
|
||||
|
||||
it('should be functions', function() {
|
||||
var fs = util.fs();
|
||||
expect(typeof fs.chmod).to.equal('function');
|
||||
expect(typeof fs.fchmod).to.equal('function');
|
||||
});
|
||||
|
||||
it('should automatically set mode=755 for a directory', function(done) {
|
||||
var fs = util.fs();
|
||||
|
||||
fs.mkdir('/dir', function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.stat('/dir', function(err, stats) {
|
||||
if(err) throw err;
|
||||
expect(stats.mode & 0o755).to.equal(0o755);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should automatically set mode=644 for a file', function(done) {
|
||||
var fs = util.fs();
|
||||
|
||||
fs.open('/file', 'w', function(err, fd) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.fstat(fd, function(err, stats) {
|
||||
if(err) throw err;
|
||||
expect(stats.mode & 0o644).to.equal(0o644);
|
||||
fs.close(fd, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow for updating mode of a given file', function(done) {
|
||||
var fs = util.fs();
|
||||
|
||||
fs.open('/file', 'w', function(err, fd) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.fchmod(fd, 0o777, function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.fstat(fd, function(err, stats) {
|
||||
if(err) throw err;
|
||||
expect(stats.mode & 0o777).to.equal(0o777);
|
||||
|
||||
fs.close(fd, function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.chmod('/file', 0o444, function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.stat('/file', function(err, stats) {
|
||||
if(err) throw err;
|
||||
|
||||
expect(stats.mode & 0o444).to.equal(0o444);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,65 @@
|
|||
var Filer = require('../..');
|
||||
var util = require('../lib/test-utils.js');
|
||||
var expect = require('chai').expect;
|
||||
|
||||
describe('fs.chown, fs.fchown', function() {
|
||||
beforeEach(util.setup);
|
||||
afterEach(util.cleanup);
|
||||
|
||||
it('should be functions', function() {
|
||||
var fs = util.fs();
|
||||
expect(typeof fs.chown).to.equal('function');
|
||||
expect(typeof fs.fchown).to.equal('function');
|
||||
});
|
||||
|
||||
it('should automatically set a file\s uid and gid to 0 (i.e., root)', function(done) {
|
||||
var fs = util.fs();
|
||||
|
||||
fs.open('/file', 'w', function(err, fd) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.fstat(fd, function(err, stats) {
|
||||
if(err) throw err;
|
||||
|
||||
expect(stats.uid).to.equal(0);
|
||||
expect(stats.gid).to.equal(0);
|
||||
fs.close(fd, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow updating gid and uid for a file', function(done) {
|
||||
var fs = util.fs();
|
||||
|
||||
fs.open('/file', 'w', function(err, fd) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.fchown(fd, 1001, 1001, function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.fstat(fd, function(err, stats) {
|
||||
if(err) throw err;
|
||||
|
||||
expect(stats.uid).to.equal(1001);
|
||||
expect(stats.gid).to.equal(1001);
|
||||
|
||||
fs.close(fd, function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.chown('/file', 500, 500, function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.stat('/file', function(err, stats) {
|
||||
if(err) throw err;
|
||||
|
||||
expect(stats.uid).to.equal(500);
|
||||
expect(stats.gid).to.equal(500);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -42,6 +42,30 @@ describe('fs.link', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('should create hard link to identical data node', function(done) {
|
||||
var fs = util.fs();
|
||||
var contents = "Hello World!";
|
||||
|
||||
fs.writeFile('/file', contents, function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.link('/file', '/hlink', function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.readFile('/file', 'utf8', function(err, fileData) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.readFile('/hlink', 'utf8', function(err, hlinkData) {
|
||||
if(err) throw err;
|
||||
|
||||
expect(fileData).to.equal(hlinkData);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should not follow symbolic links', function(done) {
|
||||
var fs = util.fs();
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
var Filer = require('../..');
|
||||
var Path = Filer.Path;
|
||||
var util = require('../lib/test-utils.js');
|
||||
var expect = require('chai').expect;
|
||||
|
||||
|
@ -256,4 +257,41 @@ describe('fs.stats', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('generated name property', function() {
|
||||
beforeEach(util.setup);
|
||||
afterEach(util.cleanup);
|
||||
|
||||
it('should correct return name for a file', function(done) {
|
||||
var fs = util.fs();
|
||||
var filepath = '/a';
|
||||
|
||||
fs.writeFile(filepath, 'data', function(err) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.stat(filepath, function(err, stats) {
|
||||
if(err) throw err;
|
||||
|
||||
expect(stats.name).to.equal(Path.basename(filepath));
|
||||
done();
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('should correct return name for an fd', function(done) {
|
||||
var fs = util.fs();
|
||||
var filepath = '/a';
|
||||
|
||||
fs.open(filepath, 'w', function(err, fd) {
|
||||
if(err) throw err;
|
||||
|
||||
fs.fstat(fd, function(err, stats) {
|
||||
if(err) throw err;
|
||||
|
||||
expect(stats.name).to.equal(Path.basename(filepath));
|
||||
done();
|
||||
});
|
||||
})
|
||||
});
|
||||
})
|
||||
});
|
||||
|
|
|
@ -26,7 +26,6 @@ describe("node.js tests: https://github.com/joyent/node/blob/master/test/simple/
|
|||
done();
|
||||
}
|
||||
});
|
||||
|
||||
fn.apply(fs, args);
|
||||
}
|
||||
|
||||
|
@ -49,11 +48,10 @@ describe("node.js tests: https://github.com/joyent/node/blob/master/test/simple/
|
|||
check(fs.appendFile, '/foo\u0000bar');
|
||||
check(fs.truncate, '/foo\u0000bar');
|
||||
check(fs.utimes, '/foo\u0000bar', 0, 0);
|
||||
// TODO - need to be implemented still...
|
||||
// check(fs.realpath, '/foo\u0000bar');
|
||||
// check(fs.chmod, '/foo\u0000bar', '0644');
|
||||
// check(fs.chown, '/foo\u0000bar', 12, 34);
|
||||
// check(fs.realpath, '/foo\u0000bar');
|
||||
// Not implemented
|
||||
// check(fs.realpath, '/foo\u0000bar');
|
||||
check(fs.chmod, '/foo\u0000bar', '0644');
|
||||
check(fs.chown, '/foo\u0000bar', 12, 34);
|
||||
|
||||
checks.forEach(function(fn){
|
||||
fn();
|
||||
|
|
|
@ -40,18 +40,18 @@ describe('FileSystemShell.ls', function() {
|
|||
expect(list.length).to.equal(2);
|
||||
|
||||
var item0 = list[0];
|
||||
expect(item0.path).to.equal('file');
|
||||
expect(item0.links).to.equal(1);
|
||||
expect(item0.name).to.equal('file');
|
||||
expect(item0.nlinks).to.equal(1);
|
||||
expect(item0.size).to.equal(1);
|
||||
expect(item0.modified).to.be.a('number');
|
||||
expect(item0.mtime).to.be.a('number');
|
||||
expect(item0.type).to.equal('FILE');
|
||||
expect(item0.contents).not.to.exist;
|
||||
|
||||
var item1 = list[1];
|
||||
expect(item1.path).to.equal('file2');
|
||||
expect(item1.links).to.equal(1);
|
||||
expect(item1.name).to.equal('file2');
|
||||
expect(item1.nlinks).to.equal(1);
|
||||
expect(item1.size).to.equal(2);
|
||||
expect(item1.modified).to.be.a('number');
|
||||
expect(item1.mtime).to.be.a('number');
|
||||
expect(item1.type).to.equal('FILE');
|
||||
expect(item0.contents).not.to.exist;
|
||||
|
||||
|
@ -84,19 +84,19 @@ describe('FileSystemShell.ls', function() {
|
|||
|
||||
// We shouldn't rely on the order we'll get the listing
|
||||
list.forEach(function(item, i, arr) {
|
||||
switch(item.path) {
|
||||
switch(item.name) {
|
||||
case 'dir2':
|
||||
expect(item.links).to.equal(1);
|
||||
expect(item.nlinks).to.equal(1);
|
||||
expect(item.size).to.be.a('number');
|
||||
expect(item.modified).to.be.a('number');
|
||||
expect(item.mtime).to.be.a('number');
|
||||
expect(item.type).to.equal('DIRECTORY');
|
||||
expect(item.contents).not.to.exist;
|
||||
break;
|
||||
case 'file':
|
||||
case 'file2':
|
||||
expect(item.links).to.equal(1);
|
||||
expect(item.nlinks).to.equal(1);
|
||||
expect(item.size).to.equal(1);
|
||||
expect(item.modified).to.be.a('number');
|
||||
expect(item.mtime).to.be.a('number');
|
||||
expect(item.type).to.equal('FILE');
|
||||
expect(item.contents).not.to.exist;
|
||||
break;
|
||||
|
@ -143,27 +143,27 @@ describe('FileSystemShell.ls', function() {
|
|||
|
||||
// We shouldn't rely on the order we'll get the listing
|
||||
list.forEach(function(item, i, arr) {
|
||||
switch(item.path) {
|
||||
switch(item.name) {
|
||||
case 'dir2':
|
||||
expect(item.links).to.equal(1);
|
||||
expect(item.nlinks).to.equal(1);
|
||||
expect(item.size).to.be.a('number');
|
||||
expect(item.modified).to.be.a('number');
|
||||
expect(item.mtime).to.be.a('number');
|
||||
expect(item.type).to.equal('DIRECTORY');
|
||||
expect(item.contents).to.exist;
|
||||
expect(item.contents.length).to.equal(1);
|
||||
var contents0 = item.contents[0];
|
||||
expect(contents0.path).to.equal('file');
|
||||
expect(contents0.links).to.equal(1);
|
||||
expect(contents0.name).to.equal('file');
|
||||
expect(contents0.nlinks).to.equal(1);
|
||||
expect(contents0.size).to.equal(1);
|
||||
expect(contents0.modified).to.be.a('number');
|
||||
expect(contents0.mtime).to.be.a('number');
|
||||
expect(contents0.type).to.equal('FILE');
|
||||
expect(contents0.contents).not.to.exist;
|
||||
break;
|
||||
case 'file':
|
||||
case 'file2':
|
||||
expect(item.links).to.equal(1);
|
||||
expect(item.nlinks).to.equal(1);
|
||||
expect(item.size).to.equal(1);
|
||||
expect(item.modified).to.be.a('number');
|
||||
expect(item.mtime).to.be.a('number');
|
||||
expect(item.type).to.equal('FILE');
|
||||
expect(item.contents).not.to.exist;
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue