[njs] Nodejs style file methods.
Dmitry Volyntsev
xeioex at nginx.com
Fri Nov 17 16:06:05 UTC 2017
details: http://hg.nginx.org/njs/rev/5c6aa60224cb
branches:
changeset: 426:5c6aa60224cb
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Fri Nov 17 18:55:07 2017 +0300
description:
Nodejs style file methods.
diffstat:
Makefile | 27 +
njs/njs_builtin.c | 84 ++-
njs/njs_builtin.h | 1 +
njs/njs_fs.c | 1095 +++++++++++++++++++++++++++++++++++++++
njs/njs_fs.h | 13 +
njs/njs_generator.c | 1 +
njs/njs_lexer_keyword.c | 1 +
njs/njs_module.c | 85 +++
njs/njs_module.h | 22 +
njs/njs_object_hash.h | 56 +
njs/njs_parser.c | 1 +
njs/njs_parser.h | 1 +
njs/njs_string.c | 46 +
njs/njs_string.h | 1 +
njs/njs_vm.h | 20 +-
njs/njscript.c | 3 +
njs/test/njs_expect_test.exp | 221 +++++++
njs/test/njs_interactive_test.c | 5 +
njs/test/njs_unit_test.c | 136 ++++
19 files changed, 1817 insertions(+), 2 deletions(-)
diffs (truncated from 2098 to 1000 lines):
diff -r 17909969892f -r 5c6aa60224cb Makefile
--- a/Makefile Fri Nov 17 18:55:07 2017 +0300
+++ b/Makefile Fri Nov 17 18:55:07 2017 +0300
@@ -22,6 +22,8 @@ NXT_BUILDDIR = build
$(NXT_BUILDDIR)/njs_date.o \
$(NXT_BUILDDIR)/njs_error.o \
$(NXT_BUILDDIR)/njs_math.o \
+ $(NXT_BUILDDIR)/njs_module.o \
+ $(NXT_BUILDDIR)/njs_fs.o \
$(NXT_BUILDDIR)/njs_extern.o \
$(NXT_BUILDDIR)/njs_variable.o \
$(NXT_BUILDDIR)/njs_builtin.o \
@@ -56,6 +58,8 @@ NXT_BUILDDIR = build
$(NXT_BUILDDIR)/njs_date.o \
$(NXT_BUILDDIR)/njs_error.o \
$(NXT_BUILDDIR)/njs_math.o \
+ $(NXT_BUILDDIR)/njs_module.o \
+ $(NXT_BUILDDIR)/njs_fs.o \
$(NXT_BUILDDIR)/njs_extern.o \
$(NXT_BUILDDIR)/njs_variable.o \
$(NXT_BUILDDIR)/njs_builtin.o \
@@ -299,6 +303,28 @@ dist:
-I$(NXT_LIB) -Injs \
njs/njs_math.c
+$(NXT_BUILDDIR)/njs_module.o: \
+ $(NXT_BUILDDIR)/libnxt.a \
+ njs/njscript.h \
+ njs/njs_vm.h \
+ njs/njs_module.h \
+ njs/njs_module.c \
+
+ $(NXT_CC) -c -o $(NXT_BUILDDIR)/njs_module.o $(NXT_CFLAGS) \
+ -I$(NXT_LIB) -Injs \
+ njs/njs_module.c
+
+$(NXT_BUILDDIR)/njs_fs.o: \
+ $(NXT_BUILDDIR)/libnxt.a \
+ njs/njscript.h \
+ njs/njs_vm.h \
+ njs/njs_fs.h \
+ njs/njs_fs.c \
+
+ $(NXT_CC) -c -o $(NXT_BUILDDIR)/njs_fs.o $(NXT_CFLAGS) \
+ -I$(NXT_LIB) -Injs \
+ njs/njs_fs.c
+
$(NXT_BUILDDIR)/njs_extern.o: \
$(NXT_BUILDDIR)/libnxt.a \
njs/njscript.h \
@@ -332,6 +358,7 @@ dist:
njs/njs_string.h \
njs/njs_object.h \
njs/njs_array.h \
+ njs/njs_module.h \
njs/njs_function.h \
njs/njs_regexp.h \
njs/njs_parser.h \
diff -r 17909969892f -r 5c6aa60224cb njs/njs_builtin.c
--- a/njs/njs_builtin.c Fri Nov 17 18:55:07 2017 +0300
+++ b/njs/njs_builtin.c Fri Nov 17 18:55:07 2017 +0300
@@ -30,6 +30,8 @@
#include <njs_date.h>
#include <njs_error.h>
#include <njs_math.h>
+#include <njs_module.h>
+#include <njs_fs.h>
#include <string.h>
#include <stdio.h>
@@ -54,6 +56,11 @@ const njs_object_init_t *njs_object_i
};
+const njs_object_init_t *njs_module_init[] = {
+ &njs_fs_object_init /* fs */
+};
+
+
const njs_object_init_t *njs_prototype_init[] = {
&njs_object_prototype_init,
&njs_array_prototype_init,
@@ -111,8 +118,10 @@ njs_builtin_objects_create(njs_vm_t *vm)
{
nxt_int_t ret;
nxt_uint_t i;
+ njs_module_t *module;
njs_object_t *objects;
njs_function_t *functions, *constructors;
+ nxt_lvlhsh_query_t lhq;
njs_object_prototype_t *prototypes;
static const njs_object_prototype_t prototype_values[] = {
@@ -193,6 +202,7 @@ njs_builtin_objects_create(njs_vm_t *vm)
NULL, /* encodeURIComponent */
NULL, /* decodeURI */
NULL, /* decodeURIComponent */
+ NULL, /* require */
};
static const njs_function_init_t native_functions[] = {
@@ -208,6 +218,7 @@ njs_builtin_objects_create(njs_vm_t *vm)
{ njs_string_encode_uri_component, { NJS_SKIP_ARG, NJS_STRING_ARG } },
{ njs_string_decode_uri, { NJS_SKIP_ARG, NJS_STRING_ARG } },
{ njs_string_decode_uri_component, { NJS_SKIP_ARG, NJS_STRING_ARG } },
+ { njs_module_require, { NJS_SKIP_ARG, NJS_STRING_ARG } },
};
static const njs_object_prop_t null_proto_property = {
@@ -249,6 +260,37 @@ njs_builtin_objects_create(njs_vm_t *vm)
objects[i].shared = 1;
}
+ lhq.replace = 0;
+ lhq.proto = &njs_modules_hash_proto;
+ lhq.pool = vm->mem_cache_pool;
+
+ for (i = NJS_MODULE_FS; i < NJS_MODULE_MAX; i++) {
+ module = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_module_t));
+ if (nxt_slow_path(module == NULL)) {
+ return NJS_ERROR;
+ }
+
+ module->name = njs_module_init[i]->name;
+
+ ret = njs_object_hash_create(vm, &module->object.shared_hash,
+ njs_module_init[i]->properties,
+ njs_module_init[i]->items);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NXT_ERROR;
+ }
+
+ module->object.shared = 1;
+
+ lhq.key = module->name;
+ lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
+ lhq.value = module;
+
+ ret = nxt_lvlhsh_insert(&vm->modules_hash, &lhq);
+ if (nxt_fast_path(ret != NXT_OK)) {
+ return NXT_ERROR;
+ }
+ }
+
functions = vm->shared->functions;
for (i = NJS_FUNCTION_EVAL; i < NJS_FUNCTION_MAX; i++) {
@@ -857,10 +899,11 @@ njs_builtin_match_native_function(njs_vm
size_t len;
nxt_str_t string;
nxt_uint_t i;
+ njs_module_t *module;
njs_object_t *objects;
njs_function_t *constructors;
njs_object_prop_t *prop;
- nxt_lvlhsh_each_t lhe;
+ nxt_lvlhsh_each_t lhe, lhe_prop;
njs_object_prototype_t *prototypes;
objects = vm->shared->objects;
@@ -978,5 +1021,44 @@ njs_builtin_match_native_function(njs_vm
}
}
+ nxt_lvlhsh_each_init(&lhe, &njs_modules_hash_proto);
+
+ for ( ;; ) {
+ module = nxt_lvlhsh_each(&vm->modules_hash, &lhe);
+ if (module == NULL) {
+ break;
+ }
+
+ nxt_lvlhsh_each_init(&lhe_prop, &njs_object_hash_proto);
+
+ for ( ;; ) {
+ prop = nxt_lvlhsh_each(&module->object.shared_hash, &lhe_prop);
+ if (prop == NULL) {
+ break;
+ }
+
+ if (!njs_is_function(&prop->value)) {
+ continue;
+ }
+
+ if (function == prop->value.data.u.function) {
+ njs_string_get(&prop->name, &string);
+ len = module->name.length + string.length + sizeof(".");
+
+ buf = nxt_mem_cache_zalloc(vm->mem_cache_pool, len);
+ if (buf == NULL) {
+ return NXT_ERROR;
+ }
+
+ snprintf(buf, len, "%s.%s", module->name.start, string.start);
+
+ name->length = len;
+ name->start = (u_char *) buf;
+
+ return NXT_OK;
+ }
+ }
+ }
+
return NXT_DECLINED;
}
diff -r 17909969892f -r 5c6aa60224cb njs/njs_builtin.h
--- a/njs/njs_builtin.h Fri Nov 17 18:55:07 2017 +0300
+++ b/njs/njs_builtin.h Fri Nov 17 18:55:07 2017 +0300
@@ -9,6 +9,7 @@
extern const njs_object_init_t *njs_object_init[];
+extern const njs_object_init_t *njs_module_init[];
extern const njs_object_init_t *njs_prototype_init[];
extern const njs_object_init_t *njs_constructor_init[];
diff -r 17909969892f -r 5c6aa60224cb njs/njs_fs.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/njs/njs_fs.c Fri Nov 17 18:55:07 2017 +0300
@@ -0,0 +1,1095 @@
+
+/*
+ * Copyright (C) Dmitry Volyntsev
+ * Copyright (C) NGINX, Inc.
+ */
+
+#include <nxt_auto_config.h>
+#include <nxt_alignment.h>
+#include <nxt_types.h>
+#include <nxt_clang.h>
+#include <nxt_string.h>
+#include <nxt_stub.h>
+#include <nxt_djb_hash.h>
+#include <nxt_array.h>
+#include <nxt_lvlhsh.h>
+#include <nxt_random.h>
+#include <nxt_mem_cache_pool.h>
+#include <njscript.h>
+#include <njs_vm.h>
+#include <njs_string.h>
+#include <njs_object.h>
+#include <njs_object_hash.h>
+#include <njs_function.h>
+#include <njs_error.h>
+#include <njs_fs.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdio.h>
+
+
+typedef struct {
+ union {
+ njs_continuation_t cont;
+ u_char padding[NJS_CONTINUATION_SIZE];
+ } u;
+
+ nxt_bool_t done;
+} njs_fs_cont_t;
+
+
+typedef struct {
+ nxt_str_t name;
+ int value;
+} njs_fs_entry_t;
+
+
+static njs_ret_t njs_fs_read_file(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused);
+static njs_ret_t njs_fs_read_file_sync(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused);
+static njs_ret_t njs_fs_append_file(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused);
+static njs_ret_t njs_fs_write_file(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused);
+static njs_ret_t njs_fs_append_file_sync(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused);
+static njs_ret_t njs_fs_write_file_sync(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused);
+static njs_ret_t njs_fs_write_file_internal(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, int default_flags);
+static njs_ret_t njs_fs_write_file_sync_internal(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, int default_flags);
+static njs_ret_t njs_fs_done(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused);
+
+static njs_ret_t njs_fs_error(njs_vm_t *vm, const char *syscall,
+ const char *description, njs_value_t *path, int errn, njs_value_t *retval);
+static int njs_fs_flags(nxt_str_t *value);
+static mode_t njs_fs_mode(njs_value_t *value);
+
+
+static const njs_value_t njs_fs_errno_string = njs_string("errno");
+static const njs_value_t njs_fs_path_string = njs_string("path");
+static const njs_value_t njs_fs_syscall_string = njs_string("syscall");
+
+
+static njs_fs_entry_t njs_flags_table[] = {
+ { nxt_string("r"), O_RDONLY },
+ { nxt_string("r+"), O_RDWR },
+ { nxt_string("w"), O_TRUNC | O_CREAT | O_WRONLY },
+ { nxt_string("w+"), O_TRUNC | O_CREAT | O_RDWR },
+ { nxt_string("a"), O_APPEND | O_CREAT | O_WRONLY },
+ { nxt_string("a+"), O_APPEND | O_CREAT | O_RDWR },
+ { nxt_string("rs"), O_SYNC | O_RDONLY },
+ { nxt_string("sr"), O_SYNC | O_RDONLY },
+ { nxt_string("wx"), O_TRUNC | O_CREAT | O_EXCL | O_WRONLY },
+ { nxt_string("xw"), O_TRUNC | O_CREAT | O_EXCL | O_WRONLY },
+ { nxt_string("ax"), O_APPEND | O_CREAT | O_EXCL | O_WRONLY },
+ { nxt_string("xa"), O_APPEND | O_CREAT | O_EXCL | O_WRONLY },
+ { nxt_string("rs+"), O_SYNC | O_RDWR },
+ { nxt_string("sr+"), O_SYNC | O_RDWR },
+ { nxt_string("wx+"), O_TRUNC | O_CREAT | O_EXCL | O_RDWR },
+ { nxt_string("xw+"), O_TRUNC | O_CREAT | O_EXCL | O_RDWR },
+ { nxt_string("ax+"), O_APPEND | O_CREAT | O_EXCL | O_RDWR },
+ { nxt_string("xa+"), O_APPEND | O_CREAT | O_EXCL | O_RDWR },
+ { nxt_null_string, 0 }
+};
+
+
+static njs_ret_t
+njs_fs_read_file(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+ njs_index_t unused)
+{
+ int fd, errn, flags;
+ u_char *p, *start, *end;
+ ssize_t n, length;
+ nxt_str_t flag, encoding;
+ njs_ret_t ret;
+ const char *path, *syscall, *description;
+ struct stat sb;
+ njs_value_t *callback, arguments[3];
+ njs_fs_cont_t *cont;
+ njs_object_prop_t *prop;
+ nxt_lvlhsh_query_t lhq;
+
+ if (nxt_slow_path(nargs < 3)) {
+ njs_exception_type_error(vm, "too few arguments", NULL);
+ return NJS_ERROR;
+ }
+
+ if (nxt_slow_path(!njs_is_string(&args[1]))) {
+ njs_exception_type_error(vm, "path must be a string", NULL);
+ return NJS_ERROR;
+ }
+
+ flag.start = NULL;
+ encoding.length = 0;
+ encoding.start = NULL;
+
+ if (!njs_is_function(&args[2])) {
+ if (njs_is_string(&args[2])) {
+ njs_string_get(&args[2], &encoding);
+
+ } else if (njs_is_object(&args[2])) {
+ lhq.key_hash = NJS_FLAG_HASH;
+ lhq.key = nxt_string_value("flag");
+ lhq.proto = &njs_object_hash_proto;
+
+ ret = nxt_lvlhsh_find(&args[2].data.u.object->hash, &lhq);
+ if (ret == NXT_OK) {
+ prop = lhq.value;
+ njs_string_get(&prop->value, &flag);
+ }
+
+ lhq.key_hash = NJS_ENCODING_HASH;
+ lhq.key = nxt_string_value("encoding");
+ lhq.proto = &njs_object_hash_proto;
+
+ ret = nxt_lvlhsh_find(&args[2].data.u.object->hash, &lhq);
+ if (ret == NXT_OK) {
+ prop = lhq.value;
+ njs_string_get(&prop->value, &encoding);
+ }
+
+ } else {
+ njs_exception_type_error(vm, "Unknown options type "
+ "(a string or object required)", NULL);
+ return NJS_ERROR;
+ }
+
+ if (nxt_slow_path(nargs < 4 || !njs_is_function(&args[3]))) {
+ njs_exception_type_error(vm, "callback must be a function", NULL);
+ return NJS_ERROR;
+ }
+
+ callback = &args[3];
+
+ } else {
+ if (nxt_slow_path(!njs_is_function(&args[2]))) {
+ njs_exception_type_error(vm, "callback must be a function", NULL);
+ return NJS_ERROR;
+ }
+
+ callback = &args[2];
+ }
+
+ if (flag.start == NULL) {
+ flag = nxt_string_value("r");
+ }
+
+ flags = njs_fs_flags(&flag);
+ if (nxt_slow_path(flags == -1)) {
+ njs_exception_type_error(vm, "Unknown file open flags: '%.*s'",
+ (int) flag.length, flag.start);
+ return NJS_ERROR;
+ }
+
+ path = (char *) njs_string_to_c_string(vm, &args[1]);
+ if (nxt_slow_path(path == NULL)) {
+ return NJS_ERROR;
+ }
+
+ if (encoding.length != 0
+ && (encoding.length != 4 || memcmp(encoding.start, "utf8", 4) != 0))
+ {
+ njs_exception_type_error(vm, "Unknown encoding: '%.*s'",
+ (int) encoding.length, encoding.start);
+ return NJS_ERROR;
+ }
+
+ description = NULL;
+
+ /* GCC 4 complains about uninitialized errn and syscall. */
+ errn = 0;
+ syscall = NULL;
+
+ fd = open(path, flags);
+ if (nxt_slow_path(fd < 0)) {
+ errn = errno;
+ description = strerror(errno);
+ syscall = "open";
+ goto done;
+ }
+
+ ret = fstat(fd, &sb);
+ if (nxt_slow_path(ret == -1)) {
+ errn = errno;
+ description = strerror(errno);
+ syscall = "stat";
+ goto done;
+ }
+
+ if (nxt_slow_path(!S_ISREG(sb.st_mode))) {
+ errn = 0;
+ description = "File is not regular";
+ syscall = "stat";
+ goto done;
+ }
+
+ if (encoding.length != 0) {
+ length = sb.st_size;
+
+ } else {
+ length = 0;
+ }
+
+ start = njs_string_alloc(vm, &arguments[2], sb.st_size, length);
+ if (nxt_slow_path(start == NULL)) {
+ goto memory_error;
+ }
+
+ p = start;
+ end = p + sb.st_size;
+
+ while (p < end) {
+ n = read(fd, p, end - p);
+ if (nxt_slow_path(n == -1)) {
+ if (errno == EINTR) {
+ continue;
+ }
+
+ errn = errno;
+ description = strerror(errno);
+ syscall = "read";
+ goto done;
+ }
+
+ p += n;
+ }
+
+ if (encoding.length != 0) {
+ length = nxt_utf8_length(start, sb.st_size);
+
+ if (length >= 0) {
+ njs_string_offset_map_init(start, sb.st_size);
+ njs_string_length_set(&arguments[2], length);
+
+ } else {
+ errn = 0;
+ description = "Non-UTF8 file, convertion is not implemented";
+ syscall = NULL;
+ goto done;
+ }
+ }
+
+done:
+
+ if (fd > 0) {
+ close(fd);
+ }
+
+ if (description != 0) {
+ ret = njs_fs_error(vm, syscall, description, &args[1], errn,
+ &arguments[1]);
+
+ if (nxt_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ arguments[2] = njs_value_void;
+
+ } else {
+ arguments[1] = njs_value_void;
+ }
+
+ arguments[0] = njs_value_void;
+
+ cont = njs_vm_continuation(vm);
+ cont->u.cont.function = njs_fs_done;
+
+ return njs_function_apply(vm, callback->data.u.function,
+ arguments, 3, (njs_index_t) &vm->retval);
+
+memory_error:
+
+ if (fd > 0) {
+ close(fd);
+ }
+
+ njs_exception_memory_error(vm);
+
+ return NJS_ERROR;
+}
+
+
+static njs_ret_t
+njs_fs_read_file_sync(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+ njs_index_t unused)
+{
+ int fd, errn, flags;
+ u_char *p, *start, *end;
+ ssize_t n, length;
+ nxt_str_t flag, encoding;
+ njs_ret_t ret;
+ const char *path, *syscall, *description;
+ struct stat sb;
+ njs_object_prop_t *prop;
+ nxt_lvlhsh_query_t lhq;
+
+ if (nxt_slow_path(nargs < 2)) {
+ njs_exception_type_error(vm, "too few arguments", NULL);
+ return NJS_ERROR;
+ }
+
+ if (nxt_slow_path(!njs_is_string(&args[1]))) {
+ njs_exception_type_error(vm, "path must be a string", NULL);
+ return NJS_ERROR;
+ }
+
+ flag.start = NULL;
+ encoding.length = 0;
+ encoding.start = NULL;
+
+ if (nargs == 3) {
+ if (njs_is_string(&args[2])) {
+ njs_string_get(&args[2], &encoding);
+
+ } else if (njs_is_object(&args[2])) {
+ lhq.key_hash = NJS_FLAG_HASH;
+ lhq.key = nxt_string_value("flag");
+ lhq.proto = &njs_object_hash_proto;
+
+ ret = nxt_lvlhsh_find(&args[2].data.u.object->hash, &lhq);
+ if (ret == NXT_OK) {
+ prop = lhq.value;
+ njs_string_get(&prop->value, &flag);
+ }
+
+ lhq.key_hash = NJS_ENCODING_HASH;
+ lhq.key = nxt_string_value("encoding");
+ lhq.proto = &njs_object_hash_proto;
+
+ ret = nxt_lvlhsh_find(&args[2].data.u.object->hash, &lhq);
+ if (ret == NXT_OK) {
+ prop = lhq.value;
+ njs_string_get(&prop->value, &encoding);
+ }
+
+ } else {
+ njs_exception_type_error(vm, "Unknown options type "
+ "(a string or object required)", NULL);
+ return NJS_ERROR;
+ }
+ }
+
+ if (flag.start == NULL) {
+ flag = nxt_string_value("r");
+ }
+
+ flags = njs_fs_flags(&flag);
+ if (nxt_slow_path(flags == -1)) {
+ njs_exception_type_error(vm, "Unknown file open flags: '%.*s'",
+ (int) flag.length, flag.start);
+ return NJS_ERROR;
+ }
+
+ path = (char *) njs_string_to_c_string(vm, &args[1]);
+ if (nxt_slow_path(path == NULL)) {
+ return NJS_ERROR;
+ }
+
+ if (encoding.length != 0
+ && (encoding.length != 4 || memcmp(encoding.start, "utf8", 4) != 0))
+ {
+ njs_exception_type_error(vm, "Unknown encoding: '%.*s'",
+ (int) encoding.length, encoding.start);
+ return NJS_ERROR;
+ }
+
+ description = NULL;
+
+ /* GCC 4 complains about uninitialized errn and syscall. */
+ errn = 0;
+ syscall = NULL;
+
+ fd = open(path, flags);
+ if (nxt_slow_path(fd < 0)) {
+ errn = errno;
+ description = strerror(errno);
+ syscall = "open";
+ goto done;
+ }
+
+ ret = fstat(fd, &sb);
+ if (nxt_slow_path(ret == -1)) {
+ errn = errno;
+ description = strerror(errno);
+ syscall = "stat";
+ goto done;
+ }
+
+ if (nxt_slow_path(!S_ISREG(sb.st_mode))) {
+ errn = 0;
+ description = "File is not regular";
+ syscall = "stat";
+ goto done;
+ }
+
+ if (encoding.length != 0) {
+ length = sb.st_size;
+
+ } else {
+ length = 0;
+ }
+
+ start = njs_string_alloc(vm, &vm->retval, sb.st_size, length);
+ if (nxt_slow_path(start == NULL)) {
+ goto memory_error;
+ }
+
+ p = start;
+ end = p + sb.st_size;
+
+ while (p < end) {
+ n = read(fd, p, end - p);
+ if (nxt_slow_path(n == -1)) {
+ if (errno == EINTR) {
+ continue;
+ }
+
+ errn = errno;
+ description = strerror(errno);
+ syscall = "read";
+ goto done;
+ }
+
+ p += n;
+ }
+
+ if (encoding.length != 0) {
+ length = nxt_utf8_length(start, sb.st_size);
+
+ if (length >= 0) {
+ njs_string_offset_map_init(start, sb.st_size);
+ njs_string_length_set(&vm->retval, length);
+
+ } else {
+ errn = 0;
+ description = "Non-UTF8 file, convertion is not implemented";
+ syscall = NULL;
+ goto done;
+ }
+ }
+
+done:
+
+ if (fd > 0) {
+ close(fd);
+ }
+
+ if (description != 0) {
+ (void) njs_fs_error(vm, syscall, description, &args[1], errn,
+ &vm->retval);
+
+ return NJS_ERROR;
+ }
+
+ return NJS_OK;
+
+memory_error:
+
+ if (fd > 0) {
+ close(fd);
+ }
+
+ njs_exception_memory_error(vm);
+
+ return NJS_ERROR;
+}
+
+
+static njs_ret_t
+njs_fs_append_file(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+ njs_index_t unused)
+{
+ return njs_fs_write_file_internal(vm, args, nargs,
+ O_APPEND | O_CREAT | O_WRONLY);
+}
+
+
+static njs_ret_t
+njs_fs_write_file(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+ njs_index_t unused)
+{
+ return njs_fs_write_file_internal(vm, args, nargs,
+ O_TRUNC | O_CREAT | O_WRONLY);
+}
+
+
+static njs_ret_t njs_fs_append_file_sync(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused)
+{
+ return njs_fs_write_file_sync_internal(vm, args, nargs,
+ O_APPEND | O_CREAT | O_WRONLY);
+}
+
+
+static njs_ret_t njs_fs_write_file_sync(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused)
+{
+ return njs_fs_write_file_sync_internal(vm, args, nargs,
+ O_TRUNC | O_CREAT | O_WRONLY);
+}
+
+
+static njs_ret_t njs_fs_write_file_internal(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, int default_flags)
+{
+ int fd, errn, flags;
+ u_char *p, *end;
+ mode_t md;
+ ssize_t n;
+ nxt_str_t data, flag, encoding;
+ njs_ret_t ret;
+ const char *path, *syscall, *description;
+ njs_value_t *callback, *mode, arguments[2];
+ njs_fs_cont_t *cont;
+ njs_object_prop_t *prop;
+ nxt_lvlhsh_query_t lhq;
+
+ if (nxt_slow_path(nargs < 4)) {
+ njs_exception_type_error(vm, "too few arguments", NULL);
+ return NJS_ERROR;
+ }
+
+ if (nxt_slow_path(!njs_is_string(&args[1]))) {
+ njs_exception_type_error(vm, "path must be a string", NULL);
+ return NJS_ERROR;
+ }
+
+ if (nxt_slow_path(!njs_is_string(&args[2]))) {
+ njs_exception_type_error(vm, "data must be a string", NULL);
+ return NJS_ERROR;
+ }
+
+ mode = NULL;
+ flag.start = NULL;
+ encoding.length = 0;
+ encoding.start = NULL;
+
+ if (!njs_is_function(&args[3])) {
+ if (njs_is_string(&args[3])) {
+ njs_string_get(&args[3], &encoding);
+
+ } else if (njs_is_object(&args[3])) {
+ lhq.key_hash = NJS_FLAG_HASH;
+ lhq.key = nxt_string_value("flag");
+ lhq.proto = &njs_object_hash_proto;
+
+ ret = nxt_lvlhsh_find(&args[3].data.u.object->hash, &lhq);
+ if (ret == NXT_OK) {
+ prop = lhq.value;
+ njs_string_get(&prop->value, &flag);
+ }
+
+ lhq.key_hash = NJS_ENCODING_HASH;
+ lhq.key = nxt_string_value("encoding");
+ lhq.proto = &njs_object_hash_proto;
+
+ ret = nxt_lvlhsh_find(&args[3].data.u.object->hash, &lhq);
+ if (ret == NXT_OK) {
+ prop = lhq.value;
+ njs_string_get(&prop->value, &encoding);
+ }
+
+ lhq.key_hash = NJS_MODE_HASH;
+ lhq.key = nxt_string_value("mode");
+ lhq.proto = &njs_object_hash_proto;
+
+ ret = nxt_lvlhsh_find(&args[3].data.u.object->hash, &lhq);
+ if (ret == NXT_OK) {
+ prop = lhq.value;
+ mode = &prop->value;
+ }
+
+ } else {
+ njs_exception_type_error(vm, "Unknown options type "
+ "(a string or object required)", NULL);
+ return NJS_ERROR;
+ }
+
+ if (nxt_slow_path(nargs < 5 || !njs_is_function(&args[4]))) {
+ njs_exception_type_error(vm, "callback must be a function", NULL);
+ return NJS_ERROR;
+ }
+
+ callback = &args[4];
+
+ } else {
+ if (nxt_slow_path(!njs_is_function(&args[3]))) {
+ njs_exception_type_error(vm, "callback must be a function", NULL);
+ return NJS_ERROR;
+ }
+
+ callback = &args[3];
+ }
+
+ if (flag.start != NULL) {
+ flags = njs_fs_flags(&flag);
+ if (nxt_slow_path(flags == -1)) {
+ njs_exception_type_error(vm, "Unknown file open flags: '%.*s'",
+ (int) flag.length, flag.start);
+ return NJS_ERROR;
+ }
+
+ } else {
+ flags = default_flags;
+ }
+
+ if (mode != NULL) {
+ md = njs_fs_mode(mode);
+
+ } else {
+ md = 0666;
+ }
+
+ path = (char *) njs_string_to_c_string(vm, &args[1]);
+ if (nxt_slow_path(path == NULL)) {
+ return NJS_ERROR;
+ }
+
+ if (encoding.length != 0
+ && (encoding.length != 4 || memcmp(encoding.start, "utf8", 4) != 0))
+ {
+ njs_exception_type_error(vm, "Unknown encoding: '%.*s'",
+ (int) encoding.length, encoding.start);
+ return NJS_ERROR;
+ }
+
+ description = NULL;
+
+ /* GCC 4 complains about uninitialized errn and syscall. */
+ errn = 0;
+ syscall = NULL;
+
+ fd = open(path, flags, md);
+ if (nxt_slow_path(fd < 0)) {
+ errn = errno;
+ description = strerror(errno);
+ syscall = "open";
+ goto done;
+ }
+
+ njs_string_get(&args[2], &data);
+
+ p = data.start;
+ end = p + data.length;
+
+ while (p < end) {
+ n = write(fd, p, end - p);
+ if (nxt_slow_path(n == -1)) {
+ if (errno == EINTR) {
+ continue;
+ }
+
+ errn = errno;
+ description = strerror(errno);
+ syscall = "write";
+ goto done;
+ }
+
+ p += n;
+ }
+
+done:
+
+ if (fd > 0) {
+ close(fd);
+ }
+
+ if (description != 0) {
+ ret = njs_fs_error(vm, syscall, description, &args[1], errn,
+ &arguments[1]);
+
+ if (nxt_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ } else {
+ arguments[1] = njs_value_void;
+ }
+
+ arguments[0] = njs_value_void;
+
+ cont = njs_vm_continuation(vm);
+ cont->u.cont.function = njs_fs_done;
+
+ return njs_function_apply(vm, callback->data.u.function,
+ arguments, 2, (njs_index_t) &vm->retval);
+}
+
+
+static njs_ret_t
+njs_fs_write_file_sync_internal(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, int default_flags)
+{
+ int fd, errn, flags;
+ u_char *p, *end;
+ mode_t md;
+ ssize_t n;
+ nxt_str_t data, flag, encoding;
+ njs_ret_t ret;
+ const char *path, *syscall, *description;
+ njs_value_t *mode;
+ njs_object_prop_t *prop;
+ nxt_lvlhsh_query_t lhq;
+
+ if (nxt_slow_path(nargs < 3)) {
+ njs_exception_type_error(vm, "too few arguments", NULL);
+ return NJS_ERROR;
+ }
+
+ if (nxt_slow_path(!njs_is_string(&args[1]))) {
+ njs_exception_type_error(vm, "path must be a string", NULL);
+ return NJS_ERROR;
+ }
+
+ if (nxt_slow_path(!njs_is_string(&args[2]))) {
+ njs_exception_type_error(vm, "data must be a string", NULL);
+ return NJS_ERROR;
+ }
+
+ mode = NULL;
+ flag.start = NULL;
+ encoding.length = 0;
+ encoding.start = NULL;
+
+ if (nargs == 4) {
+ if (njs_is_string(&args[3])) {
+ njs_string_get(&args[3], &encoding);
+
+ } else if (njs_is_object(&args[3])) {
+ lhq.key_hash = NJS_FLAG_HASH;
+ lhq.key = nxt_string_value("flag");
+ lhq.proto = &njs_object_hash_proto;
+
+ ret = nxt_lvlhsh_find(&args[3].data.u.object->hash, &lhq);
+ if (ret == NXT_OK) {
+ prop = lhq.value;
+ njs_string_get(&prop->value, &flag);
+ }
+
+ lhq.key_hash = NJS_ENCODING_HASH;
+ lhq.key = nxt_string_value("encoding");
+ lhq.proto = &njs_object_hash_proto;
+
+ ret = nxt_lvlhsh_find(&args[3].data.u.object->hash, &lhq);
+ if (ret == NXT_OK) {
More information about the nginx-devel
mailing list