diff options
author | James M Snell <jasnell@gmail.com> | 2016-03-08 20:58:45 -0800 |
---|---|---|
committer | James M Snell <jasnell@gmail.com> | 2016-03-25 14:21:27 -0700 |
commit | 060e5f0c0064e578c2150f13e3f91ac15fdeed92 (patch) | |
tree | 50783508a123991a024a9a85a2994d5ef2a83c5d /src/node_file.cc | |
parent | 4d4f3535a9fd7486d7a94d825ac8e92a65bf9121 (diff) | |
download | android-node-v8-060e5f0c0064e578c2150f13e3f91ac15fdeed92.tar.gz android-node-v8-060e5f0c0064e578c2150f13e3f91ac15fdeed92.tar.bz2 android-node-v8-060e5f0c0064e578c2150f13e3f91ac15fdeed92.zip |
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>
Diffstat (limited to 'src/node_file.cc')
-rw-r--r-- | src/node_file.cc | 295 |
1 files changed, 184 insertions, 111 deletions
diff --git a/src/node_file.cc b/src/node_file.cc index 9c2bea4897..a669c0855f 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -34,6 +34,7 @@ using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::HandleScope; using v8::Integer; +using v8::Isolate; using v8::Local; using v8::Number; using v8::Object; @@ -56,6 +57,7 @@ class FSReqWrap: public ReqWrap<uv_fs_t> { Local<Object> req, const char* syscall, const char* data = nullptr, + enum encoding encoding = UTF8, Ownership ownership = COPY); inline void Dispose(); @@ -69,6 +71,7 @@ class FSReqWrap: public ReqWrap<uv_fs_t> { const char* syscall() const { return syscall_; } const char* data() const { return data_; } + const enum encoding encoding_; size_t self_size() const override { return sizeof(*this); } @@ -76,8 +79,10 @@ class FSReqWrap: public ReqWrap<uv_fs_t> { FSReqWrap(Environment* env, Local<Object> req, const char* syscall, - const char* data) + const char* data, + enum encoding encoding) : ReqWrap(env, req, AsyncWrap::PROVIDER_FSREQWRAP), + encoding_(encoding), syscall_(syscall), data_(data) { Wrap(object(), this); @@ -95,17 +100,21 @@ class FSReqWrap: public ReqWrap<uv_fs_t> { 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, Local<Object> req, const char* syscall, const char* data, + enum encoding encoding, Ownership ownership) { const bool copy = (data != nullptr && ownership == COPY); const size_t size = copy ? 1 + strlen(data) : 0; FSReqWrap* that; 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) that->data_ = static_cast<char*>(memcpy(that->inline_data(), data, size)); return that; @@ -127,7 +136,6 @@ static inline bool IsInt64(double x) { return x == static_cast<double>(static_cast<int64_t>(x)); } - static void After(uv_fs_t *req) { FSReqWrap* req_wrap = static_cast<FSReqWrap*>(req->data); 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. // (Feel free to increase this if you need more) Local<Value> argv[2]; + Local<Value> link; if (req->result < 0) { // An error happened. @@ -201,13 +210,35 @@ static void After(uv_fs_t *req) { break; case UV_FS_MKDTEMP: - argv[1] = String::NewFromUtf8(env->isolate(), - static_cast<const char*>(req->path)); + link = StringBytes::Encode(env->isolate(), + 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; case UV_FS_READLINK: - argv[1] = String::NewFromUtf8(env->isolate(), - static_cast<const char*>(req->ptr)); + link = StringBytes::Encode(env->isolate(), + 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; case UV_FS_READ: @@ -237,8 +268,19 @@ static void After(uv_fs_t *req) { break; } - name_argv[name_idx++] = - String::NewFromUtf8(env->isolate(), ent.name); + Local<Value> filename = StringBytes::Encode(env->isolate(), + 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)) { 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); \ 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(), \ &req_wrap->req_, \ __VA_ARGS__, \ @@ -296,8 +339,8 @@ struct fs_req_wrap { args.GetReturnValue().Set(req_wrap->persistent()); \ } -#define ASYNC_CALL(func, req, ...) \ - ASYNC_DEST_CALL(func, req, nullptr, __VA_ARGS__) \ +#define ASYNC_CALL(func, req, encoding, ...) \ + ASYNC_DEST_CALL(func, req, nullptr, encoding, __VA_ARGS__) \ #define SYNC_DEST_CALL(func, path, dest, ...) \ fs_req_wrap req_wrap; \ @@ -317,23 +360,22 @@ struct fs_req_wrap { #define SYNC_RESULT err - static void Access(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args.GetIsolate()); HandleScope scope(env->isolate()); if (args.Length() < 2) return TYPE_ERROR("path and mode are required"); - if (!args[0]->IsString()) - return TYPE_ERROR("path must be a string"); if (!args[1]->IsInt32()) 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()); if (args[2]->IsObject()) { - ASYNC_CALL(access, args[2], *path, mode); + ASYNC_CALL(access, args[2], UTF8, *path, mode); } else { SYNC_CALL(access, *path, *path, mode); } @@ -351,7 +393,7 @@ static void Close(const FunctionCallbackInfo<Value>& args) { int fd = args[0]->Int32Value(); if (args[1]->IsObject()) { - ASYNC_CALL(close, args[1], fd) + ASYNC_CALL(close, args[1], UTF8, fd) } else { SYNC_CALL(close, 0, fd) } @@ -544,13 +586,12 @@ static void Stat(const FunctionCallbackInfo<Value>& args) { if (args.Length() < 1) 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()) { - ASYNC_CALL(stat, args[1], *path) + ASYNC_CALL(stat, args[1], UTF8, *path) } else { SYNC_CALL(stat, *path, *path) args.GetReturnValue().Set( @@ -563,13 +604,12 @@ static void LStat(const FunctionCallbackInfo<Value>& args) { if (args.Length() < 1) 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()) { - ASYNC_CALL(lstat, args[1], *path) + ASYNC_CALL(lstat, args[1], UTF8, *path) } else { SYNC_CALL(lstat, *path, *path) args.GetReturnValue().Set( @@ -588,7 +628,7 @@ static void FStat(const FunctionCallbackInfo<Value>& args) { int fd = args[0]->Int32Value(); if (args[1]->IsObject()) { - ASYNC_CALL(fstat, args[1], fd) + ASYNC_CALL(fstat, args[1], UTF8, fd) } else { SYNC_CALL(fstat, 0, fd) args.GetReturnValue().Set( @@ -604,13 +644,12 @@ static void Symlink(const FunctionCallbackInfo<Value>& args) { return TYPE_ERROR("target path required"); if (len < 2) 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]); - node::Utf8Value path(env->isolate(), args[1]); + BufferValue target(env->isolate(), args[0]); + ASSERT_PATH(target) + BufferValue path(env->isolate(), args[1]); + ASSERT_PATH(path) + int flags = 0; if (args[2]->IsString()) { @@ -625,7 +664,7 @@ static void Symlink(const FunctionCallbackInfo<Value>& args) { } 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 { 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"); if (len < 2) 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]); - node::Utf8Value new_path(env->isolate(), args[1]); + BufferValue src(env->isolate(), args[0]); + ASSERT_PATH(src) + + BufferValue dest(env->isolate(), args[1]); + ASSERT_PATH(dest) 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 { - 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) { Environment* env = Environment::GetCurrent(args); - if (args.Length() < 1) + const int argc = args.Length(); + + if (argc < 1) 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()) { - ASYNC_CALL(readlink, args[1], *path) + const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8); + + Local<Value> callback = Null(env->isolate()); + if (argc == 3) + callback = args[2]; + + if (callback->IsObject()) { + ASYNC_CALL(readlink, callback, encoding, *path) } else { SYNC_CALL(readlink, *path, *path) 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); } } @@ -682,16 +735,14 @@ static void Rename(const FunctionCallbackInfo<Value>& args) { return TYPE_ERROR("old path required"); if (len < 2) 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]); - node::Utf8Value new_path(env->isolate(), args[1]); + BufferValue old_path(env->isolate(), args[0]); + ASSERT_PATH(old_path) + BufferValue new_path(env->isolate(), args[1]); + ASSERT_PATH(new_path) 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 { 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(); if (args[2]->IsObject()) { - ASYNC_CALL(ftruncate, args[2], fd, len) + ASYNC_CALL(ftruncate, args[2], UTF8, fd, len) } else { SYNC_CALL(ftruncate, 0, fd, len) } @@ -737,7 +788,7 @@ static void Fdatasync(const FunctionCallbackInfo<Value>& args) { int fd = args[0]->Int32Value(); if (args[1]->IsObject()) { - ASYNC_CALL(fdatasync, args[1], fd) + ASYNC_CALL(fdatasync, args[1], UTF8, fd) } else { SYNC_CALL(fdatasync, 0, fd) } @@ -754,7 +805,7 @@ static void Fsync(const FunctionCallbackInfo<Value>& args) { int fd = args[0]->Int32Value(); if (args[1]->IsObject()) { - ASYNC_CALL(fsync, args[1], fd) + ASYNC_CALL(fsync, args[1], UTF8, fd) } else { SYNC_CALL(fsync, 0, fd) } @@ -765,13 +816,12 @@ static void Unlink(const FunctionCallbackInfo<Value>& args) { if (args.Length() < 1) 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()) { - ASYNC_CALL(unlink, args[1], *path) + ASYNC_CALL(unlink, args[1], UTF8, *path) } else { SYNC_CALL(unlink, *path, *path) } @@ -782,13 +832,12 @@ static void RMDir(const FunctionCallbackInfo<Value>& args) { if (args.Length() < 1) 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()) { - ASYNC_CALL(rmdir, args[1], *path) + ASYNC_CALL(rmdir, args[1], UTF8, *path) } else { SYNC_CALL(rmdir, *path, *path) } @@ -799,16 +848,16 @@ static void MKDir(const FunctionCallbackInfo<Value>& args) { if (args.Length() < 2) return TYPE_ERROR("path and mode are required"); - if (!args[0]->IsString()) - return TYPE_ERROR("path must be a string"); if (!args[1]->IsInt32()) 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()); if (args[2]->IsObject()) { - ASYNC_CALL(mkdir, args[2], *path, mode) + ASYNC_CALL(mkdir, args[2], UTF8, *path, mode) } else { SYNC_CALL(mkdir, *path, *path, mode) } @@ -817,15 +866,22 @@ static void MKDir(const FunctionCallbackInfo<Value>& args) { static void ReadDir(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); - if (args.Length() < 1) + const int argc = args.Length(); + + if (argc < 1) 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()) { - ASYNC_CALL(scandir, args[1], *path, 0 /*flags*/) + const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8); + + Local<Value> callback = Null(env->isolate()); + if (argc == 3) + callback = args[2]; + + if (callback->IsObject()) { + ASYNC_CALL(scandir, callback, encoding, *path, 0 /*flags*/) } else { SYNC_CALL(scandir, *path, *path, 0 /*flags*/) @@ -845,8 +901,17 @@ static void ReadDir(const FunctionCallbackInfo<Value>& args) { if (r != 0) 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)) { 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"); if (len < 3) return TYPE_ERROR("mode required"); - if (!args[0]->IsString()) - return TYPE_ERROR("path must be a string"); if (!args[1]->IsInt32()) return TYPE_ERROR("flags must be an int"); if (!args[2]->IsInt32()) 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 mode = static_cast<int>(args[2]->Int32Value()); if (args[3]->IsObject()) { - ASYNC_CALL(open, args[3], *path, flags, mode) + ASYNC_CALL(open, args[3], UTF8, *path, flags, mode) } else { SYNC_CALL(open, *path, *path, flags, mode) 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); if (req->IsObject()) { - ASYNC_CALL(write, req, fd, &uvbuf, 1, pos) + ASYNC_CALL(write, req, UTF8, fd, &uvbuf, 1, pos) return; } @@ -983,7 +1048,7 @@ static void WriteBuffers(const FunctionCallbackInfo<Value>& args) { } if (req->IsObject()) { - ASYNC_CALL(write, req, fd, iovs, chunkCount, pos) + ASYNC_CALL(write, req, UTF8, fd, iovs, chunkCount, pos) if (iovs != s_iovs) delete[] iovs; return; @@ -1049,7 +1114,7 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) { } 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(), &req_wrap->req_, fd, @@ -1123,7 +1188,7 @@ static void Read(const FunctionCallbackInfo<Value>& args) { req = args[5]; if (req->IsObject()) { - ASYNC_CALL(read, req, fd, &uvbuf, 1, pos); + ASYNC_CALL(read, req, UTF8, fd, &uvbuf, 1, pos); } else { SYNC_CALL(read, 0, fd, &uvbuf, 1, pos) args.GetReturnValue().Set(SYNC_RESULT); @@ -1139,16 +1204,16 @@ static void Chmod(const FunctionCallbackInfo<Value>& args) { if (args.Length() < 2) return TYPE_ERROR("path and mode are required"); - if (!args[0]->IsString()) - return TYPE_ERROR("path must be a string"); if (!args[1]->IsInt32()) 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()); if (args[2]->IsObject()) { - ASYNC_CALL(chmod, args[2], *path, mode); + ASYNC_CALL(chmod, args[2], UTF8, *path, mode); } else { 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()); if (args[2]->IsObject()) { - ASYNC_CALL(fchmod, args[2], fd, mode); + ASYNC_CALL(fchmod, args[2], UTF8, fd, mode); } else { SYNC_CALL(fchmod, 0, fd, mode); } @@ -1192,19 +1257,19 @@ static void Chown(const FunctionCallbackInfo<Value>& args) { return TYPE_ERROR("uid required"); if (len < 3) return TYPE_ERROR("gid required"); - if (!args[0]->IsString()) - return TYPE_ERROR("path must be a string"); if (!args[1]->IsUint32()) return TYPE_ERROR("uid must be an unsigned int"); if (!args[2]->IsUint32()) 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_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value()); if (args[3]->IsObject()) { - ASYNC_CALL(chown, args[3], *path, uid, gid); + ASYNC_CALL(chown, args[3], UTF8, *path, uid, gid); } else { 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()); if (args[3]->IsObject()) { - ASYNC_CALL(fchown, args[3], fd, uid, gid); + ASYNC_CALL(fchown, args[3], UTF8, fd, uid, gid); } else { SYNC_CALL(fchown, 0, fd, uid, gid); } @@ -1253,19 +1318,19 @@ static void UTimes(const FunctionCallbackInfo<Value>& args) { return TYPE_ERROR("atime required"); if (len < 3) return TYPE_ERROR("mtime required"); - if (!args[0]->IsString()) - return TYPE_ERROR("path must be a string"); if (!args[1]->IsNumber()) return TYPE_ERROR("atime must be a number"); if (!args[2]->IsNumber()) 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 mtime = static_cast<double>(args[2]->NumberValue()); if (args[3]->IsObject()) { - ASYNC_CALL(utime, args[3], *path, atime, mtime); + ASYNC_CALL(utime, args[3], UTF8, *path, atime, mtime); } else { 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()); if (args[3]->IsObject()) { - ASYNC_CALL(futime, args[3], fd, atime, mtime); + ASYNC_CALL(futime, args[3], UTF8, fd, atime, mtime); } else { 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) { Environment* env = Environment::GetCurrent(args); - if (args.Length() < 1) - return TYPE_ERROR("template is required"); - if (!args[0]->IsString()) - return TYPE_ERROR("template must be a string"); + CHECK_GE(args.Length(), 2); - 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()) { - ASYNC_CALL(mkdtemp, args[1], *tmpl); + const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8); + + if (args[2]->IsObject()) { + ASYNC_CALL(mkdtemp, args[2], encoding, *tmpl); } else { SYNC_CALL(mkdtemp, *tmpl, *tmpl); - args.GetReturnValue().Set(String::NewFromUtf8(env->isolate(), - SYNC_REQ.path)); + const char* path = static_cast<const char*>(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); } } |