Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fs: migrate more fs.*Sync errors into JS land #18348

Closed
wants to merge 10 commits into from
40 changes: 34 additions & 6 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -1163,7 +1163,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: path };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use shorthand syntax?

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 +1226,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 +1241,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 +1286,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 Down Expand Up @@ -1963,7 +1988,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
49 changes: 32 additions & 17 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,43 +634,53 @@ 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());
}
}
Expand Down