Skip to content
72 changes: 60 additions & 12 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -924,8 +924,12 @@ fs.renameSync = function(oldPath, newPath) {
nullCheck(newPath);
validatePath(oldPath, 'oldPath');
validatePath(newPath, 'newPath');
return binding.rename(pathModule.toNamespacedPath(oldPath),
pathModule.toNamespacedPath(newPath));
const ctx = { path: oldPath, dest: newPath };
binding.rename(pathModule.toNamespacedPath(oldPath),
pathModule.toNamespacedPath(newPath), undefined, ctx);
if (ctx.errno !== undefined) {
throw new errors.uvException(ctx);
}
};

fs.truncate = function(path, len, callback) {
Expand Down Expand Up @@ -991,7 +995,11 @@ fs.ftruncateSync = function(fd, len = 0) {
validateUint32(fd, 'fd');
validateLen(len);
len = Math.max(0, len);
return binding.ftruncate(fd, len);
const ctx = {};
binding.ftruncate(fd, len, undefined, ctx);
if (ctx.errno !== undefined) {
throw new errors.uvException(ctx);
}
};

fs.rmdir = function(path, callback) {
Expand Down Expand Up @@ -1021,7 +1029,11 @@ fs.fdatasync = function(fd, callback) {

fs.fdatasyncSync = function(fd) {
validateUint32(fd, 'fd');
return binding.fdatasync(fd);
const ctx = {};
binding.fdatasync(fd, undefined, ctx);
if (ctx.errno !== undefined) {
throw new errors.uvException(ctx);
}
};

fs.fsync = function(fd, callback) {
Expand All @@ -1033,7 +1045,11 @@ fs.fsync = function(fd, callback) {

fs.fsyncSync = function(fd) {
validateUint32(fd, 'fd');
return binding.fsync(fd);
const ctx = {};
binding.fsync(fd, undefined, ctx);
if (ctx.errno !== undefined) {
throw new errors.uvException(ctx);
}
};

fs.mkdir = function(path, mode, callback) {
Expand Down Expand Up @@ -1163,7 +1179,13 @@ fs.readlinkSync = function(path, options) {
handleError((path = getPathFromURL(path)));
nullCheck(path);
validatePath(path, 'oldPath');
return binding.readlink(pathModule.toNamespacedPath(path), options.encoding);
const ctx = { path };
const result = binding.readlink(pathModule.toNamespacedPath(path),
options.encoding, undefined, ctx);
if (ctx.errno !== undefined) {
throw new errors.uvException(ctx);
}
return result;
};

function preprocessSymlinkDestination(path, type, linkPath) {
Expand Down Expand Up @@ -1220,6 +1242,7 @@ fs.symlink = function(target, path, type_, callback_) {
const flags = stringToSymlinkType(type);
const req = new FSReqWrap();
req.oncomplete = callback;

binding.symlink(preprocessSymlinkDestination(target, type, path),
pathModule.toNamespacedPath(path), flags, req);
};
Expand All @@ -1234,8 +1257,19 @@ fs.symlinkSync = function(target, path, type) {
validatePath(target, 'target');
validatePath(path);
const flags = stringToSymlinkType(type);
return binding.symlink(preprocessSymlinkDestination(target, type, path),
pathModule.toNamespacedPath(path), flags);

const ctx = { path: target, dest: path };
binding.symlink(preprocessSymlinkDestination(target, type, path),
pathModule.toNamespacedPath(path), flags, undefined, ctx);

if (ctx.errno !== undefined) {
throw new errors.uvException(ctx);
} else if (ctx.error) {
// TODO(joyeecheung): this is an encoding error usually caused by memory
// problems. We need to figure out proper error code(s) for this.
Error.captureStackTrace(ctx.error);
throw ctx.error;
}
};

fs.link = function(existingPath, newPath, callback) {
Expand Down Expand Up @@ -1268,8 +1302,15 @@ fs.linkSync = function(existingPath, newPath) {
nullCheck(newPath);
validatePath(existingPath, 'existingPath');
validatePath(newPath, 'newPath');
return binding.link(pathModule.toNamespacedPath(existingPath),
pathModule.toNamespacedPath(newPath));

const ctx = { path: existingPath, dest: newPath };
const result = binding.link(pathModule.toNamespacedPath(existingPath),
pathModule.toNamespacedPath(newPath),
undefined, ctx);
if (ctx.errno !== undefined) {
throw new errors.uvException(ctx);
}
return result;
};

fs.unlink = function(path, callback) {
Expand All @@ -1287,7 +1328,11 @@ fs.unlinkSync = function(path) {
handleError((path = getPathFromURL(path)));
nullCheck(path);
validatePath(path);
return binding.unlink(pathModule.toNamespacedPath(path));
const ctx = { path };
binding.unlink(pathModule.toNamespacedPath(path), undefined, ctx);
if (ctx.errno !== undefined) {
throw new errors.uvException(ctx);
}
};

fs.fchmod = function(fd, mode, callback) {
Expand Down Expand Up @@ -1963,7 +2008,10 @@ fs.realpathSync = function realpathSync(p, options) {
if (ctx.errno !== undefined) {
throw new errors.uvException(ctx);
}
linkTarget = binding.readlink(baseLong);
linkTarget = binding.readlink(baseLong, undefined, undefined, ctx);
if (ctx.errno !== undefined) {
throw new errors.uvException(ctx);
}
}
resolvedLink = pathModule.resolve(previous, linkTarget);

Expand Down
131 changes: 85 additions & 46 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -598,29 +598,34 @@ static void FStat(const FunctionCallbackInfo<Value>& args) {
static void Symlink(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

CHECK_GE(args.Length(), 3);
int argc = args.Length();
CHECK_GE(argc, 4);

BufferValue target(env->isolate(), args[0]);
CHECK_NE(*target, nullptr);
BufferValue path(env->isolate(), args[1]);
CHECK_NE(*path, nullptr);

CHECK(args[2]->IsUint32());
int flags = args[2]->Uint32Value(env->context()).ToChecked();
CHECK(args[2]->IsInt32());
int flags = args[2].As<Int32>()->Value();

if (args[3]->IsObject()) { // symlink(target, path, flags, req)
CHECK_EQ(args.Length(), 4);
AsyncDestCall(env, args, "symlink", *path, path.length(), UTF8,
AfterNoArgs, uv_fs_symlink, *target, *path, flags);
} else { // symlink(target, path, flags)
SYNC_DEST_CALL(symlink, *target, *path, *target, *path, flags)
} else { // symlink(target, path, flags, undefinec, ctx)
CHECK_EQ(argc, 5);
fs_req_wrap req_wrap;
SyncCall(env, args[4], &req_wrap, "symlink",
uv_fs_symlink, *target, *path, flags);
}
}

static void Link(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

CHECK_GE(args.Length(), 2);
int argc = args.Length();
CHECK_GE(argc, 3);

BufferValue src(env->isolate(), args[0]);
CHECK_NE(*src, nullptr);
Expand All @@ -629,130 +634,164 @@ static void Link(const FunctionCallbackInfo<Value>& args) {
CHECK_NE(*dest, nullptr);

if (args[2]->IsObject()) { // link(src, dest, req)
CHECK_EQ(args.Length(), 3);
CHECK_EQ(argc, 3);
AsyncDestCall(env, args, "link", *dest, dest.length(), UTF8,
AfterNoArgs, uv_fs_link, *src, *dest);
} else { // link(src, dest)
SYNC_DEST_CALL(link, *src, *dest, *src, *dest)
} else { // link(src, dest, undefined, ctx)
CHECK_EQ(argc, 4);
fs_req_wrap req_wrap;
SyncCall(env, args[3], &req_wrap, "link",
uv_fs_link, *src, *dest);
}
}

static void ReadLink(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

const int argc = args.Length();

CHECK_GE(argc, 1);
int argc = args.Length();
CHECK_GE(argc, 3);

BufferValue path(env->isolate(), args[0]);
CHECK_NE(*path, nullptr);

const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);

if (args[2]->IsObject()) { // readlink(path, encoding, req)
CHECK_EQ(args.Length(), 3);
CHECK_EQ(argc, 3);
AsyncCall(env, args, "readlink", encoding, AfterStringPtr,
uv_fs_readlink, *path);
} else {
SYNC_CALL(readlink, *path, *path)
const char* link_path = static_cast<const char*>(SYNC_REQ.ptr);
} else { // readlink(path, encoding, undefined, ctx)
CHECK_EQ(argc, 4);
fs_req_wrap req_wrap;
int err = SyncCall(env, args[3], &req_wrap, "readlink",
uv_fs_readlink, *path);
if (err) {
return; // syscall failed, no need to continue, error info is in ctx
}
const char* link_path = static_cast<const char*>(req_wrap.req.ptr);

Local<Value> error;
MaybeLocal<Value> rc = StringBytes::Encode(env->isolate(),
link_path,
encoding,
&error);
if (rc.IsEmpty()) {
env->isolate()->ThrowException(error);
Local<Object> ctx = args[3].As<Object>();
ctx->Set(env->context(), env->error_string(), error).FromJust();
return;
}

args.GetReturnValue().Set(rc.ToLocalChecked());
}
}

static void Rename(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

CHECK_GE(args.Length(), 2);
int argc = args.Length();
CHECK_GE(argc, 3);

BufferValue old_path(env->isolate(), args[0]);
CHECK_NE(*old_path, nullptr);
BufferValue new_path(env->isolate(), args[1]);
CHECK_NE(*new_path, nullptr);

if (args[2]->IsObject()) {
CHECK_EQ(args.Length(), 3);
if (args[2]->IsObject()) { // rename(old_path, new_path, req)
CHECK_EQ(argc, 3);
AsyncDestCall(env, args, "rename", *new_path, new_path.length(),
UTF8, AfterNoArgs, uv_fs_rename, *old_path, *new_path);
} else {
SYNC_DEST_CALL(rename, *old_path, *new_path, *old_path, *new_path)
} else { // rename(old_path, new_path, undefined, ctx)
CHECK_EQ(argc, 4);
fs_req_wrap req_wrap;
SyncCall(env, args[3], &req_wrap, "rename",
uv_fs_rename, *old_path, *new_path);
}
}

static void FTruncate(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

const int argc = args.Length();
CHECK_GE(argc, 3);

CHECK(args[0]->IsInt32());
CHECK(args[1]->IsNumber());
const int fd = args[0].As<Int32>()->Value();

int fd = args[0]->Int32Value();
const int64_t len = args[1]->IntegerValue();
CHECK(args[1]->IsNumber());
const int64_t len = args[1].As<Integer>()->Value();

if (args[2]->IsObject()) {
CHECK_EQ(args.Length(), 3);
if (args[2]->IsObject()) { // ftruncate(fd, len, req)
CHECK_EQ(argc, 3);
AsyncCall(env, args, "ftruncate", UTF8, AfterNoArgs,
uv_fs_ftruncate, fd, len);
} else {
SYNC_CALL(ftruncate, 0, fd, len)
} else { // ftruncate(fd, len, undefined, ctx)
CHECK_EQ(argc, 4);
fs_req_wrap req_wrap;
SyncCall(env, args[3], &req_wrap, "ftruncate",
uv_fs_ftruncate, fd, len);
}
}

static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

CHECK(args[0]->IsInt32());
const int argc = args.Length();
CHECK_GE(argc, 2);

int fd = args[0]->Int32Value();
CHECK(args[0]->IsInt32());
const int fd = args[0].As<Int32>()->Value();

if (args[1]->IsObject()) {
CHECK_EQ(args.Length(), 2);
if (args[1]->IsObject()) { // fdatasync(fd, req)
CHECK_EQ(argc, 2);
AsyncCall(env, args, "fdatasync", UTF8, AfterNoArgs,
uv_fs_fdatasync, fd);
} else {
SYNC_CALL(fdatasync, 0, fd)
} else { // fdatasync(fd, undefined, ctx)
CHECK_EQ(argc, 3);
fs_req_wrap req_wrap;
SyncCall(env, args[2], &req_wrap, "fdatasync",
uv_fs_fdatasync, fd);
}
}

static void Fsync(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

CHECK(args[0]->IsInt32());
const int argc = args.Length();
CHECK_GE(argc, 2);

int fd = args[0]->Int32Value();
CHECK(args[0]->IsInt32());
const int fd = args[0].As<Int32>()->Value();

if (args[1]->IsObject()) {
CHECK_EQ(args.Length(), 2);
if (args[1]->IsObject()) { // fsync(fd, req)
CHECK_EQ(argc, 2);
AsyncCall(env, args, "fsync", UTF8, AfterNoArgs,
uv_fs_fsync, fd);
} else {
SYNC_CALL(fsync, 0, fd)
} else { // fsync(fd, undefined, ctx)
CHECK_EQ(argc, 3);
fs_req_wrap req_wrap;
SyncCall(env, args[2], &req_wrap, "fsync",
uv_fs_fsync, fd);
}
}

static void Unlink(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

CHECK_GE(args.Length(), 1);
const int argc = args.Length();
CHECK_GE(argc, 2);

BufferValue path(env->isolate(), args[0]);
CHECK_NE(*path, nullptr);

if (args[1]->IsObject()) {
CHECK_EQ(args.Length(), 2);
if (args[1]->IsObject()) { // unlink(fd, req)
CHECK_EQ(argc, 2);
AsyncCall(env, args, "unlink", UTF8, AfterNoArgs,
uv_fs_unlink, *path);
} else {
SYNC_CALL(unlink, *path, *path)
} else { // unlink(fd, undefined, ctx)
CHECK_EQ(argc, 3);
fs_req_wrap req_wrap;
SyncCall(env, args[2], &req_wrap, "unlink",
uv_fs_unlink, *path);
}
}

Expand Down
Loading