From ac6594afb660aee6118cb08f57fe21e283186418 Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Tue, 21 Dec 2021 17:42:26 +0000 Subject: [PATCH] Refactor modules using external prototypes. --- auto/init | 3 + auto/make | 45 +- auto/module | 6 + auto/modules | 34 + auto/options | 2 + auto/sources | 4 - configure | 1 + {src => external}/njs_crypto.c | 533 +++--- {src => external}/njs_fs.c | 2600 ++++++++++++++------------ {src => external}/njs_query_string.c | 161 +- external/njs_webcrypto.c | 13 +- external/njs_webcrypto.h | 15 - nginx/config | 3 +- nginx/config.make | 2 +- nginx/ngx_http_js_module.c | 1 + nginx/ngx_js.c | 16 +- nginx/ngx_js.h | 3 + nginx/ngx_stream_js_module.c | 1 + src/njs.h | 9 + src/njs_buffer.c | 118 +- src/njs_buffer.h | 1 - src/njs_builtin.c | 118 +- src/njs_crypto.h | 16 - src/njs_fs.h | 16 - src/njs_main.h | 4 - src/njs_module.c | 60 +- src/njs_module.h | 4 +- src/njs_query_string.h | 12 - src/njs_shell.c | 41 +- src/njs_value.h | 2 - src/njs_vm.c | 25 +- src/njs_vm.h | 4 - src/test/njs_externals_test.c | 14 - src/test/njs_unit_test.c | 12 +- 34 files changed, 2045 insertions(+), 1854 deletions(-) create mode 100644 auto/module create mode 100644 auto/modules rename {src => external}/njs_crypto.c (61%) rename {src => external}/njs_fs.c (77%) rename {src => external}/njs_query_string.c (90%) delete mode 100644 external/njs_webcrypto.h delete mode 100644 src/njs_crypto.h delete mode 100644 src/njs_fs.h delete mode 100644 src/njs_query_string.h diff --git a/auto/init b/auto/init index 648ec261..4edea8b9 100644 --- a/auto/init +++ b/auto/init @@ -20,6 +20,9 @@ NJS_AUTOCONF_ERR=$NJS_BUILD_DIR/autoconf.err NJS_AUTO_CONFIG_H=$NJS_BUILD_DIR/njs_auto_config.h NJS_MAKEFILE=$NJS_BUILD_DIR/Makefile +NJS_LIB_MODULES= +NJS_LIB_INCS="src $NJS_BUILD_DIR" + test -d $NJS_BUILD_DIR || mkdir $NJS_BUILD_DIR > $NJS_AUTOCONF_ERR diff --git a/auto/make b/auto/make index 2aaafeac..dae84166 100644 --- a/auto/make +++ b/auto/make @@ -7,11 +7,44 @@ echo "creating $NJS_MAKEFILE" mkdir -p $NJS_BUILD_DIR/src +mkdir -p $NJS_BUILD_DIR/build +mkdir -p $NJS_BUILD_DIR/external mkdir -p $NJS_BUILD_DIR/test +njs_modules_c=$NJS_BUILD_DIR/njs_modules.c + +NJS_LIB_SRCS="$NJS_LIB_SRCS $njs_modules_c" + +njs_incs=`echo $NJS_LIB_INCS \ + | sed -e "s# *\([^ ]*\)#$njs_regex_cont-I\1#g"` njs_objs=`echo $NJS_LIB_SRCS \ | sed -e "s# *\([^ ]*\.\)c#$NJS_BUILD_DIR/\1o$njs_regex_cont#g"` +cat << END > $njs_modules_c + +#include + +END + +for mod in $NJS_LIB_MODULES +do + echo "extern njs_module_t $mod;" >> $njs_modules_c +done + +echo >> $njs_modules_c +echo 'njs_module_t *njs_modules[] = {' >> $njs_modules_c + +for mod in $NJS_LIB_MODULES +do + echo " &$mod," >> $njs_modules_c +done + +cat << END >> $njs_modules_c + NULL +}; + +END + cat << END > $NJS_MAKEFILE # This file is auto-generated by configure @@ -28,8 +61,7 @@ NPM = npm default: njs -NJS_LIB_INCS = -Isrc -I$NJS_BUILD_DIR - +NJS_LIB_INCS = $njs_incs NJS_LIB_OBJS = $njs_objs libnjs: $NJS_BUILD_DIR/libnjs.a @@ -46,9 +78,8 @@ END for njs_src in $NJS_LIB_SRCS do - fname=$(basename $njs_src) - njs_obj="src/${fname%.c}.o" - njs_dep="src/${fname%.c}.dep" + njs_obj="${njs_src%.c}.o" + njs_dep="${njs_src%.c}.dep" njs_dep_flags=`njs_gen_dep_flags $njs_dep $njs_obj` njs_dep_post=`njs_gen_dep_post $njs_dep $njs_obj` cat << END >> $NJS_MAKEFILE @@ -73,7 +104,7 @@ cat << END >> $NJS_MAKEFILE $NJS_BUILD_DIR/njs: \\ $NJS_BUILD_DIR/libnjs.a \\ - src/njs_shell.c external/njs_webcrypto.h external/njs_webcrypto.c + src/njs_shell.c \$(NJS_LINK) -o $NJS_BUILD_DIR/njs \$(NJS_CFLAGS) \\ $NJS_LIB_AUX_CFLAGS \$(NJS_LIB_INCS) -Injs \\ src/njs_shell.c \\ @@ -143,7 +174,7 @@ njs_dep_post=`njs_gen_dep_post $njs_dep $njs_externals_obj` cat << END >> $NJS_MAKEFILE $NJS_BUILD_DIR/$njs_externals_obj: \\ - $njs_src external/njs_webcrypto.h external/njs_webcrypto.c + $njs_src external/njs_webcrypto.c \$(NJS_CC) -c \$(NJS_CFLAGS) $NJS_LIB_AUX_CFLAGS \\ \$(NJS_LIB_INCS) -Injs \\ -o $NJS_BUILD_DIR/$njs_externals_obj \\ diff --git a/auto/module b/auto/module new file mode 100644 index 00000000..b830879c --- /dev/null +++ b/auto/module @@ -0,0 +1,6 @@ +# Copyright (C) Dmitry Volyntsev +# Copyright (C) NGINX, Inc. + +NJS_LIB_MODULES="$NJS_LIB_MODULES $njs_module_name" +NJS_LIB_SRCS="$NJS_LIB_SRCS $njs_module_srcs" +NJS_LIB_INCS="$NJS_LIB_INCS $njs_module_incs" diff --git a/auto/modules b/auto/modules new file mode 100644 index 00000000..4d46c664 --- /dev/null +++ b/auto/modules @@ -0,0 +1,34 @@ +# Copyright (C) Dmitry Volyntsev +# Copyright (C) NGINX, Inc. + +njs_module_name=njs_buffer_module +njs_module_incs= +njs_module_srcs=src/njs_buffer.c + +. auto/module + +njs_module_name=njs_crypto_module +njs_module_incs= +njs_module_srcs=external/njs_crypto.c + +. auto/module + +if [ $NJS_WEBCRYPTO = YES -a $NJS_HAVE_OPENSSL = YES ]; then + njs_module_name=njs_webcrypto_module + njs_module_incs= + njs_module_srcs=external/njs_webcrypto.c + + . auto/module +fi + +njs_module_name=njs_fs_module +njs_module_incs= +njs_module_srcs=external/njs_fs.c + +. auto/module + +njs_module_name=njs_query_string_module +njs_module_incs= +njs_module_srcs=external/njs_query_string.c + +. auto/module diff --git a/auto/options b/auto/options index f4b3cad1..11c1ff0c 100644 --- a/auto/options +++ b/auto/options @@ -11,6 +11,7 @@ NJS_DEBUG_MEMORY=NO NJS_ADDRESS_SANITIZER=NO NJS_TEST262=YES +NJS_WEBCRYPTO=YES NJS_TRY_PCRE2=YES NJS_CONFIGURE_OPTIONS= @@ -33,6 +34,7 @@ do --debug-memory=*) NJS_DEBUG_MEMORY="$value" ;; --test262=*) NJS_TEST262="$value" ;; + --no-webcrypto) NJS_WEBCRYPTO=NO ;; --no-pcre2) NJS_TRY_PCRE2=NO ;; --help) diff --git a/auto/sources b/auto/sources index 18f56883..21ca3345 100644 --- a/auto/sources +++ b/auto/sources @@ -42,8 +42,6 @@ NJS_LIB_SRCS=" \ src/njs_timer.c \ src/njs_module.c \ src/njs_event.c \ - src/njs_fs.c \ - src/njs_crypto.c \ src/njs_extern.c \ src/njs_variable.c \ src/njs_builtin.c \ @@ -55,9 +53,7 @@ NJS_LIB_SRCS=" \ src/njs_array_buffer.c \ src/njs_typed_array.c \ src/njs_promise.c \ - src/njs_query_string.c \ src/njs_encoding.c \ - src/njs_buffer.c \ src/njs_iterator.c \ src/njs_scope.c \ src/njs_async.c \ diff --git a/configure b/configure index 5ff6738f..5fb5af00 100755 --- a/configure +++ b/configure @@ -35,6 +35,7 @@ NJS_LIB_AUX_CFLAGS="$NJS_PCRE_CFLAGS" NJS_LIBS="$NJS_LIBRT" NJS_LIB_AUX_LIBS="$NJS_PCRE_LIB $NJS_OPENSSL_LIB" +. auto/modules . auto/make . auto/expect diff --git a/src/njs_crypto.c b/external/njs_crypto.c similarity index 61% rename from src/njs_crypto.c rename to external/njs_crypto.c index 0b65f0ed..28b0868b 100644 --- a/src/njs_crypto.c +++ b/external/njs_crypto.c @@ -61,6 +61,16 @@ static njs_crypto_enc_t *njs_crypto_encoding(njs_vm_t *vm, const njs_value_t *value); static njs_int_t njs_buffer_digest(njs_vm_t *vm, njs_value_t *value, const njs_str_t *src); +static njs_int_t njs_crypto_create_hash(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t unused); +static njs_int_t njs_hash_prototype_update(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t hmac); +static njs_int_t njs_hash_prototype_digest(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t hmac); +static njs_int_t njs_crypto_create_hmac(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t unused); + +static njs_int_t njs_crypto_init(njs_vm_t *vm); static njs_hash_alg_t njs_hash_algorithms[] = { @@ -129,24 +139,145 @@ static njs_crypto_enc_t njs_encodings[] = { }; +static njs_external_t njs_ext_crypto_hash[] = { + + { + .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL, + .name.symbol = NJS_SYMBOL_TO_STRING_TAG, + .u.property = { + .value = "Hash", + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("update"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_hash_prototype_update, + .magic8 = 0, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("digest"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_hash_prototype_digest, + .magic8 = 0, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("constructor"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_crypto_create_hash, + } + }, +}; + + +static njs_external_t njs_ext_crypto_hmac[] = { + + { + .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL, + .name.symbol = NJS_SYMBOL_TO_STRING_TAG, + .u.property = { + .value = "Hmac", + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("update"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_hash_prototype_update, + .magic8 = 1, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("digest"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_hash_prototype_digest, + .magic8 = 1, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("constructor"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_crypto_create_hmac, + .magic8 = 0, + } + }, +}; + + +static njs_external_t njs_ext_crypto_crypto[] = { + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("createHash"), + .writable = 1, + .configurable = 1, + .enumerable = 1, + .u.method = { + .native = njs_crypto_create_hash, + .magic8 = 0, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("createHmac"), + .writable = 1, + .configurable = 1, + .enumerable = 1, + .u.method = { + .native = njs_crypto_create_hmac, + .magic8 = 0, + } + }, +}; + + +static njs_int_t njs_crypto_hash_proto_id; +static njs_int_t njs_crypto_hmac_proto_id; + + +njs_module_t njs_crypto_module = { + .name = njs_str("crypto"), + .init = njs_crypto_init, +}; + + static njs_int_t njs_crypto_create_hash(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - njs_digest_t *dgst; - njs_hash_alg_t *alg; - njs_object_value_t *hash; + njs_digest_t *dgst; + njs_hash_alg_t *alg; alg = njs_crypto_algorithm(vm, njs_arg(args, nargs, 1)); if (njs_slow_path(alg == NULL)) { return NJS_ERROR; } - hash = njs_object_value_alloc(vm, NJS_OBJ_TYPE_CRYPTO_HASH, 0, NULL); - if (njs_slow_path(hash == NULL)) { - return NJS_ERROR; - } - dgst = njs_mp_alloc(vm->mem_pool, sizeof(njs_digest_t)); if (njs_slow_path(dgst == NULL)) { njs_memory_error(vm); @@ -157,16 +288,14 @@ njs_crypto_create_hash(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, alg->init(&dgst->u); - njs_set_data(&hash->value, dgst, NJS_DATA_TAG_CRYPTO_HASH); - njs_set_object_value(&vm->retval, hash); - - return NJS_OK; + return njs_vm_external_create(vm, &vm->retval, njs_crypto_hash_proto_id, + dgst, 0); } static njs_int_t njs_hash_prototype_update(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, - njs_index_t tag) + njs_index_t hmac) { njs_str_t data; njs_int_t ret; @@ -179,9 +308,34 @@ njs_hash_prototype_update(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, const njs_buffer_encoding_t *encoding; this = njs_argument(args, 0); - if (njs_slow_path(!njs_is_object_data(this, tag))) { - njs_type_error(vm, "\"this\" is not a hash object"); - return NJS_ERROR; + + if (!hmac) { + dgst = njs_vm_external(vm, njs_crypto_hash_proto_id, this); + if (njs_slow_path(dgst == NULL)) { + njs_type_error(vm, "\"this\" is not a hash object"); + return NJS_ERROR; + } + + if (njs_slow_path(dgst->alg == NULL)) { + njs_error(vm, "Digest already called"); + return NJS_ERROR; + } + + ctx = NULL; + + } else { + ctx = njs_vm_external(vm, njs_crypto_hmac_proto_id, this); + if (njs_slow_path(ctx == NULL)) { + njs_type_error(vm, "\"this\" is not a hmac object"); + return NJS_ERROR; + } + + if (njs_slow_path(ctx->alg == NULL)) { + njs_error(vm, "Digest already called"); + return NJS_ERROR; + } + + dgst = NULL; } value = njs_arg(args, nargs, 1); @@ -221,22 +375,10 @@ njs_hash_prototype_update(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_ERROR; } - if (tag == NJS_DATA_TAG_CRYPTO_HASH) { - dgst = njs_object_data(this); - if (njs_slow_path(dgst->alg == NULL)) { - njs_error(vm, "Digest already called"); - return NJS_ERROR; - } - + if (!hmac) { dgst->alg->update(&dgst->u, data.start, data.length); } else { - ctx = njs_object_data(this); - if (njs_slow_path(ctx->alg == NULL)) { - njs_error(vm, "Digest already called"); - return NJS_ERROR; - } - ctx->alg->update(&ctx->u, data.start, data.length); } @@ -248,7 +390,7 @@ njs_hash_prototype_update(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, static njs_int_t njs_hash_prototype_digest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, - njs_index_t tag) + njs_index_t hmac) { njs_str_t str; njs_hmac_t *ctx; @@ -259,32 +401,45 @@ njs_hash_prototype_digest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, u_char hash1[32], digest[32]; this = njs_argument(args, 0); - if (njs_slow_path(!njs_is_object_data(this, tag))) { - njs_type_error(vm, "\"this\" is not a hash object"); - return NJS_ERROR; - } - enc = njs_crypto_encoding(vm, njs_arg(args, nargs, 1)); - if (njs_slow_path(enc == NULL)) { - return NJS_ERROR; - } + if (!hmac) { + dgst = njs_vm_external(vm, njs_crypto_hash_proto_id, this); + if (njs_slow_path(dgst == NULL)) { + njs_type_error(vm, "\"this\" is not a hash object"); + return NJS_ERROR; + } - if (tag == NJS_DATA_TAG_CRYPTO_HASH) { - dgst = njs_object_data(this); if (njs_slow_path(dgst->alg == NULL)) { goto exception; } - alg = dgst->alg; - alg->final(digest, &dgst->u); - dgst->alg = NULL; + ctx = NULL; } else { - ctx = njs_object_data(this); + ctx = njs_vm_external(vm, njs_crypto_hmac_proto_id, this); + if (njs_slow_path(ctx == NULL)) { + njs_type_error(vm, "\"this\" is not a hmac object"); + return NJS_ERROR; + } + if (njs_slow_path(ctx->alg == NULL)) { goto exception; } + dgst = NULL; + } + + enc = njs_crypto_encoding(vm, njs_arg(args, nargs, 1)); + if (njs_slow_path(enc == NULL)) { + return NJS_ERROR; + } + + if (!hmac) { + alg = dgst->alg; + alg->final(digest, &dgst->u); + dgst->alg = NULL; + + } else { alg = ctx->alg; alg->final(hash1, &ctx->u); @@ -307,103 +462,6 @@ exception: } -static const njs_object_prop_t njs_hash_prototype_properties[] = -{ - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_string("Hash"), - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_wellknown_symbol(NJS_SYMBOL_TO_STRING_TAG), - .value = njs_string("Hash"), - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("update"), - .value = njs_native_function2(njs_hash_prototype_update, 0, - NJS_DATA_TAG_CRYPTO_HASH), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("digest"), - .value = njs_native_function2(njs_hash_prototype_digest, 0, - NJS_DATA_TAG_CRYPTO_HASH), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("constructor"), - .value = njs_prop_handler(njs_object_prototype_create_constructor), - .writable = 1, - .configurable = 1, - }, -}; - - -const njs_object_init_t njs_hash_prototype_init = { - njs_hash_prototype_properties, - njs_nitems(njs_hash_prototype_properties), -}; - - -static njs_int_t -njs_hash_constructor(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused) -{ - return njs_crypto_create_hash(vm, args, nargs, unused); -} - - -static const njs_object_prop_t njs_hash_constructor_properties[] = -{ - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_string("Hash"), - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("length"), - .value = njs_value(NJS_NUMBER, 1, 2.0), - .configurable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("prototype"), - .value = njs_prop_handler(njs_object_prototype_create), - }, -}; - - -const njs_object_init_t njs_hash_constructor_init = { - njs_hash_constructor_properties, - njs_nitems(njs_hash_constructor_properties), -}; - - -const njs_object_type_init_t njs_hash_type_init = { - .constructor = njs_native_ctor(njs_hash_constructor, 2, 0), - .constructor_props = &njs_hash_constructor_init, - .prototype_props = &njs_hash_prototype_init, - .prototype_value = { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), - .object = { .type = NJS_OBJECT } } }, -}; - - static njs_int_t njs_crypto_create_hmac(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) @@ -415,7 +473,6 @@ njs_crypto_create_hmac(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_typed_array_t *array; const njs_value_t *value; njs_array_buffer_t *buffer; - njs_object_value_t *hmac; u_char digest[32], key_buf[64]; alg = njs_crypto_algorithm(vm, njs_arg(args, nargs, 1)); @@ -483,155 +540,11 @@ njs_crypto_create_hmac(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, alg->init(&ctx->u); alg->update(&ctx->u, key_buf, 64); - hmac = njs_object_value_alloc(vm, NJS_OBJ_TYPE_CRYPTO_HMAC, 0, NULL); - if (njs_slow_path(hmac == NULL)) { - return NJS_ERROR; - } - - njs_set_data(&hmac->value, ctx, NJS_DATA_TAG_CRYPTO_HMAC); - njs_set_object_value(&vm->retval, hmac); - - return NJS_OK; -} - - -static const njs_object_prop_t njs_hmac_prototype_properties[] = -{ - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_string("Hmac"), - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_wellknown_symbol(NJS_SYMBOL_TO_STRING_TAG), - .value = njs_string("Hmac"), - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("update"), - .value = njs_native_function2(njs_hash_prototype_update, 0, - NJS_DATA_TAG_CRYPTO_HMAC), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("digest"), - .value = njs_native_function2(njs_hash_prototype_digest, 0, - NJS_DATA_TAG_CRYPTO_HMAC), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("constructor"), - .value = njs_prop_handler(njs_object_prototype_create_constructor), - .writable = 1, - .configurable = 1, - }, -}; - - -const njs_object_init_t njs_hmac_prototype_init = { - njs_hmac_prototype_properties, - njs_nitems(njs_hmac_prototype_properties), -}; - - -static njs_int_t -njs_hmac_constructor(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused) -{ - return njs_crypto_create_hmac(vm, args, nargs, unused); + return njs_vm_external_create(vm, &vm->retval, njs_crypto_hmac_proto_id, + ctx, 0); } -static const njs_object_prop_t njs_hmac_constructor_properties[] = -{ - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_string("Hmac"), - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("length"), - .value = njs_value(NJS_NUMBER, 1, 3.0), - .configurable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("prototype"), - .value = njs_prop_handler(njs_object_prototype_create), - }, -}; - - -const njs_object_init_t njs_hmac_constructor_init = { - njs_hmac_constructor_properties, - njs_nitems(njs_hmac_constructor_properties), -}; - - -static const njs_object_prop_t njs_crypto_object_properties[] = -{ - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_string("crypto"), - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("sandbox"), - .value = njs_value(NJS_BOOLEAN, 1, 1.0), - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("createHash"), - .value = njs_native_function(njs_crypto_create_hash, 0), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("createHmac"), - .value = njs_native_function(njs_crypto_create_hmac, 0), - .writable = 1, - .configurable = 1, - }, - -}; - - -const njs_object_init_t njs_crypto_object_init = { - njs_crypto_object_properties, - njs_nitems(njs_crypto_object_properties), -}; - - -const njs_object_type_init_t njs_hmac_type_init = { - .constructor = njs_native_ctor(njs_hmac_constructor, 3, 0), - .constructor_props = &njs_hmac_constructor_init, - .prototype_props = &njs_hmac_prototype_init, - .prototype_value = { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), - .object = { .type = NJS_OBJECT } } }, -}; - - static njs_hash_alg_t * njs_crypto_algorithm(njs_vm_t *vm, const njs_value_t *value) { @@ -691,3 +604,47 @@ njs_buffer_digest(njs_vm_t *vm, njs_value_t *value, const njs_str_t *src) { return njs_buffer_new(vm, value, src->start, src->length); } + + +static njs_int_t +njs_crypto_init(njs_vm_t *vm) +{ + njs_int_t ret, proto_id; + njs_mod_t *module; + njs_opaque_value_t value; + + njs_crypto_hash_proto_id = + njs_vm_external_prototype(vm, njs_ext_crypto_hash, + njs_nitems(njs_ext_crypto_hash)); + if (njs_slow_path(njs_crypto_hash_proto_id < 0)) { + return NJS_ERROR; + } + + njs_crypto_hmac_proto_id = + njs_vm_external_prototype(vm, njs_ext_crypto_hmac, + njs_nitems(njs_ext_crypto_hmac)); + if (njs_slow_path(njs_crypto_hmac_proto_id < 0)) { + return NJS_ERROR; + } + + proto_id = njs_vm_external_prototype(vm, njs_ext_crypto_crypto, + njs_nitems(njs_ext_crypto_crypto)); + if (njs_slow_path(proto_id < 0)) { + return NJS_ERROR; + } + + ret = njs_vm_external_create(vm, njs_value_arg(&value), proto_id, NULL, 1); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + + module = njs_module_add(vm, &njs_str_value("crypto"), 1); + if (njs_slow_path(module == NULL)) { + return NJS_ERROR; + } + + njs_value_assign(&module->value, &value); + module->function.native = 1; + + return NJS_OK; +} diff --git a/src/njs_fs.c b/external/njs_fs.c similarity index 77% rename from src/njs_fs.c rename to external/njs_fs.c index 129978f8..e76ac154 100644 --- a/src/njs_fs.c +++ b/external/njs_fs.c @@ -36,6 +36,9 @@ #define njs_fs_magic(calltype, mode) \ (((mode) << 2) | calltype) +#define njs_fs_magic2(field, type) \ + (((type) << 4) | field) + typedef enum { NJS_FS_DIRECT, @@ -126,6 +129,46 @@ typedef njs_int_t (*njs_file_tree_walk_cb_t)(const char *, const struct stat *, njs_ftw_type_t); +static njs_int_t njs_fs_access(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t calltype); +static njs_int_t njs_fs_mkdir(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t calltype); +static njs_int_t njs_fs_read(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t calltype); +static njs_int_t njs_fs_readdir(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t calltype); +static njs_int_t njs_fs_realpath(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t calltype); +static njs_int_t njs_fs_rename(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t calltype); +static njs_int_t njs_fs_rmdir(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t calltype); +static njs_int_t njs_fs_stat(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t calltype); +static njs_int_t njs_fs_symlink(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t calltype); +static njs_int_t njs_fs_unlink(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t calltype); +static njs_int_t njs_fs_write(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t calltype); + +static njs_int_t njs_fs_constants(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *unused, njs_value_t *retval); +static njs_int_t njs_fs_promises(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *unused, njs_value_t *retval); + +static njs_int_t njs_fs_dirent_constructor(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t unused); +static njs_int_t njs_fs_dirent_test(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t testtype); + +static njs_int_t njs_fs_stats_test(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t testtype); +static njs_int_t njs_fs_stats_prop(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval); +static njs_int_t njs_fs_stats_create(njs_vm_t *vm, struct stat *st, + njs_value_t *retval); + static njs_int_t njs_fs_fd_read(njs_vm_t *vm, int fd, njs_str_t *data); static njs_int_t njs_fs_error(njs_vm_t *vm, const char *syscall, @@ -153,8 +196,16 @@ static njs_int_t njs_fs_add_event(njs_vm_t *vm, const njs_value_t *callback, static njs_int_t njs_fs_dirent_create(njs_vm_t *vm, njs_value_t *name, njs_value_t *type, njs_value_t *retval); -static njs_int_t njs_fs_stats_create(njs_vm_t *vm, struct stat *st, - njs_value_t *retval); + +static njs_int_t njs_fs_init(njs_vm_t *vm); + + +static const njs_value_t string_flag = njs_string("flag"); +static const njs_value_t string_mode = njs_string("mode"); +static const njs_value_t string_buffer = njs_string("buffer"); +static const njs_value_t string_encoding = njs_string("encoding"); +static const njs_value_t string_recursive = njs_string("recursive"); + static njs_fs_entry_t njs_flags_table[] = { { njs_str("a"), O_APPEND | O_CREAT | O_WRONLY }, @@ -174,162 +225,714 @@ static njs_fs_entry_t njs_flags_table[] = { }; -static const njs_value_t string_flag = njs_string("flag"); -static const njs_value_t string_mode = njs_string("mode"); -static const njs_value_t string_buffer = njs_string("buffer"); -static const njs_value_t string_encoding = njs_string("encoding"); -static const njs_value_t string_recursive = njs_string("recursive"); +static njs_external_t njs_ext_fs[] = { + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("access"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_access, + .magic8 = NJS_FS_CALLBACK, + } + }, -static njs_int_t -njs_fs_read_file(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, - njs_index_t calltype) -{ - int fd, flags; - njs_str_t data; - njs_int_t ret; - const char *path; - njs_value_t flag, encode, retval, *callback, *options; - struct stat sb; - const njs_buffer_encoding_t *encoding; - char path_buf[NJS_MAX_PATH + 1]; + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("accessSync"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_access, + .magic8 = NJS_FS_DIRECT, + } + }, - path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path"); - if (njs_slow_path(path == NULL)) { - return NJS_ERROR; - } + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("appendFile"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_write, + .magic8 = njs_fs_magic(NJS_FS_CALLBACK, NJS_FS_APPEND), + } + }, - callback = NULL; + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("appendFileSync"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_write, + .magic8 = njs_fs_magic(NJS_FS_DIRECT, NJS_FS_APPEND), + } + }, - options = njs_arg(args, nargs, 2); + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("constants"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_constants, + } + }, - if (calltype == NJS_FS_CALLBACK) { - callback = njs_arg(args, nargs, njs_min(nargs - 1, 3)); - if (!njs_is_function(callback)) { - njs_type_error(vm, "\"callback\" must be a function"); - return NJS_ERROR; + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("Dirent"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_dirent_constructor, + .ctor = 1, } + }, - if (options == callback) { - options = njs_value_arg(&njs_value_undefined); + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("lstat"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_stat, + .magic8 = njs_fs_magic(NJS_FS_CALLBACK, NJS_FS_LSTAT), } - } + }, - njs_set_undefined(&flag); - njs_set_undefined(&encode); + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("lstatSync"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_stat, + .magic8 = njs_fs_magic(NJS_FS_DIRECT, NJS_FS_LSTAT), + } + }, - switch (options->type) { - case NJS_STRING: - encode = *options; - break; + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("mkdir"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_mkdir, + .magic8 = NJS_FS_CALLBACK, + } + }, - case NJS_UNDEFINED: - break; + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("mkdirSync"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_mkdir, + .magic8 = NJS_FS_DIRECT, + } + }, - default: - if (!njs_is_object(options)) { - njs_type_error(vm, "Unknown options type: \"%s\" " - "(a string or object required)", - njs_type_string(options->type)); - return NJS_ERROR; + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("promises"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_promises, } + }, - ret = njs_value_property(vm, options, njs_value_arg(&string_flag), - &flag); - if (njs_slow_path(ret == NJS_ERROR)) { - return ret; + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("readdir"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_readdir, + .magic8 = NJS_FS_CALLBACK, } + }, - ret = njs_value_property(vm, options, njs_value_arg(&string_encoding), - &encode); - if (njs_slow_path(ret == NJS_ERROR)) { - return ret; + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("readdirSync"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_readdir, + .magic8 = NJS_FS_DIRECT, } - } + }, - flags = njs_fs_flags(vm, &flag, O_RDONLY); - if (njs_slow_path(flags == -1)) { - return NJS_ERROR; - } + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("readFile"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_read, + .magic8 = NJS_FS_CALLBACK, + } + }, - encoding = NULL; - if (njs_is_defined(&encode)) { - encoding = njs_buffer_encoding(vm, &encode); - if (njs_slow_path(encoding == NULL)) { - return NJS_ERROR; + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("readFileSync"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_read, + .magic8 = NJS_FS_DIRECT, } - } + }, - fd = open(path, flags); - if (njs_slow_path(fd < 0)) { - ret = njs_fs_error(vm, "open", strerror(errno), path, errno, &retval); - goto done; - } + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("realpath"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_realpath, + .magic8 = NJS_FS_CALLBACK, + } + }, - ret = fstat(fd, &sb); - if (njs_slow_path(ret == -1)) { - ret = njs_fs_error(vm, "stat", strerror(errno), path, errno, &retval); - goto done; - } + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("realpathSync"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_realpath, + .magic8 = NJS_FS_DIRECT, + } + }, - if (njs_slow_path(!S_ISREG(sb.st_mode))) { - ret = njs_fs_error(vm, "stat", "File is not regular", path, 0, &retval); - goto done; - } + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("rename"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_rename, + .magic8 = NJS_FS_CALLBACK, + } + }, - data.start = NULL; - data.length = sb.st_size; + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("renameSync"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_rename, + .magic8 = NJS_FS_DIRECT, + } + }, - ret = njs_fs_fd_read(vm, fd, &data); - if (njs_slow_path(ret != NJS_OK)) { - if (ret == NJS_DECLINED) { - ret = njs_fs_error(vm, "read", strerror(errno), path, errno, - &retval); + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("rmdir"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_rmdir, + .magic8 = NJS_FS_CALLBACK, } + }, - goto done; - } + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("rmdirSync"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_rmdir, + .magic8 = NJS_FS_DIRECT, + } + }, - if (encoding == NULL) { - ret = njs_buffer_set(vm, &retval, data.start, data.length); + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("stat"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_stat, + .magic8 = njs_fs_magic(NJS_FS_CALLBACK, NJS_FS_STAT), + } + }, - } else { - ret = encoding->encode(vm, &retval, &data); - njs_mp_free(vm->mem_pool, data.start); - } + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("statSync"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_stat, + .magic8 = njs_fs_magic(NJS_FS_DIRECT, NJS_FS_STAT), + } + }, -done: + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("symlink"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_symlink, + .magic8 = NJS_FS_CALLBACK, + } + }, - if (fd != -1) { - (void) close(fd); - } + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("symlinkSync"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_symlink, + .magic8 = NJS_FS_DIRECT, + } + }, - if (ret == NJS_OK) { - return njs_fs_result(vm, &retval, calltype, callback, 2); - } + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("unlink"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_unlink, + .magic8 = NJS_FS_CALLBACK, + } + }, - return NJS_ERROR; -} + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("unlinkSync"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_unlink, + .magic8 = NJS_FS_DIRECT, + } + }, + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("writeFile"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_write, + .magic8 = njs_fs_magic(NJS_FS_CALLBACK, NJS_FS_TRUNC), + } + }, -static njs_int_t -njs_fs_write_file(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, - njs_index_t magic) -{ - int fd, flags; - u_char *p, *end; - mode_t md; - ssize_t n; - njs_str_t content; - njs_int_t ret; - const char *path; - njs_value_t flag, mode, encode, retval, *data, *callback, - *options; - njs_typed_array_t *array; - njs_fs_calltype_t calltype; - njs_array_buffer_t *buffer; - const njs_buffer_encoding_t *encoding; - char path_buf[NJS_MAX_PATH + 1]; + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("writeFileSync"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_write, + .magic8 = njs_fs_magic(NJS_FS_DIRECT, NJS_FS_TRUNC), + } + }, + +}; + + +static njs_external_t njs_ext_dirent[] = { + + { + .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL, + .name.symbol = NJS_SYMBOL_TO_STRING_TAG, + .u.property = { + .value = "Dirent", + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("constructor"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_dirent_constructor, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("isBlockDevice"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_dirent_test, + .magic8 = DT_BLK, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("isCharacterDevice"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_dirent_test, + .magic8 = DT_CHR, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("isDirectory"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_dirent_test, + .magic8 = DT_DIR, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("isFIFO"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_dirent_test, + .magic8 = DT_FIFO, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("isFile"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_dirent_test, + .magic8 = DT_REG, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("isSocket"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_dirent_test, + .magic8 = DT_SOCK, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("isSymbolicLink"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_dirent_test, + .magic8 = DT_LNK, + } + }, +}; + + +static njs_external_t njs_ext_stats[] = { + + { + .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL, + .name.symbol = NJS_SYMBOL_TO_STRING_TAG, + .u.property = { + .value = "Stats", + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("atime"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_stats_prop, + .magic32 = njs_fs_magic2(NJS_FS_STAT_ATIME, NJS_DATE), + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("atimeMs"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_stats_prop, + .magic32 = njs_fs_magic2(NJS_FS_STAT_ATIME, NJS_NUMBER), + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("birthtime"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_stats_prop, + .magic32 = njs_fs_magic2(NJS_FS_STAT_BIRTHTIME, NJS_DATE), + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("birthtimeMs"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_stats_prop, + .magic32 = njs_fs_magic2(NJS_FS_STAT_BIRTHTIME, NJS_NUMBER), + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("ctime"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_stats_prop, + .magic32 = njs_fs_magic2(NJS_FS_STAT_CTIME, NJS_DATE), + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("ctimeMs"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_stats_prop, + .magic32 = njs_fs_magic2(NJS_FS_STAT_CTIME, NJS_NUMBER), + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("blksize"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_stats_prop, + .magic32 = njs_fs_magic2(NJS_FS_STAT_BLKSIZE, NJS_NUMBER), + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("blocks"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_stats_prop, + .magic32 = njs_fs_magic2(NJS_FS_STAT_BLOCKS, NJS_NUMBER), + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("dev"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_stats_prop, + .magic32 = njs_fs_magic2(NJS_FS_STAT_DEV, NJS_NUMBER), + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("gid"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_stats_prop, + .magic32 = njs_fs_magic2(NJS_FS_STAT_GID, NJS_NUMBER), + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("ino"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_stats_prop, + .magic32 = njs_fs_magic2(NJS_FS_STAT_INO, NJS_NUMBER), + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("mode"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_stats_prop, + .magic32 = njs_fs_magic2(NJS_FS_STAT_MODE, NJS_NUMBER), + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("mtime"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_stats_prop, + .magic32 = njs_fs_magic2(NJS_FS_STAT_MTIME, NJS_DATE), + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("mtimeMs"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_stats_prop, + .magic32 = njs_fs_magic2(NJS_FS_STAT_MTIME, NJS_NUMBER), + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("nlink"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_stats_prop, + .magic32 = njs_fs_magic2(NJS_FS_STAT_NLINK, NJS_NUMBER), + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("rdev"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_stats_prop, + .magic32 = njs_fs_magic2(NJS_FS_STAT_RDEV, NJS_NUMBER), + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("size"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_stats_prop, + .magic32 = njs_fs_magic2(NJS_FS_STAT_SIZE, NJS_NUMBER), + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("uid"), + .enumerable = 1, + .u.property = { + .handler = njs_fs_stats_prop, + .magic32 = njs_fs_magic2(NJS_FS_STAT_UID, NJS_NUMBER), + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("isBlockDevice"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_stats_test, + .magic8 = DT_BLK, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("isCharacterDevice"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_stats_test, + .magic8 = DT_CHR, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("isDirectory"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_stats_test, + .magic8 = DT_DIR, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("isFIFO"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_stats_test, + .magic8 = DT_FIFO, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("isFile"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_stats_test, + .magic8 = DT_REG, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("isSocket"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_stats_test, + .magic8 = DT_SOCK, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("isSymbolicLink"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_fs_stats_test, + .magic8 = DT_LNK, + } + }, + +}; + + +static njs_int_t njs_fs_stats_proto_id; +static njs_int_t njs_fs_dirent_proto_id; + + +njs_module_t njs_fs_module = { + .name = njs_str("fs"), + .init = njs_fs_init, +}; + + +static njs_int_t +njs_fs_access(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_index_t calltype) +{ + int md; + njs_int_t ret; + const char *path; + njs_value_t retval, *callback, *mode; + char path_buf[NJS_MAX_PATH + 1]; path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path"); if (njs_slow_path(path == NULL)) { @@ -337,28 +940,84 @@ njs_fs_write_file(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } callback = NULL; - calltype = magic & 3; - options = njs_arg(args, nargs, 3); + mode = njs_arg(args, nargs, 2); if (calltype == NJS_FS_CALLBACK) { - callback = njs_arg(args, nargs, njs_min(nargs - 1, 4)); + callback = njs_arg(args, nargs, njs_min(nargs - 1, 3)); if (!njs_is_function(callback)) { njs_type_error(vm, "\"callback\" must be a function"); return NJS_ERROR; } + if (mode == callback) { + mode = njs_value_arg(&njs_value_undefined); + } + } + + switch (mode->type) { + case NJS_UNDEFINED: + md = F_OK; + break; + + case NJS_NUMBER: + md = njs_number(mode); + break; + + default: + njs_type_error(vm, "\"mode\" must be a number"); + return NJS_ERROR; + } + + njs_set_undefined(&retval); + + ret = access(path, md); + if (njs_slow_path(ret != 0)) { + ret = njs_fs_error(vm, "access", strerror(errno), path, errno, &retval); + } + + if (ret == NJS_OK) { + return njs_fs_result(vm, &retval, calltype, callback, 1); + } + + return NJS_ERROR; +} + + +static njs_int_t +njs_fs_mkdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_index_t calltype) +{ + char *path; + mode_t md; + njs_int_t ret; + njs_value_t mode, recursive, retval, *callback, *options; + char path_buf[NJS_MAX_PATH + 1]; + + path = (char *) 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 (njs_slow_path(calltype == NJS_FS_CALLBACK)) { + callback = njs_arg(args, nargs, njs_min(nargs - 1, 3)); + if (!njs_is_function(callback)) { + njs_type_error(vm, "\"callback\" must be a function"); + return NJS_ERROR; + } if (options == callback) { options = njs_value_arg(&njs_value_undefined); } } - njs_set_undefined(&flag); njs_set_undefined(&mode); - njs_set_undefined(&encode); + njs_set_false(&recursive); switch (options->type) { - case NJS_STRING: - encode = *options; + case NJS_NUMBER: + mode = *options; break; case NJS_UNDEFINED: @@ -367,158 +1026,164 @@ njs_fs_write_file(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, default: if (!njs_is_object(options)) { njs_type_error(vm, "Unknown options type: \"%s\" " - "(a string or object required)", + "(a number or object required)", njs_type_string(options->type)); return NJS_ERROR; } - ret = njs_value_property(vm, options, njs_value_arg(&string_flag), - &flag); - if (njs_slow_path(ret == NJS_ERROR)) { - return ret; - } - ret = njs_value_property(vm, options, njs_value_arg(&string_mode), &mode); if (njs_slow_path(ret == NJS_ERROR)) { return ret; } - ret = njs_value_property(vm, options, njs_value_arg(&string_encoding), - &encode); + ret = njs_value_property(vm, options, njs_value_arg(&string_recursive), + &recursive); if (njs_slow_path(ret == NJS_ERROR)) { return ret; } } - data = njs_arg(args, nargs, 2); + md = njs_fs_mode(vm, &mode, 0777); + if (njs_slow_path(md == (mode_t) -1)) { + return NJS_ERROR; + } - switch (data->type) { - case NJS_TYPED_ARRAY: - case NJS_DATA_VIEW: - array = njs_typed_array(data); - buffer = array->buffer; - if (njs_slow_path(njs_is_detached_buffer(buffer))) { - njs_type_error(vm, "detached buffer"); + ret = njs_fs_make_path(vm, path, md, njs_is_true(&recursive), &retval); + + if (ret == NJS_OK) { + return njs_fs_result(vm, &retval, calltype, callback, 1); + } + + return NJS_ERROR; +} + + +static njs_int_t +njs_fs_read(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_index_t calltype) +{ + int fd, flags; + njs_str_t data; + njs_int_t ret; + const char *path; + njs_value_t flag, encode, retval, *callback, *options; + struct stat sb; + const njs_buffer_encoding_t *encoding; + char path_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_is_function(callback)) { + njs_type_error(vm, "\"callback\" must be a function"); return NJS_ERROR; } - content.start = &buffer->u.u8[array->offset]; - content.length = array->byte_length; - break; + if (options == callback) { + options = njs_value_arg(&njs_value_undefined); + } + } + njs_set_undefined(&flag); + njs_set_undefined(&encode); + + switch (options->type) { case NJS_STRING: + encode = *options; + break; + + case NJS_UNDEFINED: + break; + default: - encoding = njs_buffer_encoding(vm, &encode); - if (njs_slow_path(encoding == NULL)) { + if (!njs_is_object(options)) { + njs_type_error(vm, "Unknown options type: \"%s\" " + "(a string or object required)", + njs_type_string(options->type)); return NJS_ERROR; } - ret = njs_value_to_string(vm, &retval, data); - if (njs_slow_path(ret != NJS_OK)) { - return NJS_ERROR; + ret = njs_value_property(vm, options, njs_value_arg(&string_flag), + &flag); + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; } - ret = njs_buffer_decode_string(vm, &retval, &retval, encoding); - if (njs_slow_path(ret != NJS_OK)) { - return NJS_ERROR; + ret = njs_value_property(vm, options, njs_value_arg(&string_encoding), + &encode); + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; } - - njs_string_get(&retval, &content); - break; } - flags = njs_fs_flags(vm, &flag, O_CREAT | O_WRONLY); + flags = njs_fs_flags(vm, &flag, O_RDONLY); if (njs_slow_path(flags == -1)) { return NJS_ERROR; } - flags |= ((magic >> 2) == NJS_FS_APPEND) ? O_APPEND : O_TRUNC; - - md = njs_fs_mode(vm, &mode, 0666); - if (njs_slow_path(md == (mode_t) -1)) { - return NJS_ERROR; + encoding = NULL; + if (njs_is_defined(&encode)) { + encoding = njs_buffer_encoding(vm, &encode); + if (njs_slow_path(encoding == NULL)) { + return NJS_ERROR; + } } - fd = open(path, flags, md); + fd = open(path, flags); if (njs_slow_path(fd < 0)) { ret = njs_fs_error(vm, "open", strerror(errno), path, errno, &retval); goto done; } - p = content.start; - end = p + content.length; - - while (p < end) { - n = write(fd, p, end - p); - if (njs_slow_path(n == -1)) { - if (errno == EINTR) { - continue; - } - - ret = njs_fs_error(vm, "write", strerror(errno), path, errno, - &retval); - goto done; - } - - p += n; - } - - ret = NJS_OK; - njs_set_undefined(&retval); - -done: - - if (fd != -1) { - (void) close(fd); + ret = fstat(fd, &sb); + if (njs_slow_path(ret == -1)) { + ret = njs_fs_error(vm, "stat", strerror(errno), path, errno, &retval); + goto done; } - if (ret == NJS_OK) { - return njs_fs_result(vm, &retval, calltype, callback, 1); + if (njs_slow_path(!S_ISREG(sb.st_mode))) { + ret = njs_fs_error(vm, "stat", "File is not regular", path, 0, &retval); + goto done; } - return NJS_ERROR; -} - - -static njs_int_t -njs_fs_rename(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, - njs_index_t calltype) -{ - njs_int_t ret; - const char *path, *newpath; - njs_value_t retval, *callback; - char path_buf[NJS_MAX_PATH + 1], newpath_buf[NJS_MAX_PATH + 1]; - - callback = NULL; + data.start = NULL; + data.length = sb.st_size; - if (calltype == NJS_FS_CALLBACK) { - callback = njs_arg(args, nargs, 3); - if (!njs_is_function(callback)) { - njs_type_error(vm, "\"callback\" must be a function"); - return NJS_ERROR; + ret = njs_fs_fd_read(vm, fd, &data); + if (njs_slow_path(ret != NJS_OK)) { + if (ret == NJS_DECLINED) { + ret = njs_fs_error(vm, "read", strerror(errno), path, errno, + &retval); } - } - path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "oldPath"); - if (njs_slow_path(path == NULL)) { - return NJS_ERROR; + goto done; } - newpath = njs_fs_path(vm, newpath_buf, njs_arg(args, nargs, 2), "newPath"); - if (njs_slow_path(newpath == NULL)) { - return NJS_ERROR; + if (encoding == NULL) { + ret = njs_buffer_set(vm, &retval, data.start, data.length); + + } else { + ret = encoding->encode(vm, &retval, &data); + njs_mp_free(vm->mem_pool, data.start); } - njs_set_undefined(&retval); +done: - ret = rename(path, newpath); - if (njs_slow_path(ret != 0)) { - ret = njs_fs_error(vm, "rename", strerror(errno), NULL, errno, &retval); + if (fd != -1) { + (void) close(fd); } if (ret == NJS_OK) { - return njs_fs_result(vm, &retval, calltype, callback, 1); + return njs_fs_result(vm, &retval, calltype, callback, 2); } return NJS_ERROR; @@ -526,14 +1191,21 @@ njs_fs_rename(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, static njs_int_t -njs_fs_access(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, +njs_fs_readdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t calltype) { - int md; - njs_int_t ret; - const char *path; - njs_value_t retval, *callback, *mode; - char path_buf[NJS_MAX_PATH + 1]; + DIR *dir; + njs_str_t s; + njs_int_t ret; + const char *path; + njs_value_t encode, types, ename, etype, retval, + *callback, *options, *value; + njs_array_t *results; + struct dirent *entry; + const njs_buffer_encoding_t *encoding; + char path_buf[NJS_MAX_PATH + 1]; + + static const njs_value_t string_types = njs_string("withFileTypes"); path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path"); if (njs_slow_path(path == NULL)) { @@ -541,137 +1213,133 @@ njs_fs_access(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } callback = NULL; - mode = njs_arg(args, nargs, 2); + options = njs_arg(args, nargs, 2); - if (calltype == NJS_FS_CALLBACK) { + if (njs_slow_path(calltype == NJS_FS_CALLBACK)) { callback = njs_arg(args, nargs, njs_min(nargs - 1, 3)); if (!njs_is_function(callback)) { njs_type_error(vm, "\"callback\" must be a function"); return NJS_ERROR; } - - if (mode == callback) { - mode = njs_value_arg(&njs_value_undefined); + if (options == callback) { + options = njs_value_arg(&njs_value_undefined); } } - switch (mode->type) { - case NJS_UNDEFINED: - md = F_OK; + njs_set_false(&types); + njs_set_undefined(&encode); + + switch (options->type) { + case NJS_STRING: + encode = *options; break; - case NJS_NUMBER: - md = njs_number(mode); + case NJS_UNDEFINED: break; default: - njs_type_error(vm, "\"mode\" must be a number"); - return NJS_ERROR; - } + if (!njs_is_object(options)) { + njs_type_error(vm, "Unknown options type: \"%s\" " + "(a string or object required)", + njs_type_string(options->type)); + return NJS_ERROR; + } - njs_set_undefined(&retval); + ret = njs_value_property(vm, options, njs_value_arg(&string_encoding), + &encode); + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; + } - ret = access(path, md); - if (njs_slow_path(ret != 0)) { - ret = njs_fs_error(vm, "access", strerror(errno), path, errno, &retval); + ret = njs_value_property(vm, options, njs_value_arg(&string_types), + &types); + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; + } } - if (ret == NJS_OK) { - return njs_fs_result(vm, &retval, calltype, callback, 1); + encoding = NULL; + if (!njs_is_string(&encode) || !njs_string_eq(&encode, &string_buffer)) { + encoding = njs_buffer_encoding(vm, &encode); + if (njs_slow_path(encoding == NULL)) { + return NJS_ERROR; + } } - return NJS_ERROR; -} - - -static njs_int_t -njs_fs_symlink(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, - njs_index_t calltype) -{ - njs_int_t ret; - const char *target, *path; - njs_value_t retval, *callback, *type; - char target_buf[NJS_MAX_PATH + 1], path_buf[NJS_MAX_PATH + 1]; - - target = njs_fs_path(vm, target_buf, njs_arg(args, nargs, 1), "target"); - if (njs_slow_path(target == NULL)) { + results = njs_array_alloc(vm, 1, 0, NJS_ARRAY_SPARE); + if (njs_slow_path(results == NULL)) { return NJS_ERROR; } - path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 2), "path"); - if (njs_slow_path(path == NULL)) { - return NJS_ERROR; + njs_set_array(&retval, results); + + dir = opendir(path); + if (njs_slow_path(dir == NULL)) { + ret = njs_fs_error(vm, "opendir", strerror(errno), path, errno, + &retval); + goto done; } - callback = NULL; - type = njs_arg(args, nargs, 3); + ret = NJS_OK; - if (calltype == NJS_FS_CALLBACK) { - callback = njs_arg(args, nargs, njs_min(nargs - 1, 4)); - if (!njs_is_function(callback)) { - njs_type_error(vm, "\"callback\" must be a function"); - return NJS_ERROR; - } + for ( ;; ) { + errno = 0; + entry = readdir(dir); + if (njs_slow_path(entry == NULL)) { + if (errno != 0) { + ret = njs_fs_error(vm, "readdir", strerror(errno), path, errno, + &retval); + } - if (type == callback) { - type = njs_value_arg(&njs_value_undefined); + goto done; } - } - - if (njs_slow_path(!njs_is_undefined(type) && !njs_is_string(type))) { - njs_type_error(vm, "\"type\" must be a string"); - return NJS_ERROR; - } - njs_set_undefined(&retval); + s.start = (u_char *) entry->d_name; + s.length = njs_strlen(s.start); - ret = symlink(target, path); - if (njs_slow_path(ret != 0)) { - ret = njs_fs_error(vm, "symlink", strerror(errno), path, errno, - &retval); - } + if ((s.length == 1 && s.start[0] == '.') + || (s.length == 2 && (s.start[0] == '.' && s.start[1] == '.'))) + { + continue; + } - if (ret == NJS_OK) { - return njs_fs_result(vm, &retval, calltype, callback, 1); - } + value = njs_array_push(vm, results); + if (njs_slow_path(value == NULL)) { + goto done; + } - return NJS_ERROR; -} + if (encoding == NULL) { + ret = njs_buffer_set(vm, &ename, s.start, s.length); + } else { + ret = encoding->encode(vm, &ename, &s); + } -static njs_int_t -njs_fs_unlink(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, - njs_index_t calltype) -{ - njs_int_t ret; - const char *path; - njs_value_t retval, *callback; - char path_buf[NJS_MAX_PATH + 1]; + if (njs_slow_path(ret != NJS_OK)) { + goto done; + } - path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path"); - if (njs_slow_path(path == NULL)) { - return NJS_ERROR; - } + if (njs_fast_path(!njs_is_true(&types))) { + *value = ename; + continue; + } - callback = NULL; + njs_set_number(&etype, njs_dentry_type(entry)); - if (calltype == NJS_FS_CALLBACK) { - callback = njs_arg(args, nargs, 2); - if (!njs_is_function(callback)) { - njs_type_error(vm, "\"callback\" must be a function"); - return NJS_ERROR; + ret = njs_fs_dirent_create(vm, &ename, &etype, value); + if (njs_slow_path(ret != NJS_OK)) { + goto done; } } - njs_set_undefined(&retval); +done: - ret = unlink(path); - if (njs_slow_path(ret != 0)) { - ret = njs_fs_error(vm, "unlink", strerror(errno), path, errno, &retval); + if (dir != NULL) { + (void) closedir(dir); } if (ret == NJS_OK) { - return njs_fs_result(vm, &retval, calltype, callback, 1); + return njs_fs_result(vm, &retval, calltype, callback, 2); } return NJS_ERROR; @@ -769,73 +1437,41 @@ done: } -static njs_int_t -njs_fs_mkdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, - njs_index_t calltype) -{ - char *path; - mode_t md; - njs_int_t ret; - njs_value_t mode, recursive, retval, *callback, *options; - char path_buf[NJS_MAX_PATH + 1]; - - path = (char *) 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 (njs_slow_path(calltype == NJS_FS_CALLBACK)) { - callback = njs_arg(args, nargs, njs_min(nargs - 1, 3)); - if (!njs_is_function(callback)) { - njs_type_error(vm, "\"callback\" must be a function"); - return NJS_ERROR; - } - if (options == callback) { - options = njs_value_arg(&njs_value_undefined); - } - } - - njs_set_undefined(&mode); - njs_set_false(&recursive); - - switch (options->type) { - case NJS_NUMBER: - mode = *options; - break; +static njs_int_t +njs_fs_rename(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_index_t calltype) +{ + njs_int_t ret; + const char *path, *newpath; + njs_value_t retval, *callback; + char path_buf[NJS_MAX_PATH + 1], newpath_buf[NJS_MAX_PATH + 1]; - case NJS_UNDEFINED: - break; + callback = NULL; - default: - if (!njs_is_object(options)) { - njs_type_error(vm, "Unknown options type: \"%s\" " - "(a number or object required)", - njs_type_string(options->type)); + if (calltype == NJS_FS_CALLBACK) { + callback = njs_arg(args, nargs, 3); + if (!njs_is_function(callback)) { + njs_type_error(vm, "\"callback\" must be a function"); return NJS_ERROR; } + } - ret = njs_value_property(vm, options, njs_value_arg(&string_mode), - &mode); - if (njs_slow_path(ret == NJS_ERROR)) { - return ret; - } - - ret = njs_value_property(vm, options, njs_value_arg(&string_recursive), - &recursive); - if (njs_slow_path(ret == NJS_ERROR)) { - return ret; - } + path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "oldPath"); + if (njs_slow_path(path == NULL)) { + return NJS_ERROR; } - md = njs_fs_mode(vm, &mode, 0777); - if (njs_slow_path(md == (mode_t) -1)) { + newpath = njs_fs_path(vm, newpath_buf, njs_arg(args, nargs, 2), "newPath"); + if (njs_slow_path(newpath == NULL)) { return NJS_ERROR; } - ret = njs_fs_make_path(vm, path, md, njs_is_true(&recursive), &retval); + njs_set_undefined(&retval); + + ret = rename(path, newpath); + if (njs_slow_path(ret != 0)) { + ret = njs_fs_error(vm, "rename", strerror(errno), NULL, errno, &retval); + } if (ret == NJS_OK) { return njs_fs_result(vm, &retval, calltype, callback, 1); @@ -905,21 +1541,19 @@ njs_fs_rmdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, static njs_int_t -njs_fs_readdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, - njs_index_t calltype) +njs_fs_stat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_index_t magic) { - DIR *dir; - njs_str_t s; - njs_int_t ret; - const char *path; - njs_value_t encode, types, ename, etype, retval, - *callback, *options, *value; - njs_array_t *results; - struct dirent *entry; - const njs_buffer_encoding_t *encoding; - char path_buf[NJS_MAX_PATH + 1]; + njs_int_t ret; + njs_bool_t throw; + struct stat sb; + const char *path; + njs_value_t retval, *callback, *options; + njs_fs_calltype_t calltype; + char path_buf[NJS_MAX_PATH + 1]; - static const njs_value_t string_types = njs_string("withFileTypes"); + static const njs_value_t string_bigint = njs_string("bigint"); + static const njs_value_t string_throw = njs_string("throwIfNoEntry"); path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path"); if (njs_slow_path(path == NULL)) { @@ -927,6 +1561,7 @@ njs_fs_readdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } callback = NULL; + calltype = magic & 3; options = njs_arg(args, nargs, 2); if (njs_slow_path(calltype == NJS_FS_CALLBACK)) { @@ -940,120 +1575,155 @@ njs_fs_readdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } } - njs_set_false(&types); - njs_set_undefined(&encode); + throw = 1; switch (options->type) { - case NJS_STRING: - encode = *options; - break; - case NJS_UNDEFINED: break; default: if (!njs_is_object(options)) { njs_type_error(vm, "Unknown options type: \"%s\" " - "(a string or object required)", + "(an object required)", njs_type_string(options->type)); return NJS_ERROR; } - ret = njs_value_property(vm, options, njs_value_arg(&string_encoding), - &encode); + ret = njs_value_property(vm, options, njs_value_arg(&string_bigint), + &retval); if (njs_slow_path(ret == NJS_ERROR)) { return ret; } - ret = njs_value_property(vm, options, njs_value_arg(&string_types), - &types); - if (njs_slow_path(ret == NJS_ERROR)) { - return ret; + if (njs_bool(&retval)) { + njs_type_error(vm, "\"bigint\" is not supported"); + return NJS_ERROR; + } + + if (calltype == NJS_FS_DIRECT) { + ret = njs_value_property(vm, options, njs_value_arg(&string_throw), + &retval); + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; + } + + throw = njs_bool(&retval); } } - encoding = NULL; - if (!njs_is_string(&encode) || !njs_string_eq(&encode, &string_buffer)) { - encoding = njs_buffer_encoding(vm, &encode); - if (njs_slow_path(encoding == NULL)) { - return NJS_ERROR; + ret = ((magic >> 2) == NJS_FS_STAT) ? stat(path, &sb) : lstat(path, &sb); + if (njs_slow_path(ret != 0)) { + if (errno != ENOENT || throw) { + ret = njs_fs_error(vm, + ((magic >> 2) == NJS_FS_STAT) ? "stat" : "lstat", + strerror(errno), path, errno, &retval); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + } else { + njs_set_undefined(&retval); } + + return njs_fs_result(vm, &retval, calltype, callback, 2); } - results = njs_array_alloc(vm, 1, 0, NJS_ARRAY_SPARE); - if (njs_slow_path(results == NULL)) { + ret = njs_fs_stats_create(vm, &sb, &retval); + if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } - njs_set_array(&retval, results); + return njs_fs_result(vm, &retval, calltype, callback, 2); +} - dir = opendir(path); - if (njs_slow_path(dir == NULL)) { - ret = njs_fs_error(vm, "opendir", strerror(errno), path, errno, - &retval); - goto done; - } - ret = NJS_OK; +static njs_int_t +njs_fs_symlink(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_index_t calltype) +{ + njs_int_t ret; + const char *target, *path; + njs_value_t retval, *callback, *type; + char target_buf[NJS_MAX_PATH + 1], path_buf[NJS_MAX_PATH + 1]; - for ( ;; ) { - errno = 0; - entry = readdir(dir); - if (njs_slow_path(entry == NULL)) { - if (errno != 0) { - ret = njs_fs_error(vm, "readdir", strerror(errno), path, errno, - &retval); - } + target = njs_fs_path(vm, target_buf, njs_arg(args, nargs, 1), "target"); + if (njs_slow_path(target == NULL)) { + return NJS_ERROR; + } - goto done; - } + path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 2), "path"); + if (njs_slow_path(path == NULL)) { + return NJS_ERROR; + } - s.start = (u_char *) entry->d_name; - s.length = njs_strlen(s.start); + callback = NULL; + type = njs_arg(args, nargs, 3); - if ((s.length == 1 && s.start[0] == '.') - || (s.length == 2 && (s.start[0] == '.' && s.start[1] == '.'))) - { - continue; + if (calltype == NJS_FS_CALLBACK) { + callback = njs_arg(args, nargs, njs_min(nargs - 1, 4)); + if (!njs_is_function(callback)) { + njs_type_error(vm, "\"callback\" must be a function"); + return NJS_ERROR; } - value = njs_array_push(vm, results); - if (njs_slow_path(value == NULL)) { - goto done; + if (type == callback) { + type = njs_value_arg(&njs_value_undefined); } + } - if (encoding == NULL) { - ret = njs_buffer_set(vm, &ename, s.start, s.length); + if (njs_slow_path(!njs_is_undefined(type) && !njs_is_string(type))) { + njs_type_error(vm, "\"type\" must be a string"); + return NJS_ERROR; + } - } else { - ret = encoding->encode(vm, &ename, &s); - } + njs_set_undefined(&retval); - if (njs_slow_path(ret != NJS_OK)) { - goto done; - } + ret = symlink(target, path); + if (njs_slow_path(ret != 0)) { + ret = njs_fs_error(vm, "symlink", strerror(errno), path, errno, + &retval); + } - if (njs_fast_path(!njs_is_true(&types))) { - *value = ename; - continue; - } + if (ret == NJS_OK) { + return njs_fs_result(vm, &retval, calltype, callback, 1); + } - njs_set_number(&etype, njs_dentry_type(entry)); + return NJS_ERROR; +} - ret = njs_fs_dirent_create(vm, &ename, &etype, value); - if (njs_slow_path(ret != NJS_OK)) { - goto done; + +static njs_int_t +njs_fs_unlink(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_index_t calltype) +{ + njs_int_t ret; + const char *path; + njs_value_t retval, *callback; + char path_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; + + if (calltype == NJS_FS_CALLBACK) { + callback = njs_arg(args, nargs, 2); + if (!njs_is_function(callback)) { + njs_type_error(vm, "\"callback\" must be a function"); + return NJS_ERROR; } } -done: + njs_set_undefined(&retval); - if (dir != NULL) { - (void) closedir(dir); + ret = unlink(path); + if (njs_slow_path(ret != 0)) { + ret = njs_fs_error(vm, "unlink", strerror(errno), path, errno, &retval); } if (ret == NJS_OK) { - return njs_fs_result(vm, &retval, calltype, callback, 2); + return njs_fs_result(vm, &retval, calltype, callback, 1); } return NJS_ERROR; @@ -1061,19 +1731,23 @@ done: static njs_int_t -njs_fs_stat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, +njs_fs_write(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t magic) { - njs_int_t ret; - njs_bool_t throw; - struct stat sb; - const char *path; - njs_value_t retval, *callback, *options; - njs_fs_calltype_t calltype; - char path_buf[NJS_MAX_PATH + 1]; - - static const njs_value_t string_bigint = njs_string("bigint"); - static const njs_value_t string_throw = njs_string("throwIfNoEntry"); + int fd, flags; + u_char *p, *end; + mode_t md; + ssize_t n; + njs_str_t content; + njs_int_t ret; + const char *path; + njs_value_t flag, mode, encode, retval, *data, *callback, + *options; + njs_typed_array_t *array; + njs_fs_calltype_t calltype; + njs_array_buffer_t *buffer; + const njs_buffer_encoding_t *encoding; + char path_buf[NJS_MAX_PATH + 1]; path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path"); if (njs_slow_path(path == NULL)) { @@ -1082,77 +1756,146 @@ njs_fs_stat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, callback = NULL; calltype = magic & 3; - options = njs_arg(args, nargs, 2); + options = njs_arg(args, nargs, 3); - if (njs_slow_path(calltype == NJS_FS_CALLBACK)) { - callback = njs_arg(args, nargs, njs_min(nargs - 1, 3)); + if (calltype == NJS_FS_CALLBACK) { + callback = njs_arg(args, nargs, njs_min(nargs - 1, 4)); if (!njs_is_function(callback)) { njs_type_error(vm, "\"callback\" must be a function"); return NJS_ERROR; } + if (options == callback) { options = njs_value_arg(&njs_value_undefined); } } - throw = 1; + njs_set_undefined(&flag); + njs_set_undefined(&mode); + njs_set_undefined(&encode); switch (options->type) { + case NJS_STRING: + encode = *options; + break; + case NJS_UNDEFINED: break; default: if (!njs_is_object(options)) { njs_type_error(vm, "Unknown options type: \"%s\" " - "(an object required)", + "(a string or object required)", njs_type_string(options->type)); return NJS_ERROR; } - ret = njs_value_property(vm, options, njs_value_arg(&string_bigint), - &retval); + ret = njs_value_property(vm, options, njs_value_arg(&string_flag), + &flag); if (njs_slow_path(ret == NJS_ERROR)) { return ret; } - if (njs_bool(&retval)) { - njs_type_error(vm, "\"bigint\" is not supported"); + ret = njs_value_property(vm, options, njs_value_arg(&string_mode), + &mode); + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; + } + + ret = njs_value_property(vm, options, njs_value_arg(&string_encoding), + &encode); + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; + } + } + + data = njs_arg(args, nargs, 2); + + switch (data->type) { + case NJS_TYPED_ARRAY: + case NJS_DATA_VIEW: + array = njs_typed_array(data); + buffer = array->buffer; + if (njs_slow_path(njs_is_detached_buffer(buffer))) { + njs_type_error(vm, "detached buffer"); return NJS_ERROR; } - if (calltype == NJS_FS_DIRECT) { - ret = njs_value_property(vm, options, njs_value_arg(&string_throw), - &retval); - if (njs_slow_path(ret == NJS_ERROR)) { - return ret; - } + content.start = &buffer->u.u8[array->offset]; + content.length = array->byte_length; + break; - throw = njs_bool(&retval); + case NJS_STRING: + default: + encoding = njs_buffer_encoding(vm, &encode); + if (njs_slow_path(encoding == NULL)) { + return NJS_ERROR; + } + + ret = njs_value_to_string(vm, &retval, data); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + + ret = njs_buffer_decode_string(vm, &retval, &retval, encoding); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; } + + njs_string_get(&retval, &content); + break; } - ret = ((magic >> 2) == NJS_FS_STAT) ? stat(path, &sb) : lstat(path, &sb); - if (njs_slow_path(ret != 0)) { - if (errno != ENOENT || throw) { - ret = njs_fs_error(vm, - ((magic >> 2) == NJS_FS_STAT) ? "stat" : "lstat", - strerror(errno), path, errno, &retval); - if (njs_slow_path(ret != NJS_OK)) { - return NJS_ERROR; + flags = njs_fs_flags(vm, &flag, O_CREAT | O_WRONLY); + if (njs_slow_path(flags == -1)) { + return NJS_ERROR; + } + + flags |= ((magic >> 2) == NJS_FS_APPEND) ? O_APPEND : O_TRUNC; + + md = njs_fs_mode(vm, &mode, 0666); + if (njs_slow_path(md == (mode_t) -1)) { + return NJS_ERROR; + } + + fd = open(path, flags, md); + if (njs_slow_path(fd < 0)) { + ret = njs_fs_error(vm, "open", strerror(errno), path, errno, &retval); + goto done; + } + + p = content.start; + end = p + content.length; + + while (p < end) { + n = write(fd, p, end - p); + if (njs_slow_path(n == -1)) { + if (errno == EINTR) { + continue; } - } else { - njs_set_undefined(&retval); + + ret = njs_fs_error(vm, "write", strerror(errno), path, errno, + &retval); + goto done; } - return njs_fs_result(vm, &retval, calltype, callback, 2); + p += n; } - ret = njs_fs_stats_create(vm, &sb, &retval); - if (njs_slow_path(ret != NJS_OK)) { - return NJS_ERROR; + ret = NJS_OK; + njs_set_undefined(&retval); + +done: + + if (fd != -1) { + (void) close(fd); } - return njs_fs_result(vm, &retval, calltype, callback, 2); + if (ret == NJS_OK) { + return njs_fs_result(vm, &retval, calltype, callback, 1); + } + + return NJS_ERROR; } @@ -1822,21 +2565,16 @@ static njs_int_t njs_fs_dirent_create(njs_vm_t *vm, njs_value_t *name, njs_value_t *type, njs_value_t *retval) { - njs_int_t ret; - njs_object_t *object; + njs_int_t ret; static const njs_value_t string_name = njs_string("name"); static const njs_value_t string_type = njs_string("type"); - object = njs_object_alloc(vm); - if (njs_slow_path(object == NULL)) { - return NJS_ERROR; + ret = njs_vm_external_create(vm, retval, njs_fs_dirent_proto_id, NULL, 0); + if (njs_slow_path(ret != NJS_OK)) { + return ret; } - object->__proto__ = &vm->prototypes[NJS_OBJ_TYPE_FS_DIRENT].object; - - njs_set_object(retval, object); - ret = njs_value_property_set(vm, retval, njs_value_arg(&string_name), name); if (njs_slow_path(ret != NJS_OK)) { @@ -1844,18 +2582,13 @@ njs_fs_dirent_create(njs_vm_t *vm, njs_value_t *name, njs_value_t *type, } /* TODO: use a private symbol as a key. */ - ret = njs_value_property_set(vm, retval, njs_value_arg(&string_type), - type); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } - - return NJS_OK; + return njs_value_property_set(vm, retval, njs_value_arg(&string_type), + type); } static njs_int_t -njs_dirent_constructor(njs_vm_t *vm, njs_value_t *args, +njs_fs_dirent_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { if (njs_slow_path(!vm->top_frame->ctor)) { @@ -1864,157 +2597,68 @@ njs_dirent_constructor(njs_vm_t *vm, njs_value_t *args, } return njs_fs_dirent_create(vm, njs_arg(args, nargs, 1), - njs_arg(args, nargs, 2), &vm->retval); -} - - -static const njs_object_prop_t njs_dirent_constructor_properties[] = -{ - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_string("Dirent"), - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("length"), - .value = njs_value(NJS_NUMBER, 1, 2.0), - .configurable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("prototype"), - .value = njs_prop_handler(njs_object_prototype_create), - }, -}; - - -const njs_object_init_t njs_dirent_constructor_init = { - njs_dirent_constructor_properties, - njs_nitems(njs_dirent_constructor_properties), -}; - - -static njs_int_t -njs_fs_dirent_test(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, - njs_index_t testtype) -{ - njs_int_t ret; - njs_value_t type, *this; - - static const njs_value_t string_type = njs_string("type"); - - this = njs_argument(args, 0); - - ret = njs_value_property(vm, this, njs_value_arg(&string_type), &type); - if (njs_slow_path(ret == NJS_ERROR)) { - return ret; - } - - if (njs_slow_path(njs_is_number(&type) - && (njs_number(&type) == NJS_DT_INVALID))) - { - njs_internal_error(vm, "dentry type is not supported on this platform"); - return NJS_ERROR; - } - - njs_set_boolean(&vm->retval, - njs_is_number(&type) && testtype == njs_number(&type)); - - return NJS_OK; -} - - -static const njs_object_prop_t njs_dirent_prototype_properties[] = -{ - { - .type = NJS_PROPERTY, - .name = njs_wellknown_symbol(NJS_SYMBOL_TO_STRING_TAG), - .value = njs_string("Dirent"), - .configurable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("constructor"), - .value = njs_prop_handler(njs_object_prototype_create_constructor), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("isDirectory"), - .value = njs_native_function2(njs_fs_dirent_test, 0, DT_DIR), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("isFile"), - .value = njs_native_function2(njs_fs_dirent_test, 0, DT_REG), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("isBlockDevice"), - .value = njs_native_function2(njs_fs_dirent_test, 0, DT_BLK), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_long_string("isCharacterDevice"), - .value = njs_native_function2(njs_fs_dirent_test, 0, DT_CHR), - .writable = 1, - .configurable = 1, - }, + njs_arg(args, nargs, 2), &vm->retval); +} + +static const njs_object_prop_t njs_dirent_constructor_properties[] = +{ { .type = NJS_PROPERTY, - .name = njs_string("isSymbolicLink"), - .value = njs_native_function2(njs_fs_dirent_test, 0, DT_LNK), - .writable = 1, + .name = njs_string("name"), + .value = njs_string("Dirent"), .configurable = 1, }, { .type = NJS_PROPERTY, - .name = njs_string("isFIFO"), - .value = njs_native_function2(njs_fs_dirent_test, 0, DT_FIFO), - .writable = 1, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 2.0), .configurable = 1, }, { - .type = NJS_PROPERTY, - .name = njs_string("isSocket"), - .value = njs_native_function2(njs_fs_dirent_test, 0, DT_SOCK), - .writable = 1, - .configurable = 1, + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("prototype"), + .value = njs_prop_handler(njs_object_prototype_create), }, }; -const njs_object_init_t njs_dirent_prototype_init = { - njs_dirent_prototype_properties, - njs_nitems(njs_dirent_prototype_properties), +const njs_object_init_t njs_dirent_constructor_init = { + njs_dirent_constructor_properties, + njs_nitems(njs_dirent_constructor_properties), }; -const njs_object_type_init_t njs_dirent_type_init = { - .constructor = njs_native_ctor(njs_dirent_constructor, 2, 0), - .prototype_props = &njs_dirent_prototype_init, - .constructor_props = &njs_dirent_constructor_init, - .prototype_value = { .object = { .type = NJS_OBJECT } }, -}; +static njs_int_t +njs_fs_dirent_test(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_index_t testtype) +{ + njs_int_t ret; + njs_value_t type, *this; + + static const njs_value_t string_type = njs_string("type"); + + this = njs_argument(args, 0); + + ret = njs_value_property(vm, this, njs_value_arg(&string_type), &type); + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; + } + + if (njs_slow_path(njs_is_number(&type) + && (njs_number(&type) == NJS_DT_INVALID))) + { + njs_internal_error(vm, "dentry type is not supported on this platform"); + return NJS_ERROR; + } + + njs_set_boolean(&vm->retval, + njs_is_number(&type) && testtype == njs_number(&type)); + + return NJS_OK; +} static void @@ -2077,38 +2721,18 @@ njs_fs_to_stat(njs_stat_t *dst, struct stat *st) static njs_int_t njs_fs_stats_create(njs_vm_t *vm, struct stat *st, njs_value_t *retval) { - njs_stat_t *copy; - njs_object_value_t *stat; + njs_stat_t *stat; - stat = njs_object_value_alloc(vm, NJS_OBJ_TYPE_FS_STATS, 0, NULL); + stat = njs_mp_alloc(vm->mem_pool, sizeof(njs_stat_t)); if (njs_slow_path(stat == NULL)) { - return NJS_ERROR; - } - - stat->object.shared_hash = - vm->prototypes[NJS_OBJ_TYPE_FS_STATS].object.shared_hash; - - copy = njs_mp_alloc(vm->mem_pool, sizeof(njs_stat_t)); - if (copy == NULL) { njs_memory_error(vm); return NJS_ERROR; } - njs_fs_to_stat(copy, st); - - njs_set_data(&stat->value, copy, NJS_DATA_TAG_FS_STAT); - njs_set_object_value(retval, stat); - - return NJS_OK; -} - + njs_fs_to_stat(stat, st); -static njs_int_t -njs_stats_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, - njs_index_t unused) -{ - njs_type_error(vm, "Stats is not a constructor"); - return NJS_ERROR; + return njs_vm_external_create(vm, retval, njs_fs_stats_proto_id, + stat, 0); } @@ -2116,18 +2740,14 @@ static njs_int_t njs_fs_stats_test(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t testtype) { - unsigned mask; - njs_stat_t *st; - njs_value_t *this; - - this = njs_argument(args, 0); + unsigned mask; + njs_stat_t *st; - if (njs_slow_path(!njs_is_object_data(this, NJS_DATA_TAG_FS_STAT))) { + st = njs_vm_external(vm, njs_fs_stats_proto_id, njs_argument(args, 0)); + if (njs_slow_path(st == NULL)) { return NJS_DECLINED; } - st = njs_object_data(this); - switch (testtype) { case DT_DIR: mask = S_IFDIR; @@ -2174,13 +2794,12 @@ njs_fs_stats_prop(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, #define njs_fs_time_ms(ts) ((ts)->tv_sec * 1000.0 + (ts)->tv_nsec / 1000000.0) - if (njs_slow_path(!njs_is_object_data(value, NJS_DATA_TAG_FS_STAT))) { + st = njs_vm_external(vm, njs_fs_stats_proto_id, value); + if (njs_slow_path(st == NULL)) { return NJS_DECLINED; } - st = njs_object_data(value); - - switch (prop->value.data.magic16) { + switch (prop->value.data.magic32 & 0xf) { case NJS_FS_STAT_DEV: v = st->st_dev; break; @@ -2217,309 +2836,46 @@ njs_fs_stats_prop(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, v = st->st_blksize; break; - case NJS_FS_STAT_BLOCKS: - v = st->st_blocks; - break; - - case NJS_FS_STAT_ATIME: - v = njs_fs_time_ms(&st->st_atim); - break; - - case NJS_FS_STAT_BIRTHTIME: - v = njs_fs_time_ms(&st->st_birthtim); - break; - - case NJS_FS_STAT_CTIME: - v = njs_fs_time_ms(&st->st_ctim); - break; - - case NJS_FS_STAT_MTIME: - default: - v = njs_fs_time_ms(&st->st_mtim); - break; - } - - switch (prop->value.data.magic32) { - case NJS_NUMBER: - njs_set_number(retval, v); - break; - - case NJS_DATE: - default: - date = njs_date_alloc(vm, v); - if (njs_slow_path(date == NULL)) { - return NJS_ERROR; - } - - njs_set_date(retval, date); - break; - } - - return NJS_OK; -} - - -static const njs_object_prop_t njs_stats_constructor_properties[] = -{ - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_string("Stats"), - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("length"), - .value = njs_value(NJS_NUMBER, 1, 0), - .configurable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("prototype"), - .value = njs_prop_handler(njs_object_prototype_create), - }, -}; - - -const njs_object_init_t njs_stats_constructor_init = { - njs_stats_constructor_properties, - njs_nitems(njs_stats_constructor_properties), -}; - - -static const njs_object_prop_t njs_stats_prototype_properties[] = -{ - { - .type = NJS_PROPERTY, - .name = njs_wellknown_symbol(NJS_SYMBOL_TO_STRING_TAG), - .value = njs_string("Stats"), - .configurable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("constructor"), - .value = njs_prop_handler(njs_object_prototype_create_constructor), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("isBlockDevice"), - .value = njs_native_function2(njs_fs_stats_test, 0, DT_BLK), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_long_string("isCharacterDevice"), - .value = njs_native_function2(njs_fs_stats_test, 0, DT_CHR), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("isDirectory"), - .value = njs_native_function2(njs_fs_stats_test, 0, DT_DIR), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("isFIFO"), - .value = njs_native_function2(njs_fs_stats_test, 0, DT_FIFO), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("isFile"), - .value = njs_native_function2(njs_fs_stats_test, 0, DT_REG), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("isSocket"), - .value = njs_native_function2(njs_fs_stats_test, 0, DT_SOCK), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("isSymbolicLink"), - .value = njs_native_function2(njs_fs_stats_test, 0, DT_LNK), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("dev"), - .value = njs_prop_handler2(njs_fs_stats_prop, NJS_FS_STAT_DEV, - NJS_NUMBER), - .enumerable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("ino"), - .value = njs_prop_handler2(njs_fs_stats_prop, NJS_FS_STAT_INO, - NJS_NUMBER), - .enumerable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("mode"), - .value = njs_prop_handler2(njs_fs_stats_prop, NJS_FS_STAT_MODE, - NJS_NUMBER), - .enumerable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("nlink"), - .value = njs_prop_handler2(njs_fs_stats_prop, NJS_FS_STAT_NLINK, - NJS_NUMBER), - .enumerable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("uid"), - .value = njs_prop_handler2(njs_fs_stats_prop, NJS_FS_STAT_UID, - NJS_NUMBER), - .enumerable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("gid"), - .value = njs_prop_handler2(njs_fs_stats_prop, NJS_FS_STAT_GID, - NJS_NUMBER), - .enumerable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("rdev"), - .value = njs_prop_handler2(njs_fs_stats_prop, NJS_FS_STAT_RDEV, - NJS_NUMBER), - .enumerable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("size"), - .value = njs_prop_handler2(njs_fs_stats_prop, NJS_FS_STAT_SIZE, - NJS_NUMBER), - .enumerable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("blksize"), - .value = njs_prop_handler2(njs_fs_stats_prop, NJS_FS_STAT_BLKSIZE, - NJS_NUMBER), - .enumerable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("blocks"), - .value = njs_prop_handler2(njs_fs_stats_prop, NJS_FS_STAT_BLOCKS, - NJS_NUMBER), - .enumerable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("atimeMs"), - .value = njs_prop_handler2(njs_fs_stats_prop, NJS_FS_STAT_ATIME, - NJS_NUMBER), - .enumerable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("birthtimeMs"), - .value = njs_prop_handler2(njs_fs_stats_prop, NJS_FS_STAT_BIRTHTIME, - NJS_NUMBER), - .enumerable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("ctimeMs"), - .value = njs_prop_handler2(njs_fs_stats_prop, NJS_FS_STAT_CTIME, - NJS_NUMBER), - .enumerable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("mtimeMs"), - .value = njs_prop_handler2(njs_fs_stats_prop, NJS_FS_STAT_MTIME, - NJS_NUMBER), - .enumerable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("atime"), - .value = njs_prop_handler2(njs_fs_stats_prop, NJS_FS_STAT_ATIME, - NJS_DATE), - .enumerable = 1, - }, + case NJS_FS_STAT_BLOCKS: + v = st->st_blocks; + break; - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("birthtime"), - .value = njs_prop_handler2(njs_fs_stats_prop, NJS_FS_STAT_BIRTHTIME, - NJS_DATE), - .enumerable = 1, - }, + case NJS_FS_STAT_ATIME: + v = njs_fs_time_ms(&st->st_atim); + break; - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("ctime"), - .value = njs_prop_handler2(njs_fs_stats_prop, NJS_FS_STAT_CTIME, - NJS_DATE), - .enumerable = 1, - }, + case NJS_FS_STAT_BIRTHTIME: + v = njs_fs_time_ms(&st->st_birthtim); + break; - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("mtime"), - .value = njs_prop_handler2(njs_fs_stats_prop, NJS_FS_STAT_MTIME, - NJS_DATE), - .enumerable = 1, - }, -}; + case NJS_FS_STAT_CTIME: + v = njs_fs_time_ms(&st->st_ctim); + break; + + case NJS_FS_STAT_MTIME: + default: + v = njs_fs_time_ms(&st->st_mtim); + break; + } + switch (prop->value.data.magic32 >> 4) { + case NJS_NUMBER: + njs_set_number(retval, v); + break; -const njs_object_init_t njs_stats_prototype_init = { - njs_stats_prototype_properties, - njs_nitems(njs_stats_prototype_properties), -}; + case NJS_DATE: + default: + date = njs_date_alloc(vm, v); + if (njs_slow_path(date == NULL)) { + return NJS_ERROR; + } + njs_set_date(retval, date); + break; + } -const njs_object_type_init_t njs_stats_type_init = { - .constructor = njs_native_ctor(njs_stats_constructor, 0, 0), - .prototype_props = &njs_stats_prototype_init, - .constructor_props = &njs_stats_constructor_init, - .prototype_value = { .object = { .type = NJS_OBJECT } }, -}; + return NJS_OK; +} static const njs_object_prop_t njs_fs_promises_properties[] = @@ -2527,7 +2883,7 @@ static const njs_object_prop_t njs_fs_promises_properties[] = { .type = NJS_PROPERTY, .name = njs_string("readFile"), - .value = njs_native_function2(njs_fs_read_file, 0, NJS_FS_PROMISE), + .value = njs_native_function2(njs_fs_read, 0, NJS_FS_PROMISE), .writable = 1, .configurable = 1, }, @@ -2535,7 +2891,7 @@ static const njs_object_prop_t njs_fs_promises_properties[] = { .type = NJS_PROPERTY, .name = njs_string("appendFile"), - .value = njs_native_function2(njs_fs_write_file, 0, + .value = njs_native_function2(njs_fs_write, 0, njs_fs_magic(NJS_FS_PROMISE, NJS_FS_APPEND)), .writable = 1, .configurable = 1, @@ -2544,8 +2900,8 @@ static const njs_object_prop_t njs_fs_promises_properties[] = { .type = NJS_PROPERTY, .name = njs_string("writeFile"), - .value = njs_native_function2(njs_fs_write_file, 0, - njs_fs_magic(NJS_FS_PROMISE, NJS_FS_TRUNC)), + .value = njs_native_function2(njs_fs_write, 0, + njs_fs_magic(NJS_FS_PROMISE, NJS_FS_TRUNC)), .writable = 1, .configurable = 1, }, @@ -2692,255 +3048,47 @@ njs_fs_constants(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, } -static const njs_object_prop_t njs_fs_object_properties[] = +static njs_int_t +njs_fs_init(njs_vm_t *vm) { - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_string("fs"), - .configurable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("constants"), - .value = njs_prop_handler(njs_fs_constants), - .enumerable = 1, - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("promises"), - .value = njs_prop_handler(njs_fs_promises), - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("Dirent"), - .value = _njs_native_function(njs_dirent_constructor, 2, 1, 0), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("access"), - .value = njs_native_function2(njs_fs_access, 0, NJS_FS_CALLBACK), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("accessSync"), - .value = njs_native_function2(njs_fs_access, 0, NJS_FS_DIRECT), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("readFile"), - .value = njs_native_function2(njs_fs_read_file, 0, NJS_FS_CALLBACK), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("readFileSync"), - .value = njs_native_function2(njs_fs_read_file, 0, NJS_FS_DIRECT), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("appendFile"), - .value = njs_native_function2(njs_fs_write_file, 0, - njs_fs_magic(NJS_FS_CALLBACK, NJS_FS_APPEND)), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("appendFileSync"), - .value = njs_native_function2(njs_fs_write_file, 0, - njs_fs_magic(NJS_FS_DIRECT, NJS_FS_APPEND)), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("writeFile"), - .value = njs_native_function2(njs_fs_write_file, 0, - njs_fs_magic(NJS_FS_CALLBACK, NJS_FS_TRUNC)), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("writeFileSync"), - .value = njs_native_function2(njs_fs_write_file, 0, - njs_fs_magic(NJS_FS_DIRECT, NJS_FS_TRUNC)), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("rename"), - .value = njs_native_function2(njs_fs_rename, 0, NJS_FS_CALLBACK), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("renameSync"), - .value = njs_native_function2(njs_fs_rename, 0, NJS_FS_DIRECT), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("symlink"), - .value = njs_native_function2(njs_fs_symlink, 0, NJS_FS_CALLBACK), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("symlinkSync"), - .value = njs_native_function2(njs_fs_symlink, 0, NJS_FS_DIRECT), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("unlink"), - .value = njs_native_function2(njs_fs_unlink, 0, NJS_FS_CALLBACK), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("unlinkSync"), - .value = njs_native_function2(njs_fs_unlink, 0, NJS_FS_DIRECT), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("realpath"), - .value = njs_native_function2(njs_fs_realpath, 0, NJS_FS_CALLBACK), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("realpathSync"), - .value = njs_native_function2(njs_fs_realpath, 0, NJS_FS_DIRECT), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("mkdir"), - .value = njs_native_function2(njs_fs_mkdir, 0, NJS_FS_CALLBACK), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("mkdirSync"), - .value = njs_native_function2(njs_fs_mkdir, 0, NJS_FS_DIRECT), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("rmdir"), - .value = njs_native_function2(njs_fs_rmdir, 0, NJS_FS_CALLBACK), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("rmdirSync"), - .value = njs_native_function2(njs_fs_rmdir, 0, NJS_FS_DIRECT), - .writable = 1, - .configurable = 1, - }, + njs_int_t ret, proto_id; + njs_mod_t *module; + njs_opaque_value_t value; - { - .type = NJS_PROPERTY, - .name = njs_string("readdir"), - .value = njs_native_function2(njs_fs_readdir, 0, NJS_FS_CALLBACK), - .writable = 1, - .configurable = 1, - }, + if (vm->options.sandbox) { + return NJS_OK; + } - { - .type = NJS_PROPERTY, - .name = njs_string("readdirSync"), - .value = njs_native_function2(njs_fs_readdir, 0, NJS_FS_DIRECT), - .writable = 1, - .configurable = 1, - }, + njs_fs_stats_proto_id = njs_vm_external_prototype(vm, njs_ext_stats, + njs_nitems(njs_ext_stats)); + if (njs_slow_path(njs_fs_stats_proto_id < 0)) { + return NJS_ERROR; + } - { - .type = NJS_PROPERTY, - .name = njs_string("lstat"), - .value = njs_native_function2(njs_fs_stat, 0, - njs_fs_magic(NJS_FS_CALLBACK, NJS_FS_LSTAT)), - .writable = 1, - .configurable = 1, - }, + njs_fs_dirent_proto_id = njs_vm_external_prototype(vm, njs_ext_dirent, + njs_nitems(njs_ext_dirent)); + if (njs_slow_path(njs_fs_dirent_proto_id < 0)) { + return NJS_ERROR; + } - { - .type = NJS_PROPERTY, - .name = njs_string("lstatSync"), - .value = njs_native_function2(njs_fs_stat, 0, - njs_fs_magic(NJS_FS_DIRECT, NJS_FS_LSTAT)), - .writable = 1, - .configurable = 1, - }, + proto_id = njs_vm_external_prototype(vm, njs_ext_fs, + njs_nitems(njs_ext_fs)); + if (njs_slow_path(proto_id < 0)) { + return NJS_ERROR; + } - { - .type = NJS_PROPERTY, - .name = njs_string("stat"), - .value = njs_native_function2(njs_fs_stat, 0, - njs_fs_magic(NJS_FS_CALLBACK, NJS_FS_STAT)), - .writable = 1, - .configurable = 1, - }, + ret = njs_vm_external_create(vm, njs_value_arg(&value), proto_id, NULL, 1); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } - { - .type = NJS_PROPERTY, - .name = njs_string("statSync"), - .value = njs_native_function2(njs_fs_stat, 0, - njs_fs_magic(NJS_FS_DIRECT, NJS_FS_STAT)), - .writable = 1, - .configurable = 1, - }, -}; + module = njs_module_add(vm, &njs_str_value("fs"), 1); + if (njs_slow_path(module == NULL)) { + return NJS_ERROR; + } + njs_value_assign(&module->value, &value); + module->function.native = 1; -const njs_object_init_t njs_fs_object_init = { - njs_fs_object_properties, - njs_nitems(njs_fs_object_properties), -}; + return NJS_OK; +} diff --git a/src/njs_query_string.c b/external/njs_query_string.c similarity index 90% rename from src/njs_query_string.c rename to external/njs_query_string.c index 7f8d6b1a..701449fc 100644 --- a/src/njs_query_string.c +++ b/external/njs_query_string.c @@ -18,11 +18,93 @@ static const njs_value_t njs_decode_uri_str = static const njs_value_t njs_max_keys_str = njs_string("maxKeys"); +static njs_int_t njs_query_string_parse(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t unused); +static njs_int_t njs_query_string_stringify(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t unused); static njs_int_t njs_query_string_escape(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused); static njs_int_t njs_query_string_unescape(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused); +static njs_int_t njs_query_string_init(njs_vm_t *vm); + + +static njs_external_t njs_ext_query_string[] = { + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("parse"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_query_string_parse, + .magic8 = 0, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("stringify"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_query_string_stringify, + .magic8 = 0, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("decode"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_query_string_parse, + .magic8 = 0, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("encode"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_query_string_stringify, + .magic8 = 0, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("escape"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_query_string_escape, + .magic8 = 0, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("unescape"), + .writable = 1, + .configurable = 1, + .u.method = { + .native = njs_query_string_unescape, + .magic8 = 0, + } + }, +}; + + +njs_module_t njs_query_string_module = { + .name = njs_str("querystring"), + .init = njs_query_string_init, +}; + static njs_object_t * njs_query_string_object_alloc(njs_vm_t *vm) @@ -859,66 +941,31 @@ njs_query_string_unescape(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } -static const njs_object_prop_t njs_query_string_object_properties[] = +static njs_int_t +njs_query_string_init(njs_vm_t *vm) { - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_string("querystring"), - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("parse"), - .value = njs_native_function(njs_query_string_parse, 4), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("stringify"), - .value = njs_native_function(njs_query_string_stringify, 4), - .writable = 1, - .configurable = 1, - }, + njs_int_t ret, proto_id; + njs_mod_t *module; + njs_opaque_value_t value; - { - .type = NJS_PROPERTY, - .name = njs_string("escape"), - .value = njs_native_function(njs_query_string_escape, 1), - .writable = 1, - .configurable = 1, - }, - - { - .type = NJS_PROPERTY, - .name = njs_string("unescape"), - .value = njs_native_function(njs_query_string_unescape, 1), - .writable = 1, - .configurable = 1, - }, + proto_id = njs_vm_external_prototype(vm, njs_ext_query_string, + njs_nitems(njs_ext_query_string)); + if (njs_slow_path(proto_id < 0)) { + return NJS_ERROR; + } - { - .type = NJS_PROPERTY, - .name = njs_string("decode"), - .value = njs_native_function(njs_query_string_parse, 4), - .writable = 1, - .configurable = 1, - }, + ret = njs_vm_external_create(vm, njs_value_arg(&value), proto_id, NULL, 1); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } - { - .type = NJS_PROPERTY, - .name = njs_string("encode"), - .value = njs_native_function(njs_query_string_stringify, 4), - .writable = 1, - .configurable = 1, - }, -}; + module = njs_module_add(vm, &njs_str_value("querystring"), 1); + if (njs_slow_path(module == NULL)) { + return NJS_ERROR; + } + njs_value_assign(&module->value, &value); + module->function.native = 1; -const njs_object_init_t njs_query_string_object_init = { - njs_query_string_object_properties, - njs_nitems(njs_query_string_object_properties), -}; + return NJS_OK; +} diff --git a/external/njs_webcrypto.c b/external/njs_webcrypto.c index 7ac7ed75..450ebfd6 100644 --- a/external/njs_webcrypto.c +++ b/external/njs_webcrypto.c @@ -6,7 +6,6 @@ #include -#include "njs_webcrypto.h" #include "njs_openssl.h" typedef enum { @@ -138,6 +137,8 @@ static njs_int_t njs_webcrypto_result(njs_vm_t *vm, njs_value_t *result, njs_int_t rc); static void njs_webcrypto_error(njs_vm_t *vm, const char *fmt, ...); +static njs_int_t njs_webcrypto_init(njs_vm_t *vm); + static njs_webcrypto_entry_t njs_webcrypto_alg[] = { #define njs_webcrypto_algorithm(type, usage_mask, fmt_mask) \ @@ -487,6 +488,12 @@ static njs_external_t njs_ext_webcrypto[] = { }; +njs_module_t njs_webcrypto_module = { + .name = njs_str("webcrypto"), + .init = njs_webcrypto_init, +}; + + static njs_int_t njs_webcrypto_crypto_key_proto_id; @@ -2652,8 +2659,8 @@ njs_webcrypto_error(njs_vm_t *vm, const char *fmt, ...) } -njs_int_t -njs_external_webcrypto_init(njs_vm_t *vm) +static njs_int_t +njs_webcrypto_init(njs_vm_t *vm) { njs_int_t ret, proto_id; njs_str_t name; diff --git a/external/njs_webcrypto.h b/external/njs_webcrypto.h deleted file mode 100644 index 3331b57b..00000000 --- a/external/njs_webcrypto.h +++ /dev/null @@ -1,15 +0,0 @@ - -/* - * Copyright (C) Dmitry Volyntsev - * Copyright (C) NGINX, Inc. - */ - - -#ifndef _NJS_EXTERNAL_WEBCRYPTO_H_INCLUDED_ -#define _NJS_EXTERNAL_WEBCRYPTO_H_INCLUDED_ - - -njs_int_t njs_external_webcrypto_init(njs_vm_t *vm); - - -#endif /* _NJS_EXTERNAL_WEBCRYPTO_H_INCLUDED_ */ diff --git a/nginx/config b/nginx/config index 7ebdcfe9..a0fbeeea 100644 --- a/nginx/config +++ b/nginx/config @@ -1,8 +1,7 @@ ngx_addon_name="ngx_js_module" NJS_DEPS="$ngx_addon_dir/ngx_js.h \ - $ngx_addon_dir/ngx_js_fetch.h \ - $ngx_addon_dir/../external/njs_webcrypto.h" + $ngx_addon_dir/ngx_js_fetch.h" NJS_SRCS="$ngx_addon_dir/ngx_js.c \ $ngx_addon_dir/ngx_js_fetch.c \ $ngx_addon_dir/../external/njs_webcrypto.c" diff --git a/nginx/config.make b/nginx/config.make index 3623216c..30f88d81 100644 --- a/nginx/config.make +++ b/nginx/config.make @@ -3,7 +3,7 @@ cat << END >> $NGX_MAKEFILE $ngx_addon_dir/../build/libnjs.a: $NGX_MAKEFILE cd $ngx_addon_dir/.. \\ && if [ -f build/Makefile ]; then \$(MAKE) clean; fi \\ - && CFLAGS="\$(CFLAGS)" CC="\$(CC)" ./configure --no-pcre2 \\ + && CFLAGS="\$(CFLAGS)" CC="\$(CC)" ./configure --no-webcrypto --no-pcre2 \\ && \$(MAKE) END diff --git a/nginx/ngx_http_js_module.c b/nginx/ngx_http_js_module.c index 68592ad2..40ee8491 100644 --- a/nginx/ngx_http_js_module.c +++ b/nginx/ngx_http_js_module.c @@ -3515,6 +3515,7 @@ ngx_http_js_init_main_conf(ngx_conf_t *cf, void *conf) options.unhandled_rejection = NJS_VM_OPT_UNHANDLED_REJECTION_THROW; options.ops = &ngx_http_js_ops; options.metas = &ngx_http_js_metas; + options.addons = njs_js_addon_modules; options.argv = ngx_argv; options.argc = ngx_argc; diff --git a/nginx/ngx_js.c b/nginx/ngx_js.c index 012adb48..6799b182 100644 --- a/nginx/ngx_js.c +++ b/nginx/ngx_js.c @@ -10,7 +10,9 @@ #include #include "ngx_js.h" #include "ngx_js_fetch.h" -#include "../external/njs_webcrypto.h" + + +extern njs_module_t njs_webcrypto_module; static njs_external_t ngx_js_ext_core[] = { @@ -66,6 +68,12 @@ static njs_external_t ngx_js_ext_core[] = { }; +njs_module_t *njs_js_addon_modules[] = { + &njs_webcrypto_module, + NULL, +}; + + ngx_int_t ngx_js_call(njs_vm_t *vm, ngx_str_t *fname, ngx_log_t *log, njs_opaque_value_t *args, njs_uint_t nargs) @@ -177,12 +185,6 @@ ngx_js_core_init(njs_vm_t *vm, ngx_log_t *log) return NGX_ERROR; } - ret = njs_external_webcrypto_init(vm); - if (ret != NJS_OK) { - ngx_log_error(NGX_LOG_EMERG, log, 0, "failed to add webcrypto object"); - return NGX_ERROR; - } - proto_id = njs_vm_external_prototype(vm, ngx_js_ext_core, njs_nitems(ngx_js_ext_core)); if (proto_id < 0) { diff --git a/nginx/ngx_js.h b/nginx/ngx_js.h index 16891aea..2a9bf856 100644 --- a/nginx/ngx_js.h +++ b/nginx/ngx_js.h @@ -72,4 +72,7 @@ ngx_int_t ngx_js_string(njs_vm_t *vm, njs_value_t *value, njs_str_t *str); ngx_int_t ngx_js_integer(njs_vm_t *vm, njs_value_t *value, ngx_int_t *n); +extern njs_module_t *njs_js_addon_modules[]; + + #endif /* _NGX_JS_H_INCLUDED_ */ diff --git a/nginx/ngx_stream_js_module.c b/nginx/ngx_stream_js_module.c index 44a7d38e..b2b30907 100644 --- a/nginx/ngx_stream_js_module.c +++ b/nginx/ngx_stream_js_module.c @@ -1537,6 +1537,7 @@ ngx_stream_js_init_main_conf(ngx_conf_t *cf, void *conf) options.unhandled_rejection = NJS_VM_OPT_UNHANDLED_REJECTION_THROW; options.ops = &ngx_stream_js_ops; options.metas = &ngx_stream_js_metas; + options.addons = njs_js_addon_modules; options.argv = ngx_argv; options.argc = ngx_argc; diff --git a/src/njs.h b/src/njs.h index 907950a4..08a27594 100644 --- a/src/njs.h +++ b/src/njs.h @@ -197,11 +197,20 @@ typedef struct { } njs_vm_meta_t; +typedef njs_int_t (*njs_addon_init_pt)(njs_vm_t *vm); + +typedef struct { + njs_str_t name; + njs_addon_init_pt init; +} njs_module_t; + + typedef struct { njs_external_ptr_t external; njs_vm_shared_t *shared; njs_vm_ops_t *ops; njs_vm_meta_t *metas; + njs_module_t **addons; njs_str_t file; char **argv; diff --git a/src/njs_buffer.c b/src/njs_buffer.c index 2c47657c..778babdc 100644 --- a/src/njs_buffer.c +++ b/src/njs_buffer.c @@ -79,6 +79,56 @@ static njs_int_t njs_buffer_fill_typed_array(njs_vm_t *vm, static void njs_buffer_decode_destroy(njs_vm_t *vm, const njs_value_t *source, njs_value_t *target); +static njs_int_t njs_buffer(njs_vm_t *vm, + njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, + njs_value_t *retval); +static njs_int_t njs_buffer_constants(njs_vm_t *vm, + njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, + njs_value_t *retval); +static njs_int_t njs_buffer_constant(njs_vm_t *vm, + njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, + njs_value_t *retval); + +static njs_int_t njs_buffer_init(njs_vm_t *vm); + + +static njs_external_t njs_ext_buffer[] = { + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("Buffer"), + .enumerable = 1, + .u.property = { + .handler = njs_buffer, + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("constants"), + .enumerable = 1, + .u.property = { + .handler = njs_buffer_constants, + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("kMaxLength"), + .enumerable = 1, + .u.property = { + .handler = njs_buffer_constant, + .magic32 = INT32_MAX, + } + }, +}; + + +njs_module_t njs_buffer_module = { + .name = njs_str("buffer"), + .init = njs_buffer_init, +}; + njs_int_t njs_buffer_set(njs_vm_t *vm, njs_value_t *value, const u_char *start, @@ -2934,6 +2984,15 @@ static const njs_object_init_t njs_buffer_constants_init = { }; +static njs_int_t +njs_buffer(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, + njs_value_t *unused, njs_value_t *retval) +{ + return njs_object_prop_init(vm, &njs_buffer_constructor_init, prop, value, + retval); +} + + static njs_int_t njs_buffer_constants(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, njs_value_t *unused, njs_value_t *retval) @@ -2944,47 +3003,40 @@ njs_buffer_constants(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, static njs_int_t -njs_buffer(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, +njs_buffer_constant(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, njs_value_t *unused, njs_value_t *retval) { - return njs_object_prop_init(vm, &njs_buffer_constructor_init, prop, value, - retval); + njs_value_number_set(retval, njs_vm_prop_magic32(prop)); + + return NJS_OK; } -static const njs_object_prop_t njs_buffer_object_properties[] = +static njs_int_t +njs_buffer_init(njs_vm_t *vm) { - { - .type = NJS_PROPERTY, - .name = njs_string("name"), - .value = njs_string("buffer"), - .configurable = 1, - }, + njs_int_t ret, proto_id; + njs_mod_t *module; + njs_opaque_value_t value; - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("constants"), - .value = njs_prop_handler(njs_buffer_constants), - .enumerable = 1, - }, + proto_id = njs_vm_external_prototype(vm, njs_ext_buffer, + njs_nitems(njs_ext_buffer)); + if (njs_slow_path(proto_id < 0)) { + return NJS_ERROR; + } - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("Buffer"), - .value = njs_prop_handler(njs_buffer), - .enumerable = 1, - }, + ret = njs_vm_external_create(vm, njs_value_arg(&value), proto_id, NULL, 1); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } - { - .type = NJS_PROPERTY, - .name = njs_string("kMaxLength"), - .value = njs_value(NJS_NUMBER, 1, INT32_MAX), - .enumerable = 1, - }, -}; + module = njs_module_add(vm, &njs_str_value("buffer"), 1); + if (njs_slow_path(module == NULL)) { + return NJS_ERROR; + } + njs_value_assign(&module->value, &value); + module->function.native = 1; -const njs_object_init_t njs_buffer_object_init = { - njs_buffer_object_properties, - njs_nitems(njs_buffer_object_properties), -}; + return NJS_OK; +} diff --git a/src/njs_buffer.h b/src/njs_buffer.h index 4633ebe1..ee42d94f 100644 --- a/src/njs_buffer.h +++ b/src/njs_buffer.h @@ -35,7 +35,6 @@ njs_int_t njs_buffer_decode_string(njs_vm_t *vm, const njs_value_t *value, extern const njs_object_type_init_t njs_buffer_type_init; -extern const njs_object_init_t njs_buffer_object_init; #endif /* _NJS_BUFFER_H_INCLUDED_ */ diff --git a/src/njs_builtin.c b/src/njs_builtin.c index 5c117683..14ef6f23 100644 --- a/src/njs_builtin.c +++ b/src/njs_builtin.c @@ -53,15 +53,6 @@ static const njs_object_init_t *njs_object_init[] = { }; -static const njs_object_init_t *njs_module_init[] = { - &njs_fs_object_init, - &njs_crypto_object_init, - &njs_query_string_object_init, - &njs_buffer_object_init, - NULL -}; - - static const njs_object_type_init_t *const njs_object_type_init[NJS_OBJ_TYPE_MAX] = { @@ -88,10 +79,6 @@ static const njs_object_type_init_t *const &njs_iterator_type_init, &njs_array_iterator_type_init, - &njs_dirent_type_init, - &njs_stats_type_init, - &njs_hash_type_init, - &njs_hmac_type_init, &njs_typed_array_type_init, /* TypedArray types. */ @@ -135,20 +122,14 @@ njs_int_t njs_builtin_objects_create(njs_vm_t *vm) { njs_int_t ret; - njs_mod_t *module; njs_uint_t i; njs_object_t *object, *string_object; njs_function_t *constructor; njs_vm_shared_t *shared; - njs_lvlhsh_query_t lhq; njs_regexp_pattern_t *pattern; njs_object_prototype_t *prototype; - const njs_object_prop_t *prop; const njs_object_init_t *obj, **p; - static const njs_str_t sandbox_key = njs_str("sandbox"); - static const njs_str_t name_key = njs_str("name"); - shared = njs_mp_zalloc(vm->mem_pool, sizeof(njs_vm_shared_t)); if (njs_slow_path(shared == NULL)) { return NJS_ERROR; @@ -229,62 +210,6 @@ njs_builtin_objects_create(njs_vm_t *vm) return NJS_ERROR; } - njs_lvlhsh_init(&shared->modules_hash); - - lhq.replace = 0; - lhq.pool = vm->mem_pool; - - for (p = njs_module_init; *p != NULL; p++) { - obj = *p; - - module = njs_mp_zalloc(vm->mem_pool, sizeof(njs_mod_t)); - if (njs_slow_path(module == NULL)) { - return NJS_ERROR; - } - - module->function.native = 1; - - ret = njs_object_hash_init(vm, &module->object.shared_hash, obj); - if (njs_slow_path(ret != NJS_OK)) { - return NJS_ERROR; - } - - if (vm->options.sandbox) { - lhq.key = sandbox_key; - lhq.key_hash = njs_djb_hash(sandbox_key.start, sandbox_key.length); - lhq.proto = &njs_object_hash_proto; - - ret = njs_lvlhsh_find(&module->object.shared_hash, &lhq); - if (njs_fast_path(ret != NJS_OK)) { - continue; - } - } - - lhq.key = name_key; - lhq.key_hash = njs_djb_hash(name_key.start, name_key.length); - lhq.proto = &njs_object_hash_proto; - - ret = njs_lvlhsh_find(&module->object.shared_hash, &lhq); - if (njs_fast_path(ret != NJS_OK)) { - return NJS_ERROR; - } - - prop = lhq.value; - - njs_string_get(&prop->value, &module->name); - module->object.shared = 1; - - lhq.key = module->name; - lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length); - lhq.proto = &njs_modules_hash_proto; - lhq.value = module; - - ret = njs_lvlhsh_insert(&shared->modules_hash, &lhq); - if (njs_fast_path(ret != NJS_OK)) { - return NJS_ERROR; - } - } - prototype = shared->prototypes; for (i = NJS_OBJ_TYPE_OBJECT; i < NJS_OBJ_TYPE_MAX; i++) { @@ -338,6 +263,8 @@ njs_builtin_objects_create(njs_vm_t *vm) string_object->shared = 1; string_object->extensible = 0; + njs_lvlhsh_init(&shared->modules_hash); + vm->shared = shared; return NJS_OK; @@ -760,10 +687,13 @@ njs_builtin_match_native_function(njs_vm_t *vm, njs_function_t *function, { uint8_t magic8; njs_int_t ret; + njs_arr_t **pprotos; njs_mod_t *module; njs_uint_t i, n; - njs_value_t value; + njs_value_t value, tag; + njs_object_t object; njs_lvlhsh_each_t lhe; + njs_exotic_slots_t *slots; njs_function_name_t *fn; njs_function_native_t native; njs_builtin_traverse_t ctx; @@ -806,10 +736,10 @@ njs_builtin_match_native_function(njs_vm_t *vm, njs_function_t *function, njs_set_object(&value, &vm->constructors[i].object); ret = njs_value_property(vm, &value, njs_value_arg(&njs_string_name), - &value); + &tag); - if (ret == NJS_OK && njs_is_string(&value)) { - njs_string_get(&value, &ctx.match); + if (ret == NJS_OK && njs_is_string(&tag)) { + njs_string_get(&tag, &ctx.match); } ret = njs_object_traverse(vm, &vm->constructors[i].object, &ctx, @@ -833,7 +763,35 @@ njs_builtin_match_native_function(njs_vm_t *vm, njs_function_t *function, ctx.match = module->name; - ret = njs_object_traverse(vm, &module->object, &ctx, + ret = njs_object_traverse(vm, njs_object(&module->value), &ctx, + njs_builtin_traverse); + + if (ret == NJS_DONE) { + goto found; + } + } + + /* External prototypes (not mapped to global object). */ + + ctx.match = njs_str_value(""); + + for (i = 0; i< vm->protos->items; i++) { + njs_memzero(&object, sizeof(njs_object_t)); + + pprotos = njs_arr_item(vm->protos, i); + slots = (*pprotos)->start; + + object.shared_hash = slots->external_shared_hash; + object.slots = slots; + + njs_set_object(&value, &object); + + ret = njs_object_string_tag(vm, &value, &tag); + if (ret == NJS_OK && njs_is_string(&tag)) { + njs_string_get(&tag, &ctx.match); + } + + ret = njs_object_traverse(vm, njs_object(&value), &ctx, njs_builtin_traverse); if (ret == NJS_DONE) { diff --git a/src/njs_crypto.h b/src/njs_crypto.h deleted file mode 100644 index 27472f1d..00000000 --- a/src/njs_crypto.h +++ /dev/null @@ -1,16 +0,0 @@ - -/* - * Copyright (C) Dmitry Volyntsev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NJS_CRYPTO_H_INCLUDED_ -#define _NJS_CRYPTO_H_INCLUDED_ - -extern const njs_object_init_t njs_crypto_object_init; - -extern const njs_object_type_init_t njs_hash_type_init; -extern const njs_object_type_init_t njs_hmac_type_init; - - -#endif /* _NJS_CRYPTO_H_INCLUDED_ */ diff --git a/src/njs_fs.h b/src/njs_fs.h deleted file mode 100644 index 6d06c2a2..00000000 --- a/src/njs_fs.h +++ /dev/null @@ -1,16 +0,0 @@ - -/* - * Copyright (C) Dmitry Volyntsev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NJS_FS_H_INCLUDED_ -#define _NJS_FS_H_INCLUDED_ - - -extern const njs_object_init_t njs_fs_object_init; - -extern const njs_object_type_init_t njs_dirent_type_init; -extern const njs_object_type_init_t njs_stats_type_init; - -#endif /* _NJS_FS_H_INCLUDED_ */ diff --git a/src/njs_main.h b/src/njs_main.h index 1f505304..aa084ac9 100644 --- a/src/njs_main.h +++ b/src/njs_main.h @@ -82,10 +82,6 @@ #include #include -#include -#include -#include - #include #include diff --git a/src/njs_module.c b/src/njs_module.c index c0211565..842b2b56 100644 --- a/src/njs_module.c +++ b/src/njs_module.c @@ -39,17 +39,17 @@ static njs_bool_t njs_module_realpath_equal(const njs_str_t *path1, static njs_int_t njs_module_read(njs_vm_t *vm, int fd, njs_str_t *body); static njs_mod_t *njs_module_find(njs_vm_t *vm, njs_str_t *name, njs_bool_t local); -static njs_mod_t *njs_module_add(njs_vm_t *vm, njs_str_t *name); static njs_int_t njs_module_insert(njs_parser_t *parser, njs_mod_t *module); njs_int_t njs_module_load(njs_vm_t *vm) { - njs_int_t ret; - njs_mod_t **item, *module; - njs_uint_t i; - njs_value_t *value; + njs_int_t ret; + njs_mod_t **item, *module; + njs_uint_t i; + njs_value_t *value; + njs_object_t *object; if (vm->modules == NULL) { return NJS_OK; @@ -62,7 +62,12 @@ njs_module_load(njs_vm_t *vm) if (module->function.native) { value = njs_scope_valid_value(vm, module->index); - njs_set_object(value, &module->object); + njs_value_assign(value, &module->value); + + object = njs_object_value_copy(vm, value); + if (njs_slow_path(object == NULL)) { + return NJS_ERROR; + } } else { ret = njs_vm_invoke(vm, &module->function, NULL, 0, @@ -125,7 +130,7 @@ njs_parser_module(njs_parser_t *parser, njs_lexer_token_t *token, parser->node = NULL; - module = njs_module_find(parser->vm, &name, 0); + module = njs_module_find(parser->vm, &name, 1); if (module != NULL && module->function.native) { njs_lexer_consume_token(parser->lexer, 1); @@ -153,7 +158,7 @@ njs_parser_module(njs_parser_t *parser, njs_lexer_token_t *token, goto fail; } - module = njs_module_find(parser->vm, &info.file, 0); + module = njs_module_find(parser->vm, &info.file, 1); if (module != NULL) { (void) close(info.fd); njs_lexer_consume_token(parser->lexer, 1); @@ -233,7 +238,7 @@ njs_parser_module_lambda_after(njs_parser_t *parser, njs_lexer_token_t *token, return njs_parser_failed(parser); } - module = njs_module_add(parser->vm, &temp->info.file); + module = njs_module_add(parser->vm, &temp->info.file, 0); if (njs_slow_path(module == NULL)) { parser->lexer = temp->prev; @@ -476,10 +481,10 @@ const njs_lvlhsh_proto_t njs_modules_hash_proto static njs_mod_t * -njs_module_find(njs_vm_t *vm, njs_str_t *name, njs_bool_t local) +njs_module_find(njs_vm_t *vm, njs_str_t *name, njs_bool_t shared) { njs_int_t ret; - njs_mod_t *shared, *module; + njs_mod_t *shrd, *module; njs_object_t *object; njs_lvlhsh_query_t lhq; @@ -492,10 +497,10 @@ njs_module_find(njs_vm_t *vm, njs_str_t *name, njs_bool_t local) } if (njs_lvlhsh_find(&vm->shared->modules_hash, &lhq) == NJS_OK) { - shared = lhq.value; + shrd = lhq.value; - if (!local) { - return shared; + if (shared) { + return shrd; } module = njs_mp_alloc(vm->mem_pool, sizeof(njs_mod_t)); @@ -504,15 +509,12 @@ njs_module_find(njs_vm_t *vm, njs_str_t *name, njs_bool_t local) return NULL; } - memcpy(module, shared, sizeof(njs_mod_t)); - object = &module->object; + memcpy(module, shrd, sizeof(njs_mod_t)); - object->__proto__ = &vm->prototypes[NJS_OBJ_TYPE_OBJECT].object; - object->slots = NULL; - object->shared = 0; - object->extensible = 1; - object->error_data = 0; - object->fast_array = 0; + object = njs_object_value_copy(vm, &module->value); + if (njs_slow_path(object == NULL)) { + return NULL; + } lhq.replace = 0; lhq.value = module; @@ -528,11 +530,12 @@ njs_module_find(njs_vm_t *vm, njs_str_t *name, njs_bool_t local) } -static njs_mod_t * -njs_module_add(njs_vm_t *vm, njs_str_t *name) +njs_mod_t * +njs_module_add(njs_vm_t *vm, njs_str_t *name, njs_bool_t shared) { njs_int_t ret; njs_mod_t *module; + njs_lvlhsh_t *hash; njs_lvlhsh_query_t lhq; module = njs_mp_zalloc(vm->mem_pool, sizeof(njs_mod_t)); @@ -554,7 +557,9 @@ njs_module_add(njs_vm_t *vm, njs_str_t *name) lhq.pool = vm->mem_pool; lhq.proto = &njs_modules_hash_proto; - ret = njs_lvlhsh_insert(&vm->modules_hash, &lhq); + hash = shared ? &vm->shared->modules_hash : &vm->modules_hash; + + ret = njs_lvlhsh_insert(hash, &lhq); if (njs_fast_path(ret == NJS_OK)) { return module; } @@ -622,13 +627,14 @@ njs_module_require(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_string_get(path, &name); - module = njs_module_find(vm, &name, 1); + module = njs_module_find(vm, &name, 0); if (njs_slow_path(module == NULL)) { njs_error(vm, "Cannot find module \"%V\"", &name); return NJS_ERROR; } - njs_set_object(&vm->retval, &module->object); + njs_value_assign(&vm->retval, &module->value); + return NJS_OK; } diff --git a/src/njs_module.h b/src/njs_module.h index 95c9bc03..210f37cf 100644 --- a/src/njs_module.h +++ b/src/njs_module.h @@ -10,7 +10,7 @@ typedef struct { njs_str_t name; - njs_object_t object; + njs_value_t value; njs_index_t index; njs_function_t function; } njs_mod_t; @@ -18,12 +18,14 @@ typedef struct { njs_int_t njs_module_load(njs_vm_t *vm); void njs_module_reset(njs_vm_t *vm); +njs_mod_t *njs_module_add(njs_vm_t *vm, njs_str_t *name, njs_bool_t shared); njs_int_t njs_parser_module(njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current); njs_int_t njs_module_require(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused); +extern njs_module_t *njs_modules[]; extern const njs_lvlhsh_proto_t njs_modules_hash_proto; diff --git a/src/njs_query_string.h b/src/njs_query_string.h deleted file mode 100644 index 1cdbcee9..00000000 --- a/src/njs_query_string.h +++ /dev/null @@ -1,12 +0,0 @@ - -/* - * Copyright (C) Alexander Borisov - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NJS_QUERY_STRING_H_INCLUDED_ -#define _NJS_QUERY_STRING_H_INCLUDED_ - -extern const njs_object_init_t njs_query_string_object_init; - -#endif /* _NJS_QUERY_STRING_H_INCLUDED_ */ diff --git a/src/njs_shell.c b/src/njs_shell.c index 89dcede7..3fdd256a 100644 --- a/src/njs_shell.c +++ b/src/njs_shell.c @@ -23,11 +23,6 @@ #endif -#if (NJS_HAVE_OPENSSL) -#include "../external/njs_webcrypto.h" -#include "../external/njs_webcrypto.c" -#endif - typedef struct { uint8_t disassemble; @@ -91,7 +86,7 @@ typedef struct { static njs_int_t njs_console_init(njs_vm_t *vm, njs_console_t *console); -static njs_int_t njs_externals_init(njs_vm_t *vm, njs_console_t *console); +static njs_int_t njs_externals_init(njs_vm_t *vm); static njs_vm_t *njs_create_vm(njs_opts_t *opts, njs_vm_opt_t *vm_options); static njs_int_t njs_process_script(njs_opts_t *opts, njs_console_t *console, const njs_str_t *script); @@ -211,6 +206,18 @@ static njs_vm_ops_t njs_console_ops = { }; +njs_module_t njs_console_module = { + .name = njs_str("console"), + .init = njs_externals_init, +}; + + +static njs_module_t *njs_console_addon_modules[] = { + &njs_console_module, + NULL, +}; + + static njs_int_t njs_console_proto_id; @@ -279,6 +286,7 @@ main(int argc, char **argv) vm_options.module = opts.module; vm_options.ops = &njs_console_ops; + vm_options.addons = njs_console_addon_modules; vm_options.external = &njs_console; vm_options.argv = opts.argv; vm_options.argc = opts.argc; @@ -691,15 +699,18 @@ njs_console_init(njs_vm_t *vm, njs_console_t *console) static njs_int_t -njs_externals_init(njs_vm_t *vm, njs_console_t *console) +njs_externals_init(njs_vm_t *vm) { - njs_int_t ret; - njs_value_t *value, method; + njs_int_t ret; + njs_value_t *value, method; + njs_console_t *console; static const njs_str_t console_name = njs_str("console"); static const njs_str_t print_name = njs_str("print"); static const njs_str_t console_log = njs_str("console.log"); + console = vm->options.external; + njs_console_proto_id = njs_vm_external_prototype(vm, njs_ext_console, njs_nitems(njs_ext_console)); if (njs_slow_path(njs_console_proto_id < 0)) { @@ -737,13 +748,6 @@ njs_externals_init(njs_vm_t *vm, njs_console_t *console) return NJS_ERROR; } -#if (NJS_HAVE_OPENSSL) - ret = njs_external_webcrypto_init(vm); - if (njs_slow_path(ret != NJS_OK)) { - return NJS_ERROR; - } -#endif - return NJS_OK; } @@ -763,11 +767,6 @@ njs_create_vm(njs_opts_t *opts, njs_vm_opt_t *vm_options) return NULL; } - if (njs_externals_init(vm, vm_options->external) != NJS_OK) { - njs_stderror("failed to add external protos\n"); - return NULL; - } - for (i = 0; i < opts->n_paths; i++) { path.start = (u_char *) opts->paths[i]; path.length = njs_strlen(opts->paths[i]); diff --git a/src/njs_value.h b/src/njs_value.h index 96485d1c..62da8136 100644 --- a/src/njs_value.h +++ b/src/njs_value.h @@ -67,8 +67,6 @@ typedef enum { typedef enum { NJS_DATA_TAG_ANY = 0, NJS_DATA_TAG_EXTERNAL, - NJS_DATA_TAG_CRYPTO_HASH, - NJS_DATA_TAG_CRYPTO_HMAC, NJS_DATA_TAG_TEXT_ENCODER, NJS_DATA_TAG_TEXT_DECODER, NJS_DATA_TAG_ARRAY_ITERATOR, diff --git a/src/njs_vm.c b/src/njs_vm.c index b7a4fef2..b46f88c6 100644 --- a/src/njs_vm.c +++ b/src/njs_vm.c @@ -29,9 +29,11 @@ njs_vm_opt_init(njs_vm_opt_t *options) njs_vm_t * njs_vm_create(njs_vm_opt_t *options) { - njs_mp_t *mp; - njs_vm_t *vm; - njs_int_t ret; + njs_mp_t *mp; + njs_vm_t *vm; + njs_int_t ret; + njs_uint_t i; + njs_module_t **addons; mp = njs_mp_fast_create(2 * njs_pagesize(), 128, 512, 16); if (njs_slow_path(mp == NULL)) { @@ -79,6 +81,23 @@ njs_vm_create(njs_vm_opt_t *options) } } + for (i = 0; njs_modules[i] != NULL; i++) { + ret = njs_modules[i]->init(vm); + if (njs_slow_path(ret != NJS_OK)) { + return NULL; + } + } + + if (options->addons != NULL) { + addons = options->addons; + for (i = 0; addons[i] != NULL; i++) { + ret = addons[i]->init(vm); + if (njs_slow_path(ret != NJS_OK)) { + return NULL; + } + } + } + vm->symbol_generator = NJS_SYMBOL_KNOWN_MAX; if (njs_scope_undefined_index(vm, 0) == NJS_INDEX_ERROR) { diff --git a/src/njs_vm.h b/src/njs_vm.h index 66104e6f..b8f09b56 100644 --- a/src/njs_vm.h +++ b/src/njs_vm.h @@ -56,10 +56,6 @@ typedef enum { #define NJS_OBJ_TYPE_HIDDEN_MIN (NJS_OBJ_TYPE_ITERATOR) NJS_OBJ_TYPE_ITERATOR, NJS_OBJ_TYPE_ARRAY_ITERATOR, - NJS_OBJ_TYPE_FS_DIRENT, - NJS_OBJ_TYPE_FS_STATS, - NJS_OBJ_TYPE_CRYPTO_HASH, - NJS_OBJ_TYPE_CRYPTO_HMAC, NJS_OBJ_TYPE_TYPED_ARRAY, #define NJS_OBJ_TYPE_HIDDEN_MAX (NJS_OBJ_TYPE_TYPED_ARRAY + 1) #define NJS_OBJ_TYPE_NORMAL_MAX (NJS_OBJ_TYPE_HIDDEN_MAX) diff --git a/src/test/njs_externals_test.c b/src/test/njs_externals_test.c index 74cede07..68ec80f0 100644 --- a/src/test/njs_externals_test.c +++ b/src/test/njs_externals_test.c @@ -8,11 +8,6 @@ #include "njs_externals_test.h" -#if (NJS_HAVE_OPENSSL) -#include "../external/njs_webcrypto.h" -#include "../external/njs_webcrypto.c" -#endif - typedef struct { njs_lvlhsh_t hash; @@ -864,15 +859,6 @@ njs_externals_init_internal(njs_vm_t *vm, njs_unit_test_req_init_t *init, njs_int_t njs_externals_shared_init(njs_vm_t *vm) { -#if (NJS_HAVE_OPENSSL) - njs_int_t ret; - - ret = njs_external_webcrypto_init(vm); - if (njs_slow_path(ret != NJS_OK)) { - return NJS_ERROR; - } -#endif - return njs_externals_init_internal(vm, njs_test_requests, 1, 1); } diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index 4f13f14c..c8440d12 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -19136,10 +19136,6 @@ static njs_unit_test_t njs_crypto_module_test[] = "Hash('sha1').update('AB').digest('hex')"), njs_str("06d945942aa26a61be18c3e22bf19bbca8dd2b5d") }, - { njs_str("var h = require('crypto').createHash('sha1');" - "h.constructor.name"), - njs_str("Hash") }, - { njs_str("var hash = require('crypto').createHash.bind(undefined, 'md5');" "['hex', 'base64', 'base64url'].map(e => {" " var h = hash().update('AB').digest().toString(e);" @@ -19319,10 +19315,6 @@ static njs_unit_test_t njs_crypto_module_test[] = "Hmac('sha1', '').digest('hex')"), njs_str("fbdb1d1b18aa6c08324b7d64b71fb76370690e1d") }, - { njs_str("var h = require('crypto').createHmac('sha1', '');" - "h.constructor.name"), - njs_str("Hmac") }, - { njs_str("require('crypto').createHmac('sha1', '').digest() instanceof Buffer"), njs_str("true") }, @@ -21563,7 +21555,7 @@ static njs_unit_test_t njs_backtraces_test[] = { njs_str("var h = require('crypto').createHash('sha1');" "h.update([])"), njs_str("TypeError: data argument \"array\" is not a string or Buffer-like object\n" - " at Hash.prototype.update (native)\n" + " at Hash.update (native)\n" " at main (:1)\n") }, { njs_str("require('crypto').createHmac('sha1', [])"), @@ -21574,7 +21566,7 @@ static njs_unit_test_t njs_backtraces_test[] = { njs_str("var h = require('crypto').createHmac('sha1', 'secret');" "h.update([])"), njs_str("TypeError: data argument \"array\" is not a string or Buffer-like object\n" - " at Hmac.prototype.update (native)\n" + " at Hmac.update (native)\n" " at main (:1)\n") }, { njs_str("function f(o) {function f_in(o) {return o.a.a};" -- 2.47.3