aboutsummaryrefslogtreecommitdiff
path: root/src/node_file.cc
diff options
context:
space:
mode:
authorJames M Snell <jasnell@gmail.com>2016-03-08 20:58:45 -0800
committerJames M Snell <jasnell@gmail.com>2016-03-25 14:21:27 -0700
commit060e5f0c0064e578c2150f13e3f91ac15fdeed92 (patch)
tree50783508a123991a024a9a85a2994d5ef2a83c5d /src/node_file.cc
parent4d4f3535a9fd7486d7a94d825ac8e92a65bf9121 (diff)
downloadandroid-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.cc295
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);
}
}