fs: Buffer and encoding enhancements to fs API
This makes several changes: 1. Allow path/filename to be passed in as a Buffer on fs methods 2. Add `options.encoding` to fs.readdir, fs.readdirSync, fs.readlink, fs.readlinkSync and fs.watch. 3. Documentation updates For 1... it's now possible to do: ```js fs.open(Buffer('/fs/foo/bar'), 'w+', (err, fd) => { }); ``` For 2... ```js fs.readdir('/fs/foo/bar', {encoding:'hex'}, (err,list) => { }); fs.readdir('/fs/foo/bar', {encoding:'buffer'}, (err, list) => { }); ``` encoding can also be passed as a string ```js fs.readdir('/fs/foo/bar', 'hex', (err,list) => { }); ``` The default encoding is set to UTF8 so this addresses the discrepency that existed previously between fs.readdir and fs.watch handling filenames differently. Fixes: https://github.com/nodejs/node/issues/2088 Refs: https://github.com/nodejs/node/issues/3519 PR-URL: https://github.com/nodejs/node/pull/5616 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Trevor Norris <trev.norris@gmail.com>
This commit is contained in:
parent
4d4f3535a9
commit
060e5f0c00
@ -101,11 +101,24 @@ Objects returned from `fs.watch()` are of this type.
|
|||||||
### Event: 'change'
|
### Event: 'change'
|
||||||
|
|
||||||
* `event` {String} The type of fs change
|
* `event` {String} The type of fs change
|
||||||
* `filename` {String} The filename that changed (if relevant/available)
|
* `filename` {String | Buffer} The filename that changed (if relevant/available)
|
||||||
|
|
||||||
Emitted when something changes in a watched directory or file.
|
Emitted when something changes in a watched directory or file.
|
||||||
See more details in [`fs.watch()`][].
|
See more details in [`fs.watch()`][].
|
||||||
|
|
||||||
|
The `filename` argument may not be provided depending on operating system
|
||||||
|
support. If `filename` is provided, it will be provided as a `Buffer` if
|
||||||
|
`fs.watch()` is called with it's `encoding` option set to `'buffer'`, otherwise
|
||||||
|
`filename` will be a string.
|
||||||
|
|
||||||
|
```js
|
||||||
|
fs.watch('./tmp', {encoding: 'buffer'}, (event, filename) => {
|
||||||
|
if (filename)
|
||||||
|
console.log(filename);
|
||||||
|
// Prints: <Buffer ...>
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
### Event: 'error'
|
### Event: 'error'
|
||||||
|
|
||||||
* `error` {Error}
|
* `error` {Error}
|
||||||
@ -128,7 +141,10 @@ Emitted when the ReadStream's file is opened.
|
|||||||
|
|
||||||
### readStream.path
|
### readStream.path
|
||||||
|
|
||||||
The path to the file the stream is reading from.
|
The path to the file the stream is reading from as specified in the first
|
||||||
|
argument to `fs.createReadStream()`. If `path` is passed as a string, then
|
||||||
|
`readStream.path` will be a string. If `path` is passed as a `Buffer`, then
|
||||||
|
`readStream.path` will be a `Buffer`.
|
||||||
|
|
||||||
## Class: fs.Stats
|
## Class: fs.Stats
|
||||||
|
|
||||||
@ -217,11 +233,14 @@ for writing.
|
|||||||
|
|
||||||
### writeStream.path
|
### writeStream.path
|
||||||
|
|
||||||
The path to the file the stream is writing to.
|
The path to the file the stream is writing to as specified in the first
|
||||||
|
argument to `fs.createWriteStream()`. If `path` is passed as a string, then
|
||||||
|
`writeStream.path` will be a string. If `path` is passed as a `Buffer`, then
|
||||||
|
`writeStream.path` will be a `Buffer`.
|
||||||
|
|
||||||
## fs.access(path[, mode], callback)
|
## fs.access(path[, mode], callback)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `mode` {Integer}
|
* `mode` {Integer}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
|
|
||||||
@ -251,7 +270,7 @@ fs.access('/etc/passwd', fs.R_OK | fs.W_OK, (err) => {
|
|||||||
|
|
||||||
## fs.accessSync(path[, mode])
|
## fs.accessSync(path[, mode])
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `mode` {Integer}
|
* `mode` {Integer}
|
||||||
|
|
||||||
Synchronous version of [`fs.access()`][]. This throws if any accessibility checks
|
Synchronous version of [`fs.access()`][]. This throws if any accessibility checks
|
||||||
@ -259,7 +278,7 @@ fail, and does nothing otherwise.
|
|||||||
|
|
||||||
## fs.appendFile(file, data[, options], callback)
|
## fs.appendFile(file, data[, options], callback)
|
||||||
|
|
||||||
* `file` {String | Number} filename or file descriptor
|
* `file` {String | Buffer | Number} filename or file descriptor
|
||||||
* `data` {String | Buffer}
|
* `data` {String | Buffer}
|
||||||
* `options` {Object | String}
|
* `options` {Object | String}
|
||||||
* `encoding` {String | Null} default = `'utf8'`
|
* `encoding` {String | Null} default = `'utf8'`
|
||||||
@ -291,11 +310,18 @@ _Note: Specified file descriptors will not be closed automatically._
|
|||||||
|
|
||||||
## fs.appendFileSync(file, data[, options])
|
## fs.appendFileSync(file, data[, options])
|
||||||
|
|
||||||
|
* `file` {String | Buffer}
|
||||||
|
* `data` {String | Buffer}
|
||||||
|
* `options` {Object | String}
|
||||||
|
* `encoding` {String | Null} default = `'utf8'`
|
||||||
|
* `mode` {Integer} default = `0o666`
|
||||||
|
* `flag` {String} default = `'a'`
|
||||||
|
|
||||||
The synchronous version of [`fs.appendFile()`][]. Returns `undefined`.
|
The synchronous version of [`fs.appendFile()`][]. Returns `undefined`.
|
||||||
|
|
||||||
## fs.chmod(path, mode, callback)
|
## fs.chmod(path, mode, callback)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `mode` {Integer}
|
* `mode` {Integer}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
|
|
||||||
@ -304,14 +330,14 @@ to the completion callback.
|
|||||||
|
|
||||||
## fs.chmodSync(path, mode)
|
## fs.chmodSync(path, mode)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `mode` {Integer}
|
* `mode` {Integer}
|
||||||
|
|
||||||
Synchronous chmod(2). Returns `undefined`.
|
Synchronous chmod(2). Returns `undefined`.
|
||||||
|
|
||||||
## fs.chown(path, uid, gid, callback)
|
## fs.chown(path, uid, gid, callback)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `uid` {Integer}
|
* `uid` {Integer}
|
||||||
* `gid` {Integer}
|
* `gid` {Integer}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
@ -321,7 +347,7 @@ to the completion callback.
|
|||||||
|
|
||||||
## fs.chownSync(path, uid, gid)
|
## fs.chownSync(path, uid, gid)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `uid` {Integer}
|
* `uid` {Integer}
|
||||||
* `gid` {Integer}
|
* `gid` {Integer}
|
||||||
|
|
||||||
@ -343,7 +369,7 @@ Synchronous close(2). Returns `undefined`.
|
|||||||
|
|
||||||
## fs.createReadStream(path[, options])
|
## fs.createReadStream(path[, options])
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `options` {String | Object}
|
* `options` {String | Object}
|
||||||
* `flags` {String}
|
* `flags` {String}
|
||||||
* `encoding` {String}
|
* `encoding` {String}
|
||||||
@ -399,7 +425,7 @@ If `options` is a string, then it specifies the encoding.
|
|||||||
|
|
||||||
## fs.createWriteStream(path[, options])
|
## fs.createWriteStream(path[, options])
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `options` {String | Object}
|
* `options` {String | Object}
|
||||||
* `flags` {String}
|
* `flags` {String}
|
||||||
* `defaultEncoding` {String}
|
* `defaultEncoding` {String}
|
||||||
@ -444,7 +470,7 @@ If `options` is a string, then it specifies the encoding.
|
|||||||
|
|
||||||
Stability: 0 - Deprecated: Use [`fs.stat()`][] or [`fs.access()`][] instead.
|
Stability: 0 - Deprecated: Use [`fs.stat()`][] or [`fs.access()`][] instead.
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
|
|
||||||
Test whether or not the given path exists by checking with the file system.
|
Test whether or not the given path exists by checking with the file system.
|
||||||
@ -466,7 +492,7 @@ non-existent.
|
|||||||
|
|
||||||
Stability: 0 - Deprecated: Use [`fs.statSync()`][] or [`fs.accessSync()`][] instead.
|
Stability: 0 - Deprecated: Use [`fs.statSync()`][] or [`fs.accessSync()`][] instead.
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
|
|
||||||
Synchronous version of [`fs.exists()`][].
|
Synchronous version of [`fs.exists()`][].
|
||||||
Returns `true` if the file exists, `false` otherwise.
|
Returns `true` if the file exists, `false` otherwise.
|
||||||
@ -584,7 +610,7 @@ Synchronous version of [`fs.futimes()`][]. Returns `undefined`.
|
|||||||
|
|
||||||
## fs.lchmod(path, mode, callback)
|
## fs.lchmod(path, mode, callback)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `mode` {Integer}
|
* `mode` {Integer}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
|
|
||||||
@ -595,14 +621,14 @@ Only available on Mac OS X.
|
|||||||
|
|
||||||
## fs.lchmodSync(path, mode)
|
## fs.lchmodSync(path, mode)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `mode` {Integer}
|
* `mode` {Integer}
|
||||||
|
|
||||||
Synchronous lchmod(2). Returns `undefined`.
|
Synchronous lchmod(2). Returns `undefined`.
|
||||||
|
|
||||||
## fs.lchown(path, uid, gid, callback)
|
## fs.lchown(path, uid, gid, callback)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `uid` {Integer}
|
* `uid` {Integer}
|
||||||
* `gid` {Integer}
|
* `gid` {Integer}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
@ -612,7 +638,7 @@ to the completion callback.
|
|||||||
|
|
||||||
## fs.lchownSync(path, uid, gid)
|
## fs.lchownSync(path, uid, gid)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `uid` {Integer}
|
* `uid` {Integer}
|
||||||
* `gid` {Integer}
|
* `gid` {Integer}
|
||||||
|
|
||||||
@ -620,8 +646,8 @@ Synchronous lchown(2). Returns `undefined`.
|
|||||||
|
|
||||||
## fs.link(srcpath, dstpath, callback)
|
## fs.link(srcpath, dstpath, callback)
|
||||||
|
|
||||||
* `srcpath` {String}
|
* `srcpath` {String | Buffer}
|
||||||
* `dstpath` {String}
|
* `dstpath` {String | Buffer}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
|
|
||||||
Asynchronous link(2). No arguments other than a possible exception are given to
|
Asynchronous link(2). No arguments other than a possible exception are given to
|
||||||
@ -629,14 +655,14 @@ the completion callback.
|
|||||||
|
|
||||||
## fs.linkSync(srcpath, dstpath)
|
## fs.linkSync(srcpath, dstpath)
|
||||||
|
|
||||||
* `srcpath` {String}
|
* `srcpath` {String | Buffer}
|
||||||
* `dstpath` {String}
|
* `dstpath` {String | Buffer}
|
||||||
|
|
||||||
Synchronous link(2). Returns `undefined`.
|
Synchronous link(2). Returns `undefined`.
|
||||||
|
|
||||||
## fs.lstat(path, callback)
|
## fs.lstat(path, callback)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
|
|
||||||
Asynchronous lstat(2). The callback gets two arguments `(err, stats)` where
|
Asynchronous lstat(2). The callback gets two arguments `(err, stats)` where
|
||||||
@ -646,13 +672,13 @@ refers to.
|
|||||||
|
|
||||||
## fs.lstatSync(path)
|
## fs.lstatSync(path)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
|
|
||||||
Synchronous lstat(2). Returns an instance of `fs.Stats`.
|
Synchronous lstat(2). Returns an instance of `fs.Stats`.
|
||||||
|
|
||||||
## fs.mkdir(path[, mode], callback)
|
## fs.mkdir(path[, mode], callback)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `mode` {Integer}
|
* `mode` {Integer}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
|
|
||||||
@ -661,7 +687,7 @@ to the completion callback. `mode` defaults to `0o777`.
|
|||||||
|
|
||||||
## fs.mkdirSync(path[, mode])
|
## fs.mkdirSync(path[, mode])
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `mode` {Integer}
|
* `mode` {Integer}
|
||||||
|
|
||||||
Synchronous mkdir(2). Returns `undefined`.
|
Synchronous mkdir(2). Returns `undefined`.
|
||||||
@ -692,7 +718,7 @@ folder path.
|
|||||||
|
|
||||||
## fs.open(path, flags[, mode], callback)
|
## fs.open(path, flags[, mode], callback)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `flags` {String | Number}
|
* `flags` {String | Number}
|
||||||
* `mode` {Integer}
|
* `mode` {Integer}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
@ -759,7 +785,7 @@ the end of the file.
|
|||||||
|
|
||||||
## fs.openSync(path, flags[, mode])
|
## fs.openSync(path, flags[, mode])
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `flags` {String | Number}
|
* `flags` {String | Number}
|
||||||
* `mode` {Integer}
|
* `mode` {Integer}
|
||||||
|
|
||||||
@ -788,7 +814,12 @@ If `position` is `null`, data will be read from the current file position.
|
|||||||
|
|
||||||
The callback is given the three arguments, `(err, bytesRead, buffer)`.
|
The callback is given the three arguments, `(err, bytesRead, buffer)`.
|
||||||
|
|
||||||
## fs.readdir(path, callback)
|
## fs.readdir(path[, options], callback)
|
||||||
|
|
||||||
|
* `path` {String | Buffer}
|
||||||
|
* `options` {String | Object}
|
||||||
|
* `encoding` {String} default = `'utf8'`
|
||||||
|
* `callback` {Function}
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
@ -797,16 +828,30 @@ Asynchronous readdir(3). Reads the contents of a directory.
|
|||||||
The callback gets two arguments `(err, files)` where `files` is an array of
|
The callback gets two arguments `(err, files)` where `files` is an array of
|
||||||
the names of the files in the directory excluding `'.'` and `'..'`.
|
the names of the files in the directory excluding `'.'` and `'..'`.
|
||||||
|
|
||||||
## fs.readdirSync(path)
|
The optional `options` argument can be a string specifying an encoding, or an
|
||||||
|
object with an `encoding` property specifying the character encoding to use for
|
||||||
|
the filenames passed to the callback. If the `encoding` is set to `'buffer'`,
|
||||||
|
the filenames returned will be passed as `Buffer` objects.
|
||||||
|
|
||||||
|
## fs.readdirSync(path[, options])
|
||||||
|
|
||||||
|
* `path` {String | Buffer}
|
||||||
|
* `options` {String | Object}
|
||||||
|
* `encoding` {String} default = `'utf8'`
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String}
|
||||||
|
|
||||||
Synchronous readdir(3). Returns an array of filenames excluding `'.'` and
|
Synchronous readdir(3). Returns an array of filenames excluding `'.'` and
|
||||||
`'..'`.
|
`'..'`.
|
||||||
|
|
||||||
|
The optional `options` argument can be a string specifying an encoding, or an
|
||||||
|
object with an `encoding` property specifying the character encoding to use for
|
||||||
|
the filenames passed to the callback. If the `encoding` is set to `'buffer'`,
|
||||||
|
the filenames returned will be passed as `Buffer` objects.
|
||||||
|
|
||||||
## fs.readFile(file[, options], callback)
|
## fs.readFile(file[, options], callback)
|
||||||
|
|
||||||
* `file` {String | Integer} filename or file descriptor
|
* `file` {String | Buffer | Integer} filename or file descriptor
|
||||||
* `options` {Object | String}
|
* `options` {Object | String}
|
||||||
* `encoding` {String | Null} default = `null`
|
* `encoding` {String | Null} default = `null`
|
||||||
* `flag` {String} default = `'r'`
|
* `flag` {String} default = `'r'`
|
||||||
@ -838,7 +883,7 @@ _Note: Specified file descriptors will not be closed automatically._
|
|||||||
|
|
||||||
## fs.readFileSync(file[, options])
|
## fs.readFileSync(file[, options])
|
||||||
|
|
||||||
* `file` {String | Integer} filename or file descriptor
|
* `file` {String | Buffer | Integer} filename or file descriptor
|
||||||
* `options` {Object | String}
|
* `options` {Object | String}
|
||||||
* `encoding` {String | Null} default = `null`
|
* `encoding` {String | Null} default = `null`
|
||||||
* `flag` {String} default = `'r'`
|
* `flag` {String} default = `'r'`
|
||||||
@ -848,7 +893,12 @@ Synchronous version of [`fs.readFile`][]. Returns the contents of the `file`.
|
|||||||
If the `encoding` option is specified then this function returns a
|
If the `encoding` option is specified then this function returns a
|
||||||
string. Otherwise it returns a buffer.
|
string. Otherwise it returns a buffer.
|
||||||
|
|
||||||
## fs.readlink(path, callback)
|
## fs.readlink(path[, options], callback)
|
||||||
|
|
||||||
|
* `path` {String | Buffer}
|
||||||
|
* `options` {String | Object}
|
||||||
|
* `encoding` {String} default = `'utf8'`
|
||||||
|
* `callback` {Function}
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
@ -856,15 +906,29 @@ string. Otherwise it returns a buffer.
|
|||||||
Asynchronous readlink(2). The callback gets two arguments `(err,
|
Asynchronous readlink(2). The callback gets two arguments `(err,
|
||||||
linkString)`.
|
linkString)`.
|
||||||
|
|
||||||
## fs.readlinkSync(path)
|
The optional `options` argument can be a string specifying an encoding, or an
|
||||||
|
object with an `encoding` property specifying the character encoding to use for
|
||||||
|
the link path passed to the callback. If the `encoding` is set to `'buffer'`,
|
||||||
|
the link path returned will be passed as a `Buffer` object.
|
||||||
|
|
||||||
|
## fs.readlinkSync(path[, options])
|
||||||
|
|
||||||
|
* `path` {String | Buffer}
|
||||||
|
* `options` {String | Object}
|
||||||
|
* `encoding` {String} default = `'utf8'`
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String}
|
||||||
|
|
||||||
Synchronous readlink(2). Returns the symbolic link's string value.
|
Synchronous readlink(2). Returns the symbolic link's string value.
|
||||||
|
|
||||||
|
The optional `options` argument can be a string specifying an encoding, or an
|
||||||
|
object with an `encoding` property specifying the character encoding to use for
|
||||||
|
the link path passed to the callback. If the `encoding` is set to `'buffer'`,
|
||||||
|
the link path returned will be passed as a `Buffer` object.
|
||||||
|
|
||||||
## fs.realpath(path[, cache], callback)
|
## fs.realpath(path[, cache], callback)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `cache` {Object}
|
* `cache` {Object}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
|
|
||||||
@ -895,7 +959,7 @@ Synchronous version of [`fs.read()`][]. Returns the number of `bytesRead`.
|
|||||||
|
|
||||||
## fs.realpathSync(path[, cache])
|
## fs.realpathSync(path[, cache])
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer};
|
||||||
* `cache` {Object}
|
* `cache` {Object}
|
||||||
|
|
||||||
Synchronous realpath(2). Returns the resolved path. `cache` is an
|
Synchronous realpath(2). Returns the resolved path. `cache` is an
|
||||||
@ -904,8 +968,8 @@ resolution or avoid additional `fs.stat` calls for known real paths.
|
|||||||
|
|
||||||
## fs.rename(oldPath, newPath, callback)
|
## fs.rename(oldPath, newPath, callback)
|
||||||
|
|
||||||
* `oldPath` {String}
|
* `oldPath` {String | Buffer}
|
||||||
* `newPath` {String}
|
* `newPath` {String | Buffer}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
|
|
||||||
Asynchronous rename(2). No arguments other than a possible exception are given
|
Asynchronous rename(2). No arguments other than a possible exception are given
|
||||||
@ -913,14 +977,14 @@ to the completion callback.
|
|||||||
|
|
||||||
## fs.renameSync(oldPath, newPath)
|
## fs.renameSync(oldPath, newPath)
|
||||||
|
|
||||||
* `oldPath` {String}
|
* `oldPath` {String | Buffer}
|
||||||
* `newPath` {String}
|
* `newPath` {String | Buffer}
|
||||||
|
|
||||||
Synchronous rename(2). Returns `undefined`.
|
Synchronous rename(2). Returns `undefined`.
|
||||||
|
|
||||||
## fs.rmdir(path, callback)
|
## fs.rmdir(path, callback)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
|
|
||||||
Asynchronous rmdir(2). No arguments other than a possible exception are given
|
Asynchronous rmdir(2). No arguments other than a possible exception are given
|
||||||
@ -928,13 +992,13 @@ to the completion callback.
|
|||||||
|
|
||||||
## fs.rmdirSync(path)
|
## fs.rmdirSync(path)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
|
|
||||||
Synchronous rmdir(2). Returns `undefined`.
|
Synchronous rmdir(2). Returns `undefined`.
|
||||||
|
|
||||||
## fs.stat(path, callback)
|
## fs.stat(path, callback)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
|
|
||||||
Asynchronous stat(2). The callback gets two arguments `(err, stats)` where
|
Asynchronous stat(2). The callback gets two arguments `(err, stats)` where
|
||||||
@ -943,14 +1007,14 @@ information.
|
|||||||
|
|
||||||
## fs.statSync(path)
|
## fs.statSync(path)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
|
|
||||||
Synchronous stat(2). Returns an instance of [`fs.Stats`][].
|
Synchronous stat(2). Returns an instance of [`fs.Stats`][].
|
||||||
|
|
||||||
## fs.symlink(target, path[, type], callback)
|
## fs.symlink(target, path[, type], callback)
|
||||||
|
|
||||||
* `target` {String}
|
* `target` {String | Buffer}
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `type` {String}
|
* `type` {String}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
|
|
||||||
@ -971,15 +1035,15 @@ It creates a symbolic link named "new-port" that points to "foo".
|
|||||||
|
|
||||||
## fs.symlinkSync(target, path[, type])
|
## fs.symlinkSync(target, path[, type])
|
||||||
|
|
||||||
* `target` {String}
|
* `target` {String | Buffer}
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `type` {String}
|
* `type` {String}
|
||||||
|
|
||||||
Synchronous symlink(2). Returns `undefined`.
|
Synchronous symlink(2). Returns `undefined`.
|
||||||
|
|
||||||
## fs.truncate(path, len, callback)
|
## fs.truncate(path, len, callback)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `len` {Integer}
|
* `len` {Integer}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
|
|
||||||
@ -989,14 +1053,14 @@ first argument. In this case, `fs.ftruncate()` is called.
|
|||||||
|
|
||||||
## fs.truncateSync(path, len)
|
## fs.truncateSync(path, len)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `len` {Integer}
|
* `len` {Integer}
|
||||||
|
|
||||||
Synchronous truncate(2). Returns `undefined`.
|
Synchronous truncate(2). Returns `undefined`.
|
||||||
|
|
||||||
## fs.unlink(path, callback)
|
## fs.unlink(path, callback)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
|
|
||||||
Asynchronous unlink(2). No arguments other than a possible exception are given
|
Asynchronous unlink(2). No arguments other than a possible exception are given
|
||||||
@ -1004,13 +1068,13 @@ to the completion callback.
|
|||||||
|
|
||||||
## fs.unlinkSync(path)
|
## fs.unlinkSync(path)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
|
|
||||||
Synchronous unlink(2). Returns `undefined`.
|
Synchronous unlink(2). Returns `undefined`.
|
||||||
|
|
||||||
## fs.unwatchFile(filename[, listener])
|
## fs.unwatchFile(filename[, listener])
|
||||||
|
|
||||||
* `filename` {String}
|
* `filename` {String | Buffer}
|
||||||
* `listener` {Function}
|
* `listener` {Function}
|
||||||
|
|
||||||
Stop watching for changes on `filename`. If `listener` is specified, only that
|
Stop watching for changes on `filename`. If `listener` is specified, only that
|
||||||
@ -1026,7 +1090,7 @@ when possible._
|
|||||||
|
|
||||||
## fs.utimes(path, atime, mtime, callback)
|
## fs.utimes(path, atime, mtime, callback)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `atime` {Integer}
|
* `atime` {Integer}
|
||||||
* `mtime` {Integer}
|
* `mtime` {Integer}
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
@ -1043,7 +1107,7 @@ follow the below rules:
|
|||||||
|
|
||||||
## fs.utimesSync(path, atime, mtime)
|
## fs.utimesSync(path, atime, mtime)
|
||||||
|
|
||||||
* `path` {String}
|
* `path` {String | Buffer}
|
||||||
* `atime` {Integer}
|
* `atime` {Integer}
|
||||||
* `mtime` {Integer}
|
* `mtime` {Integer}
|
||||||
|
|
||||||
@ -1051,19 +1115,24 @@ Synchronous version of [`fs.utimes()`][]. Returns `undefined`.
|
|||||||
|
|
||||||
## fs.watch(filename[, options][, listener])
|
## fs.watch(filename[, options][, listener])
|
||||||
|
|
||||||
* `filename` {String}
|
* `filename` {String | Buffer}
|
||||||
* `options` {Object}
|
* `options` {String | Object}
|
||||||
* `persistent` {Boolean} Indicates whether the process should continue to run
|
* `persistent` {Boolean} Indicates whether the process should continue to run
|
||||||
as long as files are being watched. default = `true`
|
as long as files are being watched. default = `true`
|
||||||
* `recursive` {Boolean} Indicates whether all subdirectories should be
|
* `recursive` {Boolean} Indicates whether all subdirectories should be
|
||||||
watched, or only the current directory. The applies when a directory is
|
watched, or only the current directory. The applies when a directory is
|
||||||
specified, and only on supported platforms (See [Caveats][]). default =
|
specified, and only on supported platforms (See [Caveats][]). default =
|
||||||
`false`
|
`false`
|
||||||
|
* `encoding` {String} Specifies the character encoding to be used for the
|
||||||
|
filename passed to the listener. default = `'utf8'`
|
||||||
* `listener` {Function}
|
* `listener` {Function}
|
||||||
|
|
||||||
Watch for changes on `filename`, where `filename` is either a file or a
|
Watch for changes on `filename`, where `filename` is either a file or a
|
||||||
directory. The returned object is a [`fs.FSWatcher`][].
|
directory. The returned object is a [`fs.FSWatcher`][].
|
||||||
|
|
||||||
|
The second argument is optional. If `options` is provided as a string, it
|
||||||
|
specifies the `encoding`. Otherwise `options` should be passed as an object.
|
||||||
|
|
||||||
The listener callback gets two arguments `(event, filename)`. `event` is either
|
The listener callback gets two arguments `(event, filename)`. `event` is either
|
||||||
`'rename'` or `'change'`, and `filename` is the name of the file which triggered
|
`'rename'` or `'change'`, and `filename` is the name of the file which triggered
|
||||||
the event.
|
the event.
|
||||||
@ -1120,7 +1189,7 @@ fs.watch('somedir', (event, filename) => {
|
|||||||
|
|
||||||
## fs.watchFile(filename[, options], listener)
|
## fs.watchFile(filename[, options], listener)
|
||||||
|
|
||||||
* `filename` {String}
|
* `filename` {String | Buffer}
|
||||||
* `options` {Object}
|
* `options` {Object}
|
||||||
* `persistent` {Boolean}
|
* `persistent` {Boolean}
|
||||||
* `interval` {Integer}
|
* `interval` {Integer}
|
||||||
@ -1224,7 +1293,7 @@ the end of the file.
|
|||||||
|
|
||||||
## fs.writeFile(file, data[, options], callback)
|
## fs.writeFile(file, data[, options], callback)
|
||||||
|
|
||||||
* `file` {String | Integer} filename or file descriptor
|
* `file` {String | Buffer | Integer} filename or file descriptor
|
||||||
* `data` {String | Buffer}
|
* `data` {String | Buffer}
|
||||||
* `options` {Object | String}
|
* `options` {Object | String}
|
||||||
* `encoding` {String | Null} default = `'utf8'`
|
* `encoding` {String | Null} default = `'utf8'`
|
||||||
@ -1263,7 +1332,7 @@ _Note: Specified file descriptors will not be closed automatically._
|
|||||||
|
|
||||||
## fs.writeFileSync(file, data[, options])
|
## fs.writeFileSync(file, data[, options])
|
||||||
|
|
||||||
* `file` {String | Integer} filename or file descriptor
|
* `file` {String | Buffer | Integer} filename or file descriptor
|
||||||
* `data` {String | Buffer}
|
* `data` {String | Buffer}
|
||||||
* `options` {Object | String}
|
* `options` {Object | String}
|
||||||
* `encoding` {String | Null} default = `'utf8'`
|
* `encoding` {String | Null} default = `'utf8'`
|
||||||
|
106
lib/fs.js
106
lib/fs.js
@ -903,17 +903,32 @@ fs.mkdirSync = function(path, mode) {
|
|||||||
modeNum(mode, 0o777));
|
modeNum(mode, 0o777));
|
||||||
};
|
};
|
||||||
|
|
||||||
fs.readdir = function(path, callback) {
|
fs.readdir = function(path, options, callback) {
|
||||||
|
options = options || {};
|
||||||
|
if (typeof options === 'function') {
|
||||||
|
callback = options;
|
||||||
|
options = {};
|
||||||
|
} else if (typeof options === 'string') {
|
||||||
|
options = {encoding: options};
|
||||||
|
}
|
||||||
|
if (typeof options !== 'object')
|
||||||
|
throw new TypeError('"options" must be a string or an object');
|
||||||
|
|
||||||
callback = makeCallback(callback);
|
callback = makeCallback(callback);
|
||||||
if (!nullCheck(path, callback)) return;
|
if (!nullCheck(path, callback)) return;
|
||||||
var req = new FSReqWrap();
|
var req = new FSReqWrap();
|
||||||
req.oncomplete = callback;
|
req.oncomplete = callback;
|
||||||
binding.readdir(pathModule._makeLong(path), req);
|
binding.readdir(pathModule._makeLong(path), options.encoding, req);
|
||||||
};
|
};
|
||||||
|
|
||||||
fs.readdirSync = function(path) {
|
fs.readdirSync = function(path, options) {
|
||||||
|
options = options || {};
|
||||||
|
if (typeof options === 'string')
|
||||||
|
options = {encoding: options};
|
||||||
|
if (typeof options !== 'object')
|
||||||
|
throw new TypeError('"options" must be a string or an object');
|
||||||
nullCheck(path);
|
nullCheck(path);
|
||||||
return binding.readdir(pathModule._makeLong(path));
|
return binding.readdir(pathModule._makeLong(path), options.encoding);
|
||||||
};
|
};
|
||||||
|
|
||||||
fs.fstat = function(fd, callback) {
|
fs.fstat = function(fd, callback) {
|
||||||
@ -952,17 +967,31 @@ fs.statSync = function(path) {
|
|||||||
return binding.stat(pathModule._makeLong(path));
|
return binding.stat(pathModule._makeLong(path));
|
||||||
};
|
};
|
||||||
|
|
||||||
fs.readlink = function(path, callback) {
|
fs.readlink = function(path, options, callback) {
|
||||||
|
options = options || {};
|
||||||
|
if (typeof options === 'function') {
|
||||||
|
callback = options;
|
||||||
|
options = {};
|
||||||
|
} else if (typeof options === 'string') {
|
||||||
|
options = {encoding: options};
|
||||||
|
}
|
||||||
|
if (typeof options !== 'object')
|
||||||
|
throw new TypeError('"options" must be a string or an object');
|
||||||
callback = makeCallback(callback);
|
callback = makeCallback(callback);
|
||||||
if (!nullCheck(path, callback)) return;
|
if (!nullCheck(path, callback)) return;
|
||||||
var req = new FSReqWrap();
|
var req = new FSReqWrap();
|
||||||
req.oncomplete = callback;
|
req.oncomplete = callback;
|
||||||
binding.readlink(pathModule._makeLong(path), req);
|
binding.readlink(pathModule._makeLong(path), options.encoding, req);
|
||||||
};
|
};
|
||||||
|
|
||||||
fs.readlinkSync = function(path) {
|
fs.readlinkSync = function(path, options) {
|
||||||
|
options = options || {};
|
||||||
|
if (typeof options === 'string')
|
||||||
|
options = {encoding: options};
|
||||||
|
if (typeof options !== 'object')
|
||||||
|
throw new TypeError('"options" must be a string or an object');
|
||||||
nullCheck(path);
|
nullCheck(path);
|
||||||
return binding.readlink(pathModule._makeLong(path));
|
return binding.readlink(pathModule._makeLong(path), options.encoding);
|
||||||
};
|
};
|
||||||
|
|
||||||
function preprocessSymlinkDestination(path, type, linkPath) {
|
function preprocessSymlinkDestination(path, type, linkPath) {
|
||||||
@ -1363,11 +1392,15 @@ function FSWatcher() {
|
|||||||
}
|
}
|
||||||
util.inherits(FSWatcher, EventEmitter);
|
util.inherits(FSWatcher, EventEmitter);
|
||||||
|
|
||||||
FSWatcher.prototype.start = function(filename, persistent, recursive) {
|
FSWatcher.prototype.start = function(filename,
|
||||||
|
persistent,
|
||||||
|
recursive,
|
||||||
|
encoding) {
|
||||||
nullCheck(filename);
|
nullCheck(filename);
|
||||||
var err = this._handle.start(pathModule._makeLong(filename),
|
var err = this._handle.start(pathModule._makeLong(filename),
|
||||||
persistent,
|
persistent,
|
||||||
recursive);
|
recursive,
|
||||||
|
encoding);
|
||||||
if (err) {
|
if (err) {
|
||||||
this._handle.close();
|
this._handle.close();
|
||||||
const error = errnoException(err, `watch ${filename}`);
|
const error = errnoException(err, `watch ${filename}`);
|
||||||
@ -1380,25 +1413,27 @@ FSWatcher.prototype.close = function() {
|
|||||||
this._handle.close();
|
this._handle.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
fs.watch = function(filename) {
|
fs.watch = function(filename, options, listener) {
|
||||||
nullCheck(filename);
|
nullCheck(filename);
|
||||||
var watcher;
|
|
||||||
var options;
|
|
||||||
var listener;
|
|
||||||
|
|
||||||
if (arguments[1] !== null && typeof arguments[1] === 'object') {
|
options = options || {};
|
||||||
options = arguments[1];
|
if (typeof options === 'function') {
|
||||||
listener = arguments[2];
|
listener = options;
|
||||||
} else {
|
|
||||||
options = {};
|
options = {};
|
||||||
listener = arguments[1];
|
} else if (typeof options === 'string') {
|
||||||
|
options = {encoding: options};
|
||||||
}
|
}
|
||||||
|
if (typeof options !== 'object')
|
||||||
|
throw new TypeError('"options" must be a string or an object');
|
||||||
|
|
||||||
if (options.persistent === undefined) options.persistent = true;
|
if (options.persistent === undefined) options.persistent = true;
|
||||||
if (options.recursive === undefined) options.recursive = false;
|
if (options.recursive === undefined) options.recursive = false;
|
||||||
|
|
||||||
watcher = new FSWatcher();
|
const watcher = new FSWatcher();
|
||||||
watcher.start(filename, options.persistent, options.recursive);
|
watcher.start(filename,
|
||||||
|
options.persistent,
|
||||||
|
options.recursive,
|
||||||
|
options.encoding);
|
||||||
|
|
||||||
if (listener) {
|
if (listener) {
|
||||||
watcher.addListener('change', listener);
|
watcher.addListener('change', listener);
|
||||||
@ -2139,10 +2174,19 @@ SyncWriteStream.prototype.destroy = function() {
|
|||||||
|
|
||||||
SyncWriteStream.prototype.destroySoon = SyncWriteStream.prototype.destroy;
|
SyncWriteStream.prototype.destroySoon = SyncWriteStream.prototype.destroy;
|
||||||
|
|
||||||
fs.mkdtemp = function(prefix, callback) {
|
fs.mkdtemp = function(prefix, options, callback) {
|
||||||
if (typeof callback !== 'function') {
|
if (!prefix || typeof prefix !== 'string')
|
||||||
throw new TypeError('"callback" argument must be a function');
|
throw new TypeError('filename prefix is required');
|
||||||
|
|
||||||
|
options = options || {};
|
||||||
|
if (typeof options === 'function') {
|
||||||
|
callback = options;
|
||||||
|
options = {};
|
||||||
|
} else if (typeof options === 'string') {
|
||||||
|
options = {encoding: options};
|
||||||
}
|
}
|
||||||
|
if (typeof options !== 'object')
|
||||||
|
throw new TypeError('"options" must be a string or an object');
|
||||||
|
|
||||||
if (!nullCheck(prefix, callback)) {
|
if (!nullCheck(prefix, callback)) {
|
||||||
return;
|
return;
|
||||||
@ -2151,11 +2195,19 @@ fs.mkdtemp = function(prefix, callback) {
|
|||||||
var req = new FSReqWrap();
|
var req = new FSReqWrap();
|
||||||
req.oncomplete = callback;
|
req.oncomplete = callback;
|
||||||
|
|
||||||
binding.mkdtemp(prefix + 'XXXXXX', req);
|
binding.mkdtemp(prefix + 'XXXXXX', options.encoding, req);
|
||||||
};
|
};
|
||||||
|
|
||||||
fs.mkdtempSync = function(prefix) {
|
fs.mkdtempSync = function(prefix, options) {
|
||||||
|
if (!prefix || typeof prefix !== 'string')
|
||||||
|
throw new TypeError('filename prefix is required');
|
||||||
|
|
||||||
|
options = options || {};
|
||||||
|
if (typeof options === 'string')
|
||||||
|
options = {encoding: options};
|
||||||
|
if (typeof options !== 'object')
|
||||||
|
throw new TypeError('"options" must be a string or an object');
|
||||||
nullCheck(prefix);
|
nullCheck(prefix);
|
||||||
|
|
||||||
return binding.mkdtemp(prefix + 'XXXXXX');
|
return binding.mkdtemp(prefix + 'XXXXXX', options.encoding);
|
||||||
};
|
};
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "util-inl.h"
|
#include "util-inl.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "handle_wrap.h"
|
#include "handle_wrap.h"
|
||||||
|
#include "string_bytes.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
@ -41,6 +42,7 @@ class FSEventWrap: public HandleWrap {
|
|||||||
|
|
||||||
uv_fs_event_t handle_;
|
uv_fs_event_t handle_;
|
||||||
bool initialized_;
|
bool initialized_;
|
||||||
|
enum encoding encoding_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -86,16 +88,20 @@ void FSEventWrap::Start(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
FSEventWrap* wrap = Unwrap<FSEventWrap>(args.Holder());
|
FSEventWrap* wrap = Unwrap<FSEventWrap>(args.Holder());
|
||||||
|
|
||||||
if (args.Length() < 1 || !args[0]->IsString()) {
|
static const char kErrMsg[] = "filename must be a string or Buffer";
|
||||||
return env->ThrowTypeError("filename must be a valid string");
|
if (args.Length() < 1)
|
||||||
}
|
return env->ThrowTypeError(kErrMsg);
|
||||||
|
|
||||||
node::Utf8Value path(env->isolate(), args[0]);
|
BufferValue path(env->isolate(), args[0]);
|
||||||
|
if (*path == nullptr)
|
||||||
|
return env->ThrowTypeError(kErrMsg);
|
||||||
|
|
||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
if (args[2]->IsTrue())
|
if (args[2]->IsTrue())
|
||||||
flags |= UV_FS_EVENT_RECURSIVE;
|
flags |= UV_FS_EVENT_RECURSIVE;
|
||||||
|
|
||||||
|
wrap->encoding_ = ParseEncoding(env->isolate(), args[3], UTF8);
|
||||||
|
|
||||||
int err = uv_fs_event_init(wrap->env()->event_loop(), &wrap->handle_);
|
int err = uv_fs_event_init(wrap->env()->event_loop(), &wrap->handle_);
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
wrap->initialized_ = true;
|
wrap->initialized_ = true;
|
||||||
@ -156,7 +162,18 @@ void FSEventWrap::OnEvent(uv_fs_event_t* handle, const char* filename,
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (filename != nullptr) {
|
if (filename != nullptr) {
|
||||||
argv[2] = OneByteString(env->isolate(), filename);
|
Local<Value> fn = StringBytes::Encode(env->isolate(),
|
||||||
|
filename,
|
||||||
|
wrap->encoding_);
|
||||||
|
if (fn.IsEmpty()) {
|
||||||
|
argv[0] = Integer::New(env->isolate(), UV_EINVAL);
|
||||||
|
argv[2] = StringBytes::Encode(env->isolate(),
|
||||||
|
filename,
|
||||||
|
strlen(filename),
|
||||||
|
BUFFER);
|
||||||
|
} else {
|
||||||
|
argv[2] = fn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wrap->MakeCallback(env->onchange_string(), ARRAY_SIZE(argv), argv);
|
wrap->MakeCallback(env->onchange_string(), ARRAY_SIZE(argv), argv);
|
||||||
|
295
src/node_file.cc
295
src/node_file.cc
@ -34,6 +34,7 @@ using v8::FunctionCallbackInfo;
|
|||||||
using v8::FunctionTemplate;
|
using v8::FunctionTemplate;
|
||||||
using v8::HandleScope;
|
using v8::HandleScope;
|
||||||
using v8::Integer;
|
using v8::Integer;
|
||||||
|
using v8::Isolate;
|
||||||
using v8::Local;
|
using v8::Local;
|
||||||
using v8::Number;
|
using v8::Number;
|
||||||
using v8::Object;
|
using v8::Object;
|
||||||
@ -56,6 +57,7 @@ class FSReqWrap: public ReqWrap<uv_fs_t> {
|
|||||||
Local<Object> req,
|
Local<Object> req,
|
||||||
const char* syscall,
|
const char* syscall,
|
||||||
const char* data = nullptr,
|
const char* data = nullptr,
|
||||||
|
enum encoding encoding = UTF8,
|
||||||
Ownership ownership = COPY);
|
Ownership ownership = COPY);
|
||||||
|
|
||||||
inline void Dispose();
|
inline void Dispose();
|
||||||
@ -69,6 +71,7 @@ class FSReqWrap: public ReqWrap<uv_fs_t> {
|
|||||||
|
|
||||||
const char* syscall() const { return syscall_; }
|
const char* syscall() const { return syscall_; }
|
||||||
const char* data() const { return data_; }
|
const char* data() const { return data_; }
|
||||||
|
const enum encoding encoding_;
|
||||||
|
|
||||||
size_t self_size() const override { return sizeof(*this); }
|
size_t self_size() const override { return sizeof(*this); }
|
||||||
|
|
||||||
@ -76,8 +79,10 @@ class FSReqWrap: public ReqWrap<uv_fs_t> {
|
|||||||
FSReqWrap(Environment* env,
|
FSReqWrap(Environment* env,
|
||||||
Local<Object> req,
|
Local<Object> req,
|
||||||
const char* syscall,
|
const char* syscall,
|
||||||
const char* data)
|
const char* data,
|
||||||
|
enum encoding encoding)
|
||||||
: ReqWrap(env, req, AsyncWrap::PROVIDER_FSREQWRAP),
|
: ReqWrap(env, req, AsyncWrap::PROVIDER_FSREQWRAP),
|
||||||
|
encoding_(encoding),
|
||||||
syscall_(syscall),
|
syscall_(syscall),
|
||||||
data_(data) {
|
data_(data) {
|
||||||
Wrap(object(), this);
|
Wrap(object(), this);
|
||||||
@ -95,17 +100,21 @@ class FSReqWrap: public ReqWrap<uv_fs_t> {
|
|||||||
DISALLOW_COPY_AND_ASSIGN(FSReqWrap);
|
DISALLOW_COPY_AND_ASSIGN(FSReqWrap);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ASSERT_PATH(path) \
|
||||||
|
if (*path == nullptr) \
|
||||||
|
return TYPE_ERROR( #path " must be a string or Buffer");
|
||||||
|
|
||||||
FSReqWrap* FSReqWrap::New(Environment* env,
|
FSReqWrap* FSReqWrap::New(Environment* env,
|
||||||
Local<Object> req,
|
Local<Object> req,
|
||||||
const char* syscall,
|
const char* syscall,
|
||||||
const char* data,
|
const char* data,
|
||||||
|
enum encoding encoding,
|
||||||
Ownership ownership) {
|
Ownership ownership) {
|
||||||
const bool copy = (data != nullptr && ownership == COPY);
|
const bool copy = (data != nullptr && ownership == COPY);
|
||||||
const size_t size = copy ? 1 + strlen(data) : 0;
|
const size_t size = copy ? 1 + strlen(data) : 0;
|
||||||
FSReqWrap* that;
|
FSReqWrap* that;
|
||||||
char* const storage = new char[sizeof(*that) + size];
|
char* const storage = new char[sizeof(*that) + size];
|
||||||
that = new(storage) FSReqWrap(env, req, syscall, data);
|
that = new(storage) FSReqWrap(env, req, syscall, data, encoding);
|
||||||
if (copy)
|
if (copy)
|
||||||
that->data_ = static_cast<char*>(memcpy(that->inline_data(), data, size));
|
that->data_ = static_cast<char*>(memcpy(that->inline_data(), data, size));
|
||||||
return that;
|
return that;
|
||||||
@ -127,7 +136,6 @@ static inline bool IsInt64(double x) {
|
|||||||
return x == static_cast<double>(static_cast<int64_t>(x));
|
return x == static_cast<double>(static_cast<int64_t>(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void After(uv_fs_t *req) {
|
static void After(uv_fs_t *req) {
|
||||||
FSReqWrap* req_wrap = static_cast<FSReqWrap*>(req->data);
|
FSReqWrap* req_wrap = static_cast<FSReqWrap*>(req->data);
|
||||||
CHECK_EQ(&req_wrap->req_, req);
|
CHECK_EQ(&req_wrap->req_, req);
|
||||||
@ -143,6 +151,7 @@ static void After(uv_fs_t *req) {
|
|||||||
// Allocate space for two args. We may only use one depending on the case.
|
// Allocate space for two args. We may only use one depending on the case.
|
||||||
// (Feel free to increase this if you need more)
|
// (Feel free to increase this if you need more)
|
||||||
Local<Value> argv[2];
|
Local<Value> argv[2];
|
||||||
|
Local<Value> link;
|
||||||
|
|
||||||
if (req->result < 0) {
|
if (req->result < 0) {
|
||||||
// An error happened.
|
// An error happened.
|
||||||
@ -201,13 +210,35 @@ static void After(uv_fs_t *req) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case UV_FS_MKDTEMP:
|
case UV_FS_MKDTEMP:
|
||||||
argv[1] = String::NewFromUtf8(env->isolate(),
|
link = StringBytes::Encode(env->isolate(),
|
||||||
static_cast<const char*>(req->path));
|
static_cast<const char*>(req->path),
|
||||||
|
req_wrap->encoding_);
|
||||||
|
if (link.IsEmpty()) {
|
||||||
|
argv[0] = UVException(env->isolate(),
|
||||||
|
UV_EINVAL,
|
||||||
|
req_wrap->syscall(),
|
||||||
|
"Invalid character encoding for filename",
|
||||||
|
req->path,
|
||||||
|
req_wrap->data());
|
||||||
|
} else {
|
||||||
|
argv[1] = link;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UV_FS_READLINK:
|
case UV_FS_READLINK:
|
||||||
argv[1] = String::NewFromUtf8(env->isolate(),
|
link = StringBytes::Encode(env->isolate(),
|
||||||
static_cast<const char*>(req->ptr));
|
static_cast<const char*>(req->ptr),
|
||||||
|
req_wrap->encoding_);
|
||||||
|
if (link.IsEmpty()) {
|
||||||
|
argv[0] = UVException(env->isolate(),
|
||||||
|
UV_EINVAL,
|
||||||
|
req_wrap->syscall(),
|
||||||
|
"Invalid character encoding for link",
|
||||||
|
req->path,
|
||||||
|
req_wrap->data());
|
||||||
|
} else {
|
||||||
|
argv[1] = link;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UV_FS_READ:
|
case UV_FS_READ:
|
||||||
@ -237,8 +268,19 @@ static void After(uv_fs_t *req) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
name_argv[name_idx++] =
|
Local<Value> filename = StringBytes::Encode(env->isolate(),
|
||||||
String::NewFromUtf8(env->isolate(), ent.name);
|
ent.name,
|
||||||
|
req_wrap->encoding_);
|
||||||
|
if (filename.IsEmpty()) {
|
||||||
|
argv[0] = UVException(env->isolate(),
|
||||||
|
UV_EINVAL,
|
||||||
|
req_wrap->syscall(),
|
||||||
|
"Invalid character encoding for filename",
|
||||||
|
req->path,
|
||||||
|
req_wrap->data());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
name_argv[name_idx++] = filename;
|
||||||
|
|
||||||
if (name_idx >= ARRAY_SIZE(name_argv)) {
|
if (name_idx >= ARRAY_SIZE(name_argv)) {
|
||||||
fn->Call(env->context(), names, name_idx, name_argv)
|
fn->Call(env->context(), names, name_idx, name_argv)
|
||||||
@ -277,10 +319,11 @@ struct fs_req_wrap {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define ASYNC_DEST_CALL(func, req, dest, ...) \
|
#define ASYNC_DEST_CALL(func, req, dest, encoding, ...) \
|
||||||
Environment* env = Environment::GetCurrent(args); \
|
Environment* env = Environment::GetCurrent(args); \
|
||||||
CHECK(req->IsObject()); \
|
CHECK(req->IsObject()); \
|
||||||
FSReqWrap* req_wrap = FSReqWrap::New(env, req.As<Object>(), #func, dest); \
|
FSReqWrap* req_wrap = FSReqWrap::New(env, req.As<Object>(), \
|
||||||
|
#func, dest, encoding); \
|
||||||
int err = uv_fs_ ## func(env->event_loop(), \
|
int err = uv_fs_ ## func(env->event_loop(), \
|
||||||
&req_wrap->req_, \
|
&req_wrap->req_, \
|
||||||
__VA_ARGS__, \
|
__VA_ARGS__, \
|
||||||
@ -296,8 +339,8 @@ struct fs_req_wrap {
|
|||||||
args.GetReturnValue().Set(req_wrap->persistent()); \
|
args.GetReturnValue().Set(req_wrap->persistent()); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ASYNC_CALL(func, req, ...) \
|
#define ASYNC_CALL(func, req, encoding, ...) \
|
||||||
ASYNC_DEST_CALL(func, req, nullptr, __VA_ARGS__) \
|
ASYNC_DEST_CALL(func, req, nullptr, encoding, __VA_ARGS__) \
|
||||||
|
|
||||||
#define SYNC_DEST_CALL(func, path, dest, ...) \
|
#define SYNC_DEST_CALL(func, path, dest, ...) \
|
||||||
fs_req_wrap req_wrap; \
|
fs_req_wrap req_wrap; \
|
||||||
@ -317,23 +360,22 @@ struct fs_req_wrap {
|
|||||||
|
|
||||||
#define SYNC_RESULT err
|
#define SYNC_RESULT err
|
||||||
|
|
||||||
|
|
||||||
static void Access(const FunctionCallbackInfo<Value>& args) {
|
static void Access(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args.GetIsolate());
|
Environment* env = Environment::GetCurrent(args.GetIsolate());
|
||||||
HandleScope scope(env->isolate());
|
HandleScope scope(env->isolate());
|
||||||
|
|
||||||
if (args.Length() < 2)
|
if (args.Length() < 2)
|
||||||
return TYPE_ERROR("path and mode are required");
|
return TYPE_ERROR("path and mode are required");
|
||||||
if (!args[0]->IsString())
|
|
||||||
return TYPE_ERROR("path must be a string");
|
|
||||||
if (!args[1]->IsInt32())
|
if (!args[1]->IsInt32())
|
||||||
return TYPE_ERROR("mode must be an integer");
|
return TYPE_ERROR("mode must be an integer");
|
||||||
|
|
||||||
node::Utf8Value path(env->isolate(), args[0]);
|
BufferValue path(env->isolate(), args[0]);
|
||||||
|
ASSERT_PATH(path)
|
||||||
|
|
||||||
int mode = static_cast<int>(args[1]->Int32Value());
|
int mode = static_cast<int>(args[1]->Int32Value());
|
||||||
|
|
||||||
if (args[2]->IsObject()) {
|
if (args[2]->IsObject()) {
|
||||||
ASYNC_CALL(access, args[2], *path, mode);
|
ASYNC_CALL(access, args[2], UTF8, *path, mode);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(access, *path, *path, mode);
|
SYNC_CALL(access, *path, *path, mode);
|
||||||
}
|
}
|
||||||
@ -351,7 +393,7 @@ static void Close(const FunctionCallbackInfo<Value>& args) {
|
|||||||
int fd = args[0]->Int32Value();
|
int fd = args[0]->Int32Value();
|
||||||
|
|
||||||
if (args[1]->IsObject()) {
|
if (args[1]->IsObject()) {
|
||||||
ASYNC_CALL(close, args[1], fd)
|
ASYNC_CALL(close, args[1], UTF8, fd)
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(close, 0, fd)
|
SYNC_CALL(close, 0, fd)
|
||||||
}
|
}
|
||||||
@ -544,13 +586,12 @@ static void Stat(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
if (args.Length() < 1)
|
if (args.Length() < 1)
|
||||||
return TYPE_ERROR("path required");
|
return TYPE_ERROR("path required");
|
||||||
if (!args[0]->IsString())
|
|
||||||
return TYPE_ERROR("path must be a string");
|
|
||||||
|
|
||||||
node::Utf8Value path(env->isolate(), args[0]);
|
BufferValue path(env->isolate(), args[0]);
|
||||||
|
ASSERT_PATH(path)
|
||||||
|
|
||||||
if (args[1]->IsObject()) {
|
if (args[1]->IsObject()) {
|
||||||
ASYNC_CALL(stat, args[1], *path)
|
ASYNC_CALL(stat, args[1], UTF8, *path)
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(stat, *path, *path)
|
SYNC_CALL(stat, *path, *path)
|
||||||
args.GetReturnValue().Set(
|
args.GetReturnValue().Set(
|
||||||
@ -563,13 +604,12 @@ static void LStat(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
if (args.Length() < 1)
|
if (args.Length() < 1)
|
||||||
return TYPE_ERROR("path required");
|
return TYPE_ERROR("path required");
|
||||||
if (!args[0]->IsString())
|
|
||||||
return TYPE_ERROR("path must be a string");
|
|
||||||
|
|
||||||
node::Utf8Value path(env->isolate(), args[0]);
|
BufferValue path(env->isolate(), args[0]);
|
||||||
|
ASSERT_PATH(path)
|
||||||
|
|
||||||
if (args[1]->IsObject()) {
|
if (args[1]->IsObject()) {
|
||||||
ASYNC_CALL(lstat, args[1], *path)
|
ASYNC_CALL(lstat, args[1], UTF8, *path)
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(lstat, *path, *path)
|
SYNC_CALL(lstat, *path, *path)
|
||||||
args.GetReturnValue().Set(
|
args.GetReturnValue().Set(
|
||||||
@ -588,7 +628,7 @@ static void FStat(const FunctionCallbackInfo<Value>& args) {
|
|||||||
int fd = args[0]->Int32Value();
|
int fd = args[0]->Int32Value();
|
||||||
|
|
||||||
if (args[1]->IsObject()) {
|
if (args[1]->IsObject()) {
|
||||||
ASYNC_CALL(fstat, args[1], fd)
|
ASYNC_CALL(fstat, args[1], UTF8, fd)
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(fstat, 0, fd)
|
SYNC_CALL(fstat, 0, fd)
|
||||||
args.GetReturnValue().Set(
|
args.GetReturnValue().Set(
|
||||||
@ -604,13 +644,12 @@ static void Symlink(const FunctionCallbackInfo<Value>& args) {
|
|||||||
return TYPE_ERROR("target path required");
|
return TYPE_ERROR("target path required");
|
||||||
if (len < 2)
|
if (len < 2)
|
||||||
return TYPE_ERROR("src path required");
|
return TYPE_ERROR("src path required");
|
||||||
if (!args[0]->IsString())
|
|
||||||
return TYPE_ERROR("target path must be a string");
|
|
||||||
if (!args[1]->IsString())
|
|
||||||
return TYPE_ERROR("src path must be a string");
|
|
||||||
|
|
||||||
node::Utf8Value target(env->isolate(), args[0]);
|
BufferValue target(env->isolate(), args[0]);
|
||||||
node::Utf8Value path(env->isolate(), args[1]);
|
ASSERT_PATH(target)
|
||||||
|
BufferValue path(env->isolate(), args[1]);
|
||||||
|
ASSERT_PATH(path)
|
||||||
|
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
|
||||||
if (args[2]->IsString()) {
|
if (args[2]->IsString()) {
|
||||||
@ -625,7 +664,7 @@ static void Symlink(const FunctionCallbackInfo<Value>& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (args[3]->IsObject()) {
|
if (args[3]->IsObject()) {
|
||||||
ASYNC_DEST_CALL(symlink, args[3], *path, *target, *path, flags)
|
ASYNC_DEST_CALL(symlink, args[3], *path, UTF8, *target, *path, flags)
|
||||||
} else {
|
} else {
|
||||||
SYNC_DEST_CALL(symlink, *target, *path, *target, *path, flags)
|
SYNC_DEST_CALL(symlink, *target, *path, *target, *path, flags)
|
||||||
}
|
}
|
||||||
@ -639,37 +678,51 @@ static void Link(const FunctionCallbackInfo<Value>& args) {
|
|||||||
return TYPE_ERROR("src path required");
|
return TYPE_ERROR("src path required");
|
||||||
if (len < 2)
|
if (len < 2)
|
||||||
return TYPE_ERROR("dest path required");
|
return TYPE_ERROR("dest path required");
|
||||||
if (!args[0]->IsString())
|
|
||||||
return TYPE_ERROR("src path must be a string");
|
|
||||||
if (!args[1]->IsString())
|
|
||||||
return TYPE_ERROR("dest path must be a string");
|
|
||||||
|
|
||||||
node::Utf8Value orig_path(env->isolate(), args[0]);
|
BufferValue src(env->isolate(), args[0]);
|
||||||
node::Utf8Value new_path(env->isolate(), args[1]);
|
ASSERT_PATH(src)
|
||||||
|
|
||||||
|
BufferValue dest(env->isolate(), args[1]);
|
||||||
|
ASSERT_PATH(dest)
|
||||||
|
|
||||||
if (args[2]->IsObject()) {
|
if (args[2]->IsObject()) {
|
||||||
ASYNC_DEST_CALL(link, args[2], *new_path, *orig_path, *new_path)
|
ASYNC_DEST_CALL(link, args[2], *dest, UTF8, *src, *dest)
|
||||||
} else {
|
} else {
|
||||||
SYNC_DEST_CALL(link, *orig_path, *new_path, *orig_path, *new_path)
|
SYNC_DEST_CALL(link, *src, *dest, *src, *dest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ReadLink(const FunctionCallbackInfo<Value>& args) {
|
static void ReadLink(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
|
||||||
if (args.Length() < 1)
|
const int argc = args.Length();
|
||||||
|
|
||||||
|
if (argc < 1)
|
||||||
return TYPE_ERROR("path required");
|
return TYPE_ERROR("path required");
|
||||||
if (!args[0]->IsString())
|
|
||||||
return TYPE_ERROR("path must be a string");
|
|
||||||
|
|
||||||
node::Utf8Value path(env->isolate(), args[0]);
|
BufferValue path(env->isolate(), args[0]);
|
||||||
|
ASSERT_PATH(path)
|
||||||
|
|
||||||
if (args[1]->IsObject()) {
|
const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
|
||||||
ASYNC_CALL(readlink, args[1], *path)
|
|
||||||
|
Local<Value> callback = Null(env->isolate());
|
||||||
|
if (argc == 3)
|
||||||
|
callback = args[2];
|
||||||
|
|
||||||
|
if (callback->IsObject()) {
|
||||||
|
ASYNC_CALL(readlink, callback, encoding, *path)
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(readlink, *path, *path)
|
SYNC_CALL(readlink, *path, *path)
|
||||||
const char* link_path = static_cast<const char*>(SYNC_REQ.ptr);
|
const char* link_path = static_cast<const char*>(SYNC_REQ.ptr);
|
||||||
Local<String> rc = String::NewFromUtf8(env->isolate(), link_path);
|
Local<Value> rc = StringBytes::Encode(env->isolate(),
|
||||||
|
link_path,
|
||||||
|
encoding);
|
||||||
|
if (rc.IsEmpty()) {
|
||||||
|
return env->ThrowUVException(UV_EINVAL,
|
||||||
|
"readlink",
|
||||||
|
"Invalid character encoding for link",
|
||||||
|
*path);
|
||||||
|
}
|
||||||
args.GetReturnValue().Set(rc);
|
args.GetReturnValue().Set(rc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -682,16 +735,14 @@ static void Rename(const FunctionCallbackInfo<Value>& args) {
|
|||||||
return TYPE_ERROR("old path required");
|
return TYPE_ERROR("old path required");
|
||||||
if (len < 2)
|
if (len < 2)
|
||||||
return TYPE_ERROR("new path required");
|
return TYPE_ERROR("new path required");
|
||||||
if (!args[0]->IsString())
|
|
||||||
return TYPE_ERROR("old path must be a string");
|
|
||||||
if (!args[1]->IsString())
|
|
||||||
return TYPE_ERROR("new path must be a string");
|
|
||||||
|
|
||||||
node::Utf8Value old_path(env->isolate(), args[0]);
|
BufferValue old_path(env->isolate(), args[0]);
|
||||||
node::Utf8Value new_path(env->isolate(), args[1]);
|
ASSERT_PATH(old_path)
|
||||||
|
BufferValue new_path(env->isolate(), args[1]);
|
||||||
|
ASSERT_PATH(new_path)
|
||||||
|
|
||||||
if (args[2]->IsObject()) {
|
if (args[2]->IsObject()) {
|
||||||
ASYNC_DEST_CALL(rename, args[2], *new_path, *old_path, *new_path)
|
ASYNC_DEST_CALL(rename, args[2], *new_path, UTF8, *old_path, *new_path)
|
||||||
} else {
|
} else {
|
||||||
SYNC_DEST_CALL(rename, *old_path, *new_path, *old_path, *new_path)
|
SYNC_DEST_CALL(rename, *old_path, *new_path, *old_path, *new_path)
|
||||||
}
|
}
|
||||||
@ -720,7 +771,7 @@ static void FTruncate(const FunctionCallbackInfo<Value>& args) {
|
|||||||
const int64_t len = len_v->IntegerValue();
|
const int64_t len = len_v->IntegerValue();
|
||||||
|
|
||||||
if (args[2]->IsObject()) {
|
if (args[2]->IsObject()) {
|
||||||
ASYNC_CALL(ftruncate, args[2], fd, len)
|
ASYNC_CALL(ftruncate, args[2], UTF8, fd, len)
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(ftruncate, 0, fd, len)
|
SYNC_CALL(ftruncate, 0, fd, len)
|
||||||
}
|
}
|
||||||
@ -737,7 +788,7 @@ static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
|
|||||||
int fd = args[0]->Int32Value();
|
int fd = args[0]->Int32Value();
|
||||||
|
|
||||||
if (args[1]->IsObject()) {
|
if (args[1]->IsObject()) {
|
||||||
ASYNC_CALL(fdatasync, args[1], fd)
|
ASYNC_CALL(fdatasync, args[1], UTF8, fd)
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(fdatasync, 0, fd)
|
SYNC_CALL(fdatasync, 0, fd)
|
||||||
}
|
}
|
||||||
@ -754,7 +805,7 @@ static void Fsync(const FunctionCallbackInfo<Value>& args) {
|
|||||||
int fd = args[0]->Int32Value();
|
int fd = args[0]->Int32Value();
|
||||||
|
|
||||||
if (args[1]->IsObject()) {
|
if (args[1]->IsObject()) {
|
||||||
ASYNC_CALL(fsync, args[1], fd)
|
ASYNC_CALL(fsync, args[1], UTF8, fd)
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(fsync, 0, fd)
|
SYNC_CALL(fsync, 0, fd)
|
||||||
}
|
}
|
||||||
@ -765,13 +816,12 @@ static void Unlink(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
if (args.Length() < 1)
|
if (args.Length() < 1)
|
||||||
return TYPE_ERROR("path required");
|
return TYPE_ERROR("path required");
|
||||||
if (!args[0]->IsString())
|
|
||||||
return TYPE_ERROR("path must be a string");
|
|
||||||
|
|
||||||
node::Utf8Value path(env->isolate(), args[0]);
|
BufferValue path(env->isolate(), args[0]);
|
||||||
|
ASSERT_PATH(path)
|
||||||
|
|
||||||
if (args[1]->IsObject()) {
|
if (args[1]->IsObject()) {
|
||||||
ASYNC_CALL(unlink, args[1], *path)
|
ASYNC_CALL(unlink, args[1], UTF8, *path)
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(unlink, *path, *path)
|
SYNC_CALL(unlink, *path, *path)
|
||||||
}
|
}
|
||||||
@ -782,13 +832,12 @@ static void RMDir(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
if (args.Length() < 1)
|
if (args.Length() < 1)
|
||||||
return TYPE_ERROR("path required");
|
return TYPE_ERROR("path required");
|
||||||
if (!args[0]->IsString())
|
|
||||||
return TYPE_ERROR("path must be a string");
|
|
||||||
|
|
||||||
node::Utf8Value path(env->isolate(), args[0]);
|
BufferValue path(env->isolate(), args[0]);
|
||||||
|
ASSERT_PATH(path)
|
||||||
|
|
||||||
if (args[1]->IsObject()) {
|
if (args[1]->IsObject()) {
|
||||||
ASYNC_CALL(rmdir, args[1], *path)
|
ASYNC_CALL(rmdir, args[1], UTF8, *path)
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(rmdir, *path, *path)
|
SYNC_CALL(rmdir, *path, *path)
|
||||||
}
|
}
|
||||||
@ -799,16 +848,16 @@ static void MKDir(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
if (args.Length() < 2)
|
if (args.Length() < 2)
|
||||||
return TYPE_ERROR("path and mode are required");
|
return TYPE_ERROR("path and mode are required");
|
||||||
if (!args[0]->IsString())
|
|
||||||
return TYPE_ERROR("path must be a string");
|
|
||||||
if (!args[1]->IsInt32())
|
if (!args[1]->IsInt32())
|
||||||
return TYPE_ERROR("mode must be an integer");
|
return TYPE_ERROR("mode must be an integer");
|
||||||
|
|
||||||
node::Utf8Value path(env->isolate(), args[0]);
|
BufferValue path(env->isolate(), args[0]);
|
||||||
|
ASSERT_PATH(path)
|
||||||
|
|
||||||
int mode = static_cast<int>(args[1]->Int32Value());
|
int mode = static_cast<int>(args[1]->Int32Value());
|
||||||
|
|
||||||
if (args[2]->IsObject()) {
|
if (args[2]->IsObject()) {
|
||||||
ASYNC_CALL(mkdir, args[2], *path, mode)
|
ASYNC_CALL(mkdir, args[2], UTF8, *path, mode)
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(mkdir, *path, *path, mode)
|
SYNC_CALL(mkdir, *path, *path, mode)
|
||||||
}
|
}
|
||||||
@ -817,15 +866,22 @@ static void MKDir(const FunctionCallbackInfo<Value>& args) {
|
|||||||
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
|
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
|
||||||
if (args.Length() < 1)
|
const int argc = args.Length();
|
||||||
|
|
||||||
|
if (argc < 1)
|
||||||
return TYPE_ERROR("path required");
|
return TYPE_ERROR("path required");
|
||||||
if (!args[0]->IsString())
|
|
||||||
return TYPE_ERROR("path must be a string");
|
|
||||||
|
|
||||||
node::Utf8Value path(env->isolate(), args[0]);
|
BufferValue path(env->isolate(), args[0]);
|
||||||
|
ASSERT_PATH(path)
|
||||||
|
|
||||||
if (args[1]->IsObject()) {
|
const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
|
||||||
ASYNC_CALL(scandir, args[1], *path, 0 /*flags*/)
|
|
||||||
|
Local<Value> callback = Null(env->isolate());
|
||||||
|
if (argc == 3)
|
||||||
|
callback = args[2];
|
||||||
|
|
||||||
|
if (callback->IsObject()) {
|
||||||
|
ASYNC_CALL(scandir, callback, encoding, *path, 0 /*flags*/)
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(scandir, *path, *path, 0 /*flags*/)
|
SYNC_CALL(scandir, *path, *path, 0 /*flags*/)
|
||||||
|
|
||||||
@ -845,8 +901,17 @@ static void ReadDir(const FunctionCallbackInfo<Value>& args) {
|
|||||||
if (r != 0)
|
if (r != 0)
|
||||||
return env->ThrowUVException(r, "readdir", "", *path);
|
return env->ThrowUVException(r, "readdir", "", *path);
|
||||||
|
|
||||||
|
Local<Value> filename = StringBytes::Encode(env->isolate(),
|
||||||
|
ent.name,
|
||||||
|
encoding);
|
||||||
|
if (filename.IsEmpty()) {
|
||||||
|
return env->ThrowUVException(UV_EINVAL,
|
||||||
|
"readdir",
|
||||||
|
"Invalid character encoding for filename",
|
||||||
|
*path);
|
||||||
|
}
|
||||||
|
|
||||||
name_v[name_idx++] = String::NewFromUtf8(env->isolate(), ent.name);
|
name_v[name_idx++] = filename;
|
||||||
|
|
||||||
if (name_idx >= ARRAY_SIZE(name_v)) {
|
if (name_idx >= ARRAY_SIZE(name_v)) {
|
||||||
fn->Call(env->context(), names, name_idx, name_v)
|
fn->Call(env->context(), names, name_idx, name_v)
|
||||||
@ -873,19 +938,19 @@ static void Open(const FunctionCallbackInfo<Value>& args) {
|
|||||||
return TYPE_ERROR("flags required");
|
return TYPE_ERROR("flags required");
|
||||||
if (len < 3)
|
if (len < 3)
|
||||||
return TYPE_ERROR("mode required");
|
return TYPE_ERROR("mode required");
|
||||||
if (!args[0]->IsString())
|
|
||||||
return TYPE_ERROR("path must be a string");
|
|
||||||
if (!args[1]->IsInt32())
|
if (!args[1]->IsInt32())
|
||||||
return TYPE_ERROR("flags must be an int");
|
return TYPE_ERROR("flags must be an int");
|
||||||
if (!args[2]->IsInt32())
|
if (!args[2]->IsInt32())
|
||||||
return TYPE_ERROR("mode must be an int");
|
return TYPE_ERROR("mode must be an int");
|
||||||
|
|
||||||
node::Utf8Value path(env->isolate(), args[0]);
|
BufferValue path(env->isolate(), args[0]);
|
||||||
|
ASSERT_PATH(path)
|
||||||
|
|
||||||
int flags = args[1]->Int32Value();
|
int flags = args[1]->Int32Value();
|
||||||
int mode = static_cast<int>(args[2]->Int32Value());
|
int mode = static_cast<int>(args[2]->Int32Value());
|
||||||
|
|
||||||
if (args[3]->IsObject()) {
|
if (args[3]->IsObject()) {
|
||||||
ASYNC_CALL(open, args[3], *path, flags, mode)
|
ASYNC_CALL(open, args[3], UTF8, *path, flags, mode)
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(open, *path, *path, flags, mode)
|
SYNC_CALL(open, *path, *path, flags, mode)
|
||||||
args.GetReturnValue().Set(SYNC_RESULT);
|
args.GetReturnValue().Set(SYNC_RESULT);
|
||||||
@ -933,7 +998,7 @@ static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
|
|||||||
uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
|
uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
|
||||||
|
|
||||||
if (req->IsObject()) {
|
if (req->IsObject()) {
|
||||||
ASYNC_CALL(write, req, fd, &uvbuf, 1, pos)
|
ASYNC_CALL(write, req, UTF8, fd, &uvbuf, 1, pos)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -983,7 +1048,7 @@ static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (req->IsObject()) {
|
if (req->IsObject()) {
|
||||||
ASYNC_CALL(write, req, fd, iovs, chunkCount, pos)
|
ASYNC_CALL(write, req, UTF8, fd, iovs, chunkCount, pos)
|
||||||
if (iovs != s_iovs)
|
if (iovs != s_iovs)
|
||||||
delete[] iovs;
|
delete[] iovs;
|
||||||
return;
|
return;
|
||||||
@ -1049,7 +1114,7 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FSReqWrap* req_wrap =
|
FSReqWrap* req_wrap =
|
||||||
FSReqWrap::New(env, req.As<Object>(), "write", buf, ownership);
|
FSReqWrap::New(env, req.As<Object>(), "write", buf, UTF8, ownership);
|
||||||
int err = uv_fs_write(env->event_loop(),
|
int err = uv_fs_write(env->event_loop(),
|
||||||
&req_wrap->req_,
|
&req_wrap->req_,
|
||||||
fd,
|
fd,
|
||||||
@ -1123,7 +1188,7 @@ static void Read(const FunctionCallbackInfo<Value>& args) {
|
|||||||
req = args[5];
|
req = args[5];
|
||||||
|
|
||||||
if (req->IsObject()) {
|
if (req->IsObject()) {
|
||||||
ASYNC_CALL(read, req, fd, &uvbuf, 1, pos);
|
ASYNC_CALL(read, req, UTF8, fd, &uvbuf, 1, pos);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(read, 0, fd, &uvbuf, 1, pos)
|
SYNC_CALL(read, 0, fd, &uvbuf, 1, pos)
|
||||||
args.GetReturnValue().Set(SYNC_RESULT);
|
args.GetReturnValue().Set(SYNC_RESULT);
|
||||||
@ -1139,16 +1204,16 @@ static void Chmod(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
if (args.Length() < 2)
|
if (args.Length() < 2)
|
||||||
return TYPE_ERROR("path and mode are required");
|
return TYPE_ERROR("path and mode are required");
|
||||||
if (!args[0]->IsString())
|
|
||||||
return TYPE_ERROR("path must be a string");
|
|
||||||
if (!args[1]->IsInt32())
|
if (!args[1]->IsInt32())
|
||||||
return TYPE_ERROR("mode must be an integer");
|
return TYPE_ERROR("mode must be an integer");
|
||||||
|
|
||||||
node::Utf8Value path(env->isolate(), args[0]);
|
BufferValue path(env->isolate(), args[0]);
|
||||||
|
ASSERT_PATH(path)
|
||||||
|
|
||||||
int mode = static_cast<int>(args[1]->Int32Value());
|
int mode = static_cast<int>(args[1]->Int32Value());
|
||||||
|
|
||||||
if (args[2]->IsObject()) {
|
if (args[2]->IsObject()) {
|
||||||
ASYNC_CALL(chmod, args[2], *path, mode);
|
ASYNC_CALL(chmod, args[2], UTF8, *path, mode);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(chmod, *path, *path, mode);
|
SYNC_CALL(chmod, *path, *path, mode);
|
||||||
}
|
}
|
||||||
@ -1172,7 +1237,7 @@ static void FChmod(const FunctionCallbackInfo<Value>& args) {
|
|||||||
int mode = static_cast<int>(args[1]->Int32Value());
|
int mode = static_cast<int>(args[1]->Int32Value());
|
||||||
|
|
||||||
if (args[2]->IsObject()) {
|
if (args[2]->IsObject()) {
|
||||||
ASYNC_CALL(fchmod, args[2], fd, mode);
|
ASYNC_CALL(fchmod, args[2], UTF8, fd, mode);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(fchmod, 0, fd, mode);
|
SYNC_CALL(fchmod, 0, fd, mode);
|
||||||
}
|
}
|
||||||
@ -1192,19 +1257,19 @@ static void Chown(const FunctionCallbackInfo<Value>& args) {
|
|||||||
return TYPE_ERROR("uid required");
|
return TYPE_ERROR("uid required");
|
||||||
if (len < 3)
|
if (len < 3)
|
||||||
return TYPE_ERROR("gid required");
|
return TYPE_ERROR("gid required");
|
||||||
if (!args[0]->IsString())
|
|
||||||
return TYPE_ERROR("path must be a string");
|
|
||||||
if (!args[1]->IsUint32())
|
if (!args[1]->IsUint32())
|
||||||
return TYPE_ERROR("uid must be an unsigned int");
|
return TYPE_ERROR("uid must be an unsigned int");
|
||||||
if (!args[2]->IsUint32())
|
if (!args[2]->IsUint32())
|
||||||
return TYPE_ERROR("gid must be an unsigned int");
|
return TYPE_ERROR("gid must be an unsigned int");
|
||||||
|
|
||||||
node::Utf8Value path(env->isolate(), args[0]);
|
BufferValue path(env->isolate(), args[0]);
|
||||||
|
ASSERT_PATH(path)
|
||||||
|
|
||||||
uv_uid_t uid = static_cast<uv_uid_t>(args[1]->Uint32Value());
|
uv_uid_t uid = static_cast<uv_uid_t>(args[1]->Uint32Value());
|
||||||
uv_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value());
|
uv_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value());
|
||||||
|
|
||||||
if (args[3]->IsObject()) {
|
if (args[3]->IsObject()) {
|
||||||
ASYNC_CALL(chown, args[3], *path, uid, gid);
|
ASYNC_CALL(chown, args[3], UTF8, *path, uid, gid);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(chown, *path, *path, uid, gid);
|
SYNC_CALL(chown, *path, *path, uid, gid);
|
||||||
}
|
}
|
||||||
@ -1236,7 +1301,7 @@ static void FChown(const FunctionCallbackInfo<Value>& args) {
|
|||||||
uv_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value());
|
uv_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value());
|
||||||
|
|
||||||
if (args[3]->IsObject()) {
|
if (args[3]->IsObject()) {
|
||||||
ASYNC_CALL(fchown, args[3], fd, uid, gid);
|
ASYNC_CALL(fchown, args[3], UTF8, fd, uid, gid);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(fchown, 0, fd, uid, gid);
|
SYNC_CALL(fchown, 0, fd, uid, gid);
|
||||||
}
|
}
|
||||||
@ -1253,19 +1318,19 @@ static void UTimes(const FunctionCallbackInfo<Value>& args) {
|
|||||||
return TYPE_ERROR("atime required");
|
return TYPE_ERROR("atime required");
|
||||||
if (len < 3)
|
if (len < 3)
|
||||||
return TYPE_ERROR("mtime required");
|
return TYPE_ERROR("mtime required");
|
||||||
if (!args[0]->IsString())
|
|
||||||
return TYPE_ERROR("path must be a string");
|
|
||||||
if (!args[1]->IsNumber())
|
if (!args[1]->IsNumber())
|
||||||
return TYPE_ERROR("atime must be a number");
|
return TYPE_ERROR("atime must be a number");
|
||||||
if (!args[2]->IsNumber())
|
if (!args[2]->IsNumber())
|
||||||
return TYPE_ERROR("mtime must be a number");
|
return TYPE_ERROR("mtime must be a number");
|
||||||
|
|
||||||
const node::Utf8Value path(env->isolate(), args[0]);
|
BufferValue path(env->isolate(), args[0]);
|
||||||
|
ASSERT_PATH(path)
|
||||||
|
|
||||||
const double atime = static_cast<double>(args[1]->NumberValue());
|
const double atime = static_cast<double>(args[1]->NumberValue());
|
||||||
const double mtime = static_cast<double>(args[2]->NumberValue());
|
const double mtime = static_cast<double>(args[2]->NumberValue());
|
||||||
|
|
||||||
if (args[3]->IsObject()) {
|
if (args[3]->IsObject()) {
|
||||||
ASYNC_CALL(utime, args[3], *path, atime, mtime);
|
ASYNC_CALL(utime, args[3], UTF8, *path, atime, mtime);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(utime, *path, *path, atime, mtime);
|
SYNC_CALL(utime, *path, *path, atime, mtime);
|
||||||
}
|
}
|
||||||
@ -1293,7 +1358,7 @@ static void FUTimes(const FunctionCallbackInfo<Value>& args) {
|
|||||||
const double mtime = static_cast<double>(args[2]->NumberValue());
|
const double mtime = static_cast<double>(args[2]->NumberValue());
|
||||||
|
|
||||||
if (args[3]->IsObject()) {
|
if (args[3]->IsObject()) {
|
||||||
ASYNC_CALL(futime, args[3], fd, atime, mtime);
|
ASYNC_CALL(futime, args[3], UTF8, fd, atime, mtime);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(futime, 0, fd, atime, mtime);
|
SYNC_CALL(futime, 0, fd, atime, mtime);
|
||||||
}
|
}
|
||||||
@ -1302,19 +1367,27 @@ static void FUTimes(const FunctionCallbackInfo<Value>& args) {
|
|||||||
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
|
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
|
||||||
if (args.Length() < 1)
|
CHECK_GE(args.Length(), 2);
|
||||||
return TYPE_ERROR("template is required");
|
|
||||||
if (!args[0]->IsString())
|
|
||||||
return TYPE_ERROR("template must be a string");
|
|
||||||
|
|
||||||
node::Utf8Value tmpl(env->isolate(), args[0]);
|
BufferValue tmpl(env->isolate(), args[0]);
|
||||||
|
if (*tmpl == nullptr)
|
||||||
|
return TYPE_ERROR("template must be a string or Buffer");
|
||||||
|
|
||||||
if (args[1]->IsObject()) {
|
const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
|
||||||
ASYNC_CALL(mkdtemp, args[1], *tmpl);
|
|
||||||
|
if (args[2]->IsObject()) {
|
||||||
|
ASYNC_CALL(mkdtemp, args[2], encoding, *tmpl);
|
||||||
} else {
|
} else {
|
||||||
SYNC_CALL(mkdtemp, *tmpl, *tmpl);
|
SYNC_CALL(mkdtemp, *tmpl, *tmpl);
|
||||||
args.GetReturnValue().Set(String::NewFromUtf8(env->isolate(),
|
const char* path = static_cast<const char*>(SYNC_REQ.path);
|
||||||
SYNC_REQ.path));
|
Local<Value> rc = StringBytes::Encode(env->isolate(), path, encoding);
|
||||||
|
if (rc.IsEmpty()) {
|
||||||
|
return env->ThrowUVException(UV_EINVAL,
|
||||||
|
"mkdtemp",
|
||||||
|
"Invalid character encoding for filename",
|
||||||
|
*tmpl);
|
||||||
|
}
|
||||||
|
args.GetReturnValue().Set(rc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@ using v8::String;
|
|||||||
using v8::Value;
|
using v8::Value;
|
||||||
using v8::MaybeLocal;
|
using v8::MaybeLocal;
|
||||||
|
|
||||||
|
|
||||||
template <typename ResourceType, typename TypeName>
|
template <typename ResourceType, typename TypeName>
|
||||||
class ExternString: public ResourceType {
|
class ExternString: public ResourceType {
|
||||||
public:
|
public:
|
||||||
@ -895,4 +894,34 @@ Local<Value> StringBytes::Encode(Isolate* isolate,
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Local<Value> StringBytes::Encode(Isolate* isolate,
|
||||||
|
const char* buf,
|
||||||
|
enum encoding encoding) {
|
||||||
|
const size_t len = strlen(buf);
|
||||||
|
Local<Value> ret;
|
||||||
|
if (encoding == UCS2) {
|
||||||
|
// In Node, UCS2 means utf16le. The data must be in little-endian
|
||||||
|
// order and must be aligned on 2-bytes. This returns an empty
|
||||||
|
// value if it's not aligned and ensures the appropriate byte order
|
||||||
|
// on big endian architectures.
|
||||||
|
const bool be = IsBigEndian();
|
||||||
|
if (len % 2 != 0)
|
||||||
|
return ret;
|
||||||
|
std::vector<uint16_t> vec(len / 2);
|
||||||
|
for (size_t i = 0, k = 0; i < len; i += 2, k += 1) {
|
||||||
|
const uint8_t hi = static_cast<uint8_t>(buf[i + 0]);
|
||||||
|
const uint8_t lo = static_cast<uint8_t>(buf[i + 1]);
|
||||||
|
vec[k] = be ?
|
||||||
|
static_cast<uint16_t>(hi) << 8 | lo
|
||||||
|
: static_cast<uint16_t>(lo) << 8 | hi;
|
||||||
|
}
|
||||||
|
ret = vec.empty() ?
|
||||||
|
static_cast< Local<Value> >(String::Empty(isolate))
|
||||||
|
: StringBytes::Encode(isolate, &vec[0], vec.size());
|
||||||
|
} else {
|
||||||
|
ret = StringBytes::Encode(isolate, buf, len, encoding);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
@ -106,6 +106,10 @@ class StringBytes {
|
|||||||
const uint16_t* buf,
|
const uint16_t* buf,
|
||||||
size_t buflen);
|
size_t buflen);
|
||||||
|
|
||||||
|
static v8::Local<v8::Value> Encode(v8::Isolate* isolate,
|
||||||
|
const char* buf,
|
||||||
|
enum encoding encoding);
|
||||||
|
|
||||||
// Deprecated legacy interface
|
// Deprecated legacy interface
|
||||||
|
|
||||||
NODE_DEPRECATED("Use IsValidString(isolate, ...)",
|
NODE_DEPRECATED("Use IsValidString(isolate, ...)",
|
||||||
|
73
src/util.cc
73
src/util.cc
@ -1,37 +1,48 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "string_bytes.h"
|
#include "string_bytes.h"
|
||||||
|
#include "node_buffer.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
Utf8Value::Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value)
|
using v8::Isolate;
|
||||||
|
using v8::String;
|
||||||
|
using v8::Local;
|
||||||
|
using v8::Value;
|
||||||
|
|
||||||
|
static int MakeUtf8String(Isolate* isolate,
|
||||||
|
Local<Value> value,
|
||||||
|
char** dst,
|
||||||
|
const size_t size) {
|
||||||
|
Local<String> string = value->ToString(isolate);
|
||||||
|
if (string.IsEmpty())
|
||||||
|
return 0;
|
||||||
|
size_t len = StringBytes::StorageSize(isolate, string, UTF8) + 1;
|
||||||
|
if (len > size) {
|
||||||
|
*dst = static_cast<char*>(malloc(len));
|
||||||
|
CHECK_NE(*dst, nullptr);
|
||||||
|
}
|
||||||
|
const int flags =
|
||||||
|
String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8;
|
||||||
|
const int length = string->WriteUtf8(*dst, len, 0, flags);
|
||||||
|
(*dst)[length] = '\0';
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
Utf8Value::Utf8Value(Isolate* isolate, Local<Value> value)
|
||||||
: length_(0), str_(str_st_) {
|
: length_(0), str_(str_st_) {
|
||||||
if (value.IsEmpty())
|
if (value.IsEmpty())
|
||||||
return;
|
return;
|
||||||
|
length_ = MakeUtf8String(isolate, value, &str_, sizeof(str_st_));
|
||||||
v8::Local<v8::String> string = value->ToString(isolate);
|
|
||||||
if (string.IsEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Allocate enough space to include the null terminator
|
|
||||||
size_t len = StringBytes::StorageSize(isolate, string, UTF8) + 1;
|
|
||||||
if (len > sizeof(str_st_)) {
|
|
||||||
str_ = static_cast<char*>(malloc(len));
|
|
||||||
CHECK_NE(str_, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
const int flags =
|
|
||||||
v8::String::NO_NULL_TERMINATION | v8::String::REPLACE_INVALID_UTF8;
|
|
||||||
length_ = string->WriteUtf8(str_, len, 0, flags);
|
|
||||||
str_[length_] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TwoByteValue::TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value)
|
TwoByteValue::TwoByteValue(Isolate* isolate, Local<Value> value)
|
||||||
: length_(0), str_(str_st_) {
|
: length_(0), str_(str_st_) {
|
||||||
if (value.IsEmpty())
|
if (value.IsEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
v8::Local<v8::String> string = value->ToString(isolate);
|
Local<String> string = value->ToString(isolate);
|
||||||
if (string.IsEmpty())
|
if (string.IsEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -43,9 +54,31 @@ TwoByteValue::TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const int flags =
|
const int flags =
|
||||||
v8::String::NO_NULL_TERMINATION | v8::String::REPLACE_INVALID_UTF8;
|
String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8;
|
||||||
length_ = string->Write(str_, 0, len, flags);
|
length_ = string->Write(str_, 0, len, flags);
|
||||||
str_[length_] = '\0';
|
str_[length_] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BufferValue::BufferValue(Isolate* isolate, Local<Value> value)
|
||||||
|
: str_(str_st_), fail_(true) {
|
||||||
|
// Slightly different take on Utf8Value. If value is a String,
|
||||||
|
// it will return a Utf8 encoded string. If value is a Buffer,
|
||||||
|
// it will copy the data out of the Buffer as is.
|
||||||
|
if (value.IsEmpty())
|
||||||
|
return;
|
||||||
|
if (value->IsString()) {
|
||||||
|
MakeUtf8String(isolate, value, &str_, sizeof(str_st_));
|
||||||
|
fail_ = false;
|
||||||
|
} else if (Buffer::HasInstance(value)) {
|
||||||
|
size_t len = Buffer::Length(value) + 1;
|
||||||
|
if (len > sizeof(str_st_)) {
|
||||||
|
str_ = static_cast<char*>(malloc(len));
|
||||||
|
CHECK_NE(str_, nullptr);
|
||||||
|
}
|
||||||
|
memcpy(str_, Buffer::Data(value), len);
|
||||||
|
str_[len - 1] = '\0';
|
||||||
|
fail_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
19
src/util.h
19
src/util.h
@ -232,6 +232,25 @@ class TwoByteValue {
|
|||||||
uint16_t str_st_[1024];
|
uint16_t str_st_[1024];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BufferValue {
|
||||||
|
public:
|
||||||
|
explicit BufferValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
|
||||||
|
|
||||||
|
~BufferValue() {
|
||||||
|
if (str_ != str_st_)
|
||||||
|
free(str_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* operator*() const {
|
||||||
|
return fail_ ? nullptr : str_;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
char* str_;
|
||||||
|
char str_st_[1024];
|
||||||
|
bool fail_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
|
||||||
#endif // SRC_UTIL_H_
|
#endif // SRC_UTIL_H_
|
||||||
|
@ -57,8 +57,14 @@ function rmdirSync(p, originalEr) {
|
|||||||
if (e.code === 'ENOTDIR')
|
if (e.code === 'ENOTDIR')
|
||||||
throw originalEr;
|
throw originalEr;
|
||||||
if (e.code === 'ENOTEMPTY' || e.code === 'EEXIST' || e.code === 'EPERM') {
|
if (e.code === 'ENOTEMPTY' || e.code === 'EEXIST' || e.code === 'EPERM') {
|
||||||
fs.readdirSync(p).forEach(function(f) {
|
const enc = process.platform === 'linux' ? 'buffer' : 'utf8';
|
||||||
|
fs.readdirSync(p, enc).forEach((f) => {
|
||||||
|
if (f instanceof Buffer) {
|
||||||
|
const buf = Buffer.concat([Buffer.from(p), Buffer.from(path.sep), f]);
|
||||||
|
rimrafSync(buf);
|
||||||
|
} else {
|
||||||
rimrafSync(path.join(p, f));
|
rimrafSync(path.join(p, f));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
fs.rmdirSync(p);
|
fs.rmdirSync(p);
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ fs.access(readOnlyFile, fs.W_OK, function(err) {
|
|||||||
|
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
fs.access(100, fs.F_OK, function(err) {});
|
fs.access(100, fs.F_OK, function(err) {});
|
||||||
}, /path must be a string/);
|
}, /path must be a string or Buffer/);
|
||||||
|
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
fs.access(__filename, fs.F_OK);
|
fs.access(__filename, fs.F_OK);
|
||||||
|
41
test/parallel/test-fs-buffer.js
Normal file
41
test/parallel/test-fs-buffer.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const assert = require('assert');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
common.refreshTmpDir();
|
||||||
|
|
||||||
|
assert.doesNotThrow(() => {
|
||||||
|
fs.access(Buffer.from(common.tmpDir), common.mustCall((err) => {
|
||||||
|
if (err) throw err;
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.doesNotThrow(() => {
|
||||||
|
const buf = Buffer.from(path.join(common.tmpDir, 'a.txt'));
|
||||||
|
fs.open(buf, 'w+', common.mustCall((err, fd) => {
|
||||||
|
if (err) throw err;
|
||||||
|
assert(fd);
|
||||||
|
fs.close(fd, common.mustCall(() => {
|
||||||
|
fs.unlinkSync(buf);
|
||||||
|
}));
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.throws(() => {
|
||||||
|
fs.accessSync(true);
|
||||||
|
}, /path must be a string or Buffer/);
|
||||||
|
|
||||||
|
const dir = Buffer.from(common.fixturesDir);
|
||||||
|
fs.readdir(dir, 'hex', common.mustCall((err, list) => {
|
||||||
|
if (err) throw err;
|
||||||
|
list = list.map((i) => {
|
||||||
|
return Buffer.from(i, 'hex').toString();
|
||||||
|
});
|
||||||
|
fs.readdir(dir, common.mustCall((err, list2) => {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.deepStrictEqual(list, list2);
|
||||||
|
}));
|
||||||
|
}));
|
@ -25,12 +25,12 @@ assert.throws(
|
|||||||
function() {
|
function() {
|
||||||
fs.link();
|
fs.link();
|
||||||
},
|
},
|
||||||
/src path/
|
/src must be a string or Buffer/
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.throws(
|
assert.throws(
|
||||||
function() {
|
function() {
|
||||||
fs.link('abc');
|
fs.link('abc');
|
||||||
},
|
},
|
||||||
/dest path/
|
/dest must be a string or Buffer/
|
||||||
);
|
);
|
||||||
|
31
test/parallel/test-fs-readdir-ucs2.js
Normal file
31
test/parallel/test-fs-readdir-ucs2.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
if (process.platform !== 'linux') {
|
||||||
|
console.log('1..0 # Skipped: Test is linux specific.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
common.refreshTmpDir();
|
||||||
|
const filename = '\uD83D\uDC04';
|
||||||
|
const root = Buffer.from(`${common.tmpDir}${path.sep}`);
|
||||||
|
const filebuff = Buffer.from(filename, 'ucs2');
|
||||||
|
const fullpath = Buffer.concat([root, filebuff]);
|
||||||
|
|
||||||
|
fs.closeSync(fs.openSync(fullpath, 'w+'));
|
||||||
|
|
||||||
|
fs.readdir(common.tmpDir, 'ucs2', (err, list) => {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.equal(1, list.length);
|
||||||
|
const fn = list[0];
|
||||||
|
assert.deepStrictEqual(filebuff, Buffer.from(fn, 'ucs2'));
|
||||||
|
assert.strictEqual(fn, filename);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('exit', () => {
|
||||||
|
fs.unlinkSync(fullpath);
|
||||||
|
});
|
52
test/parallel/test-fs-watch-encoding.js
Normal file
52
test/parallel/test-fs-watch-encoding.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
if (common.isFreeBSD) {
|
||||||
|
console.log('1..0 # Skipped: Test currently not working on FreeBSD');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn = '新建文夹件.txt';
|
||||||
|
const a = path.join(common.tmpDir, fn);
|
||||||
|
|
||||||
|
const watcher1 = fs.watch(
|
||||||
|
common.tmpDir,
|
||||||
|
{encoding: 'hex'},
|
||||||
|
(event, filename) => {
|
||||||
|
if (filename)
|
||||||
|
assert.equal(filename, 'e696b0e5bbbae69687e5a4b9e4bbb62e747874');
|
||||||
|
watcher1.close();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const watcher2 = fs.watch(
|
||||||
|
common.tmpDir,
|
||||||
|
(event, filename) => {
|
||||||
|
if (filename)
|
||||||
|
assert.equal(filename, fn);
|
||||||
|
watcher2.close();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const watcher3 = fs.watch(
|
||||||
|
common.tmpDir,
|
||||||
|
{encoding: 'buffer'},
|
||||||
|
(event, filename) => {
|
||||||
|
if (filename) {
|
||||||
|
assert(filename instanceof Buffer);
|
||||||
|
assert.equal(filename.toString('utf8'), fn);
|
||||||
|
}
|
||||||
|
watcher3.close();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const fd = fs.openSync(a, 'w+');
|
||||||
|
fs.closeSync(fd);
|
||||||
|
|
||||||
|
process.on('exit', () => {
|
||||||
|
fs.unlink(a);
|
||||||
|
});
|
@ -247,7 +247,7 @@ assert.deepEqual(children, {
|
|||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
console.error('require non-string');
|
console.error('require non-string');
|
||||||
require({ foo: 'bar' });
|
require({ foo: 'bar' });
|
||||||
}, 'path must be a string');
|
}, 'path must be a string or Buffer');
|
||||||
|
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
console.error('require empty string');
|
console.error('require empty string');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user