details: https://github.com/nginx/njs/commit/1b2a339162817da195a3d8e631b61233c1aa57f0
branches: master
commit: 1b2a339162817da195a3d8e631b61233c1aa57f0
user: Dmitry Volyntsev <xeioex@nginx.com>
date: Fri, 18 Oct 2024 22:01:58 -0700
description:
FS: introduced fs.readlinkSync() and friends.
This closes #802 feature request on Github.
---
external/njs_fs_module.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++
test/fs/methods.t.js | 53 ++++++++++++++++++++
2 files changed, 181 insertions(+)
diff --git a/external/njs_fs_module.c b/external/njs_fs_module.c
index de378cee..f5221883 100644
--- a/external/njs_fs_module.c
+++ b/external/njs_fs_module.c
@@ -160,6 +160,8 @@ static njs_int_t njs_fs_read_file(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t calltype, njs_value_t *retval);
static njs_int_t njs_fs_readdir(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t calltype, njs_value_t *retval);
+static njs_int_t njs_fs_readlink(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t calltype, njs_value_t *retval);
static njs_int_t njs_fs_realpath(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t calltype, njs_value_t *retval);
static njs_int_t njs_fs_rename(njs_vm_t *vm, njs_value_t *args,
@@ -415,6 +417,17 @@ static njs_external_t njs_ext_fs_promises[] = {
}
},
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("readlink"),
+ .writable = 1,
+ .configurable = 1,
+ .u.method = {
+ .native = njs_fs_readlink,
+ .magic8 = NJS_FS_PROMISE,
+ }
+ },
+
{
.flags = NJS_EXTERN_METHOD,
.name.string = njs_str("realpath"),
@@ -726,6 +739,28 @@ static njs_external_t njs_ext_fs[] = {
}
},
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("readlink"),
+ .writable = 1,
+ .configurable = 1,
+ .u.method = {
+ .native = njs_fs_readlink,
+ .magic8 = NJS_FS_CALLBACK,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("readlinkSync"),
+ .writable = 1,
+ .configurable = 1,
+ .u.method = {
+ .native = njs_fs_readlink,
+ .magic8 = NJS_FS_DIRECT,
+ }
+ },
+
{
.flags = NJS_EXTERN_METHOD,
.name.string = njs_str("realpath"),
@@ -2035,6 +2070,99 @@ done:
}
+static njs_int_t
+njs_fs_readlink(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t calltype, njs_value_t *retval)
+{
+ ssize_t n;
+ njs_int_t ret;
+ njs_str_t s;
+ const char *path;
+ njs_value_t *callback, *options;
+ njs_opaque_value_t encode, result;
+ const njs_buffer_encoding_t *encoding;
+ char path_buf[NJS_MAX_PATH + 1],
+ dst_buf[NJS_MAX_PATH + 1];
+
+ path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path");
+ if (njs_slow_path(path == NULL)) {
+ return NJS_ERROR;
+ }
+
+ callback = NULL;
+ options = njs_arg(args, nargs, 2);
+
+ if (calltype == NJS_FS_CALLBACK) {
+ callback = njs_arg(args, nargs, njs_min(nargs - 1, 3));
+ if (!njs_value_is_function(callback)) {
+ njs_vm_type_error(vm, "\"callback\" must be a function");
+ return NJS_ERROR;
+ }
+
+ if (options == callback) {
+ options = njs_value_arg(&njs_value_undefined);
+ }
+ }
+
+ njs_value_undefined_set(njs_value_arg(&encode));
+
+ if (njs_value_is_string(options)) {
+ njs_value_assign(&encode, options);
+
+ } else if (!njs_value_is_undefined(options)) {
+ if (!njs_value_is_object(options)) {
+ njs_vm_type_error(vm, "Unknown options type "
+ "(a string or object required)");
+ return NJS_ERROR;
+ }
+
+ (void) njs_vm_object_prop(vm, options, &string_encoding, &encode);
+ }
+
+ encoding = NULL;
+
+ if (njs_value_is_string(njs_value_arg(&encode))) {
+ njs_value_string_get(njs_value_arg(&encode), &s);
+
+ } else {
+ s.length = 0;
+ s.start = NULL;
+ }
+
+ if (!njs_strstr_eq(&s, &string_buffer)) {
+ encoding = njs_buffer_encoding(vm, njs_value_arg(&encode), 1);
+ if (njs_slow_path(encoding == NULL)) {
+ return NJS_ERROR;
+ }
+ }
+
+ s.start = (u_char *) dst_buf;
+ n = readlink(path, dst_buf, sizeof(dst_buf) - 1);
+ if (njs_slow_path(n < 0)) {
+ ret = njs_fs_error(vm, "readlink", strerror(errno), path, errno,
+ &result);
+ goto done;
+ }
+
+ s.length = n;
+
+ if (encoding == NULL) {
+ ret = njs_buffer_new(vm, njs_value_arg(&result), s.start, s.length);
+
+ } else {
+ ret = encoding->encode(vm, njs_value_arg(&result), &s);
+ }
+
+done:
+
+ if (ret == NJS_OK) {
+ return njs_fs_result(vm, &result, calltype, callback, 2, retval);
+ }
+
+ return NJS_ERROR;
+}
+
+
static njs_int_t
njs_fs_realpath(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t calltype, njs_value_t *retval)
diff --git a/test/fs/methods.t.js b/test/fs/methods.t.js
index 1d177e18..72afb494 100644
--- a/test/fs/methods.t.js
+++ b/test/fs/methods.t.js
@@ -435,6 +435,56 @@ let realpathP_tsuite = {
get tests() { return realpath_tests() },
};
+async function readlink_test(params) {
+ let lname = params.args[0];
+ try { fs.unlinkSync(lname); } catch (e) {}
+ fs.symlinkSync("test/fs/ascii", lname);
+
+ let data = await method("readlink", params);
+
+ if (!params.check(data)) {
+ throw Error(`readlink failed check`);
+ }
+
+ return 'SUCCESS';
+}
+
+let readlink_tests = () => [
+ { args: [`${test_dir}/symlink`],
+ check: (data) => data.endsWith("test/fs/ascii") },
+ { args: [`${test_dir}/symlink`, {encoding:'buffer'}],
+ check: (data) => data instanceof Buffer },
+ { args: [`${test_dir}/symlink`, {encoding:'hex'}],
+ check: (data) => data.endsWith("746573742f66732f6173636969") },
+];
+
+let readlink_tsuite = {
+ name: "fs readlink",
+ skip: () => (!has_fs() || !has_buffer()),
+ T: readlink_test,
+ prepare_args: p,
+ opts: { type: "callback" },
+ get tests() { return readlink_tests() },
+};
+
+let readlinkSync_tsuite = {
+ name: "fs readlinkSync",
+ skip: () => (!has_fs() || !has_buffer()),
+ T: readlink_test,
+ prepare_args: p,
+ opts: { type: "sync" },
+ get tests() { return readlink_tests() },
+};
+
+let readlinkP_tsuite = {
+ name: "fsp readlink",
+ skip: () => (!has_fs() || !has_buffer()),
+ T: readlink_test,
+ prepare_args: p,
+ opts: { type: "promise" },
+ get tests() { return readlink_tests() },
+};
+
async function method_test(params) {
if (params.init) {
params.init(params);
@@ -1190,6 +1240,9 @@ run([
realpath_tsuite,
realpathSync_tsuite,
realpathP_tsuite,
+ readlink_tsuite,
+ readlinkSync_tsuite,
+ readlinkP_tsuite,
stat_tsuite,
statSync_tsuite,
statP_tsuite,
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel