From 7fd2166d01883aca9e2a9df9f65f552ba4196ecc Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Mon, 28 Sep 2020 17:45:44 +0000 Subject: [PATCH] Adding support for Buffer objects in "fs" methods. fs.writeFile(), fs.appendFile() and friends may accept an instance of Buffer as an argument. Also, fs.readFile() and friends now return an instance of Buffer instead of Byte-string when encoding is not provided. Added Buffer encoding for fs.readdir(), fs.realpath() and friends. --- src/njs_fs.c | 489 ++++++++++++++++------------------- src/test/njs_unit_test.c | 109 ++++---- test/js/fs_appendFile.js | 61 +++++ test/js/fs_appendFileSync.js | 59 +++++ test/js/fs_promises_001.js | 5 - test/js/fs_promises_007.js | 16 +- test/js/fs_readFile.js | 40 +++ test/js/fs_readFileSync.js | 43 +++ test/js/fs_writeFile.js | 57 ++++ test/js/fs_writeFileSync.js | 54 ++++ test/njs_expect_test.exp | 284 +++++++------------- 11 files changed, 692 insertions(+), 525 deletions(-) create mode 100644 test/js/fs_appendFile.js create mode 100644 test/js/fs_appendFileSync.js create mode 100644 test/js/fs_readFile.js create mode 100644 test/js/fs_readFileSync.js create mode 100644 test/js/fs_writeFile.js create mode 100644 test/js/fs_writeFileSync.js diff --git a/src/njs_fs.c b/src/njs_fs.c index 158f0923..1a20743c 100644 --- a/src/njs_fs.c +++ b/src/njs_fs.c @@ -50,13 +50,6 @@ typedef enum { } njs_fs_writemode_t; -typedef enum { - NJS_FS_ENC_INVALID, - NJS_FS_ENC_NONE, - NJS_FS_ENC_UTF8, -} njs_fs_encoding_t; - - typedef struct { njs_str_t name; int value; @@ -92,19 +85,19 @@ static njs_int_t njs_fs_error(njs_vm_t *vm, const char *syscall, static njs_int_t njs_fs_result(njs_vm_t *vm, njs_value_t *result, njs_index_t calltype, const njs_value_t* callback, njs_uint_t nargs); -static njs_int_t -njs_file_tree_walk(const char *path, njs_file_tree_walk_cb_t cb, int fd_limit, - njs_ftw_flags_t flags); +static njs_int_t njs_file_tree_walk(const char *path, + njs_file_tree_walk_cb_t cb, int fd_limit, njs_ftw_flags_t flags); static njs_int_t njs_fs_make_path(njs_vm_t *vm, const char *path, mode_t md, njs_bool_t recursive, njs_value_t *retval); static njs_int_t njs_fs_rmtree(njs_vm_t *vm, const char *path, njs_bool_t recursive, njs_value_t *retval); +static njs_int_t njs_fs_path(njs_vm_t *vm, const char **dst, + const njs_value_t* src, const njs_str_t *prop_name); static int njs_fs_flags(njs_vm_t *vm, njs_value_t *value, int default_flags); static mode_t njs_fs_mode(njs_vm_t *vm, njs_value_t *value, mode_t default_mode); -static njs_fs_encoding_t njs_fs_encoding(njs_vm_t *vm, njs_value_t *value); static njs_int_t njs_fs_add_event(njs_vm_t *vm, const njs_value_t *callback, const njs_value_t *args, njs_uint_t nargs); @@ -135,44 +128,28 @@ static njs_fs_entry_t njs_flags_table[] = { }; -njs_inline njs_int_t -njs_fs_path_arg(njs_vm_t *vm, const char **dst, const njs_value_t* src, - const njs_str_t *prop_name) -{ - if (njs_slow_path(!njs_is_string(src))) { - njs_type_error(vm, "\"%V\" must be a string", prop_name); - return NJS_ERROR; - } - - *dst = njs_string_to_c_string(vm, njs_value_arg(src)); - if (njs_slow_path(*dst == NULL)) { - return NJS_ERROR; - } - - return NJS_OK; -} +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_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; - u_char *start; - size_t size; - ssize_t length; - njs_str_t data; - njs_int_t ret; - const char *file_path; - njs_value_t flag, encoding, retval, *callback, *options, *path; - struct stat sb; - njs_fs_encoding_t enc; - - static const njs_value_t string_flag = njs_string("flag"); - static const njs_value_t string_encoding = njs_string("encoding"); + int fd, flags; + njs_str_t data; + njs_int_t ret; + const char *file_path; + njs_value_t flag, encode, retval, *callback, *options, + *path; + struct stat sb; + const njs_buffer_encoding_t *encoding; path = njs_arg(args, nargs, 1); - ret = njs_fs_path_arg(vm, &file_path, path, &njs_str_value("path")); + ret = njs_fs_path(vm, &file_path, path, &njs_str_value("path")); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -194,11 +171,11 @@ njs_fs_read_file(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } njs_set_undefined(&flag); - njs_set_undefined(&encoding); + njs_set_undefined(&encode); switch (options->type) { case NJS_STRING: - encoding = *options; + encode = *options; break; case NJS_UNDEFINED: @@ -219,7 +196,7 @@ njs_fs_read_file(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } ret = njs_value_property(vm, options, njs_value_arg(&string_encoding), - &encoding); + &encode); if (njs_slow_path(ret == NJS_ERROR)) { return ret; } @@ -230,9 +207,12 @@ njs_fs_read_file(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_ERROR; } - enc = njs_fs_encoding(vm, &encoding); - if (njs_slow_path(enc == NJS_FS_ENC_INVALID)) { - 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(file_path, flags); @@ -252,88 +232,25 @@ njs_fs_read_file(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, goto done; } - if (enc == NJS_FS_ENC_UTF8) { - length = sb.st_size; + data.start = NULL; + data.length = sb.st_size; - if (length > NJS_STRING_MAP_STRIDE) { - /* - * At this point length is not known, in order to set it to - * the correct value after file is read, we need to ensure that - * offset_map is allocated by njs_string_alloc(). This can be - * achieved by making length != size. - */ - length += 1; + 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); } - } else { - length = 0; + goto done; } - size = sb.st_size; - - if (njs_fast_path(size != 0)) { - start = njs_string_alloc(vm, &retval, size, length); - if (njs_slow_path(start == NULL)) { - ret = NJS_ERROR; - goto done; - } - - data.start = start; - data.length = size; - - 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); - } - - goto done; - } - - if (njs_slow_path(data.length < size)) { - /* Pseudo-files may return less data than declared by st_size. */ - njs_string_truncate(&retval, data.length, length); - } - - size = data.length; - start = data.start; + if (encoding == NULL) { + ret = njs_buffer_set(vm, &retval, data.start, data.length); } else { - /* size of the file is not known in advance. */ - - data.length = 0; - - 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); - } - - goto done; - } - - size = data.length; - start = data.start; - - ret = njs_string_new(vm, &retval, start, size, length); - if (njs_slow_path(ret != NJS_OK)) { - goto done; - } - } - - if (enc == NJS_FS_ENC_UTF8) { - length = njs_utf8_length(start, size); - - if (length >= 0) { - njs_string_length_set(&retval, length); - - } else { - ret = njs_fs_error(vm, NULL, "Non-UTF8 file, convertion " - "is not implemented", path, 0, &retval); - goto done; - } + ret = encoding->encode(vm, &retval, &data); + njs_mp_free(vm->mem_pool, data.start); } done: @@ -354,34 +271,26 @@ 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 *file_path; - njs_value_t flag, mode, encoding, retval, - *path, *data, *callback, *options; - njs_fs_encoding_t enc; - njs_fs_calltype_t calltype; - - 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_encoding = njs_string("encoding"); + int fd, flags; + u_char *p, *end; + mode_t md; + ssize_t n; + njs_str_t content; + njs_int_t ret; + const char *file_path; + njs_value_t flag, mode, encode, retval, *path, *data, + *callback, *options; + njs_typed_array_t *array; + njs_fs_calltype_t calltype; + njs_array_buffer_t *buffer; + const njs_buffer_encoding_t *encoding; path = njs_arg(args, nargs, 1); - ret = njs_fs_path_arg(vm, &file_path, path, &njs_str_value("path")); + ret = njs_fs_path(vm, &file_path, path, &njs_str_value("path")); if (njs_slow_path(ret != NJS_OK)) { return ret; } - data = njs_arg(args, nargs, 2); - if (njs_slow_path(!njs_is_string(data))) { - njs_type_error(vm, "\"data\" must be a string"); - return NJS_ERROR; - } - callback = NULL; calltype = magic & 3; options = njs_arg(args, nargs, 3); @@ -400,11 +309,11 @@ njs_fs_write_file(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_set_undefined(&flag); njs_set_undefined(&mode); - njs_set_undefined(&encoding); + njs_set_undefined(&encode); switch (options->type) { case NJS_STRING: - encoding = *options; + encode = *options; break; case NJS_UNDEFINED: @@ -431,12 +340,49 @@ njs_fs_write_file(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } ret = njs_value_property(vm, options, njs_value_arg(&string_encoding), - &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; + } + + content.start = &buffer->u.u8[array->offset]; + content.length = array->byte_length; + break; + + 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; + } + flags = njs_fs_flags(vm, &flag, O_CREAT | O_WRONLY); if (njs_slow_path(flags == -1)) { return NJS_ERROR; @@ -449,19 +395,12 @@ njs_fs_write_file(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_ERROR; } - enc = njs_fs_encoding(vm, &encoding); - if (njs_slow_path(enc == NJS_FS_ENC_INVALID)) { - return NJS_ERROR; - } - fd = open(file_path, flags, md); if (njs_slow_path(fd < 0)) { ret = njs_fs_error(vm, "open", strerror(errno), path, errno, &retval); goto done; } - njs_string_get(data, &content); - p = content.start; end = p + content.length; @@ -515,13 +454,13 @@ njs_fs_rename(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } } - ret = njs_fs_path_arg(vm, &old_path, njs_arg(args, nargs, 1), + ret = njs_fs_path(vm, &old_path, njs_arg(args, nargs, 1), &njs_str_value("oldPath")); if (njs_slow_path(ret != NJS_OK)) { return ret; } - ret = njs_fs_path_arg(vm, &new_path, njs_arg(args, nargs, 2), + ret = njs_fs_path(vm, &new_path, njs_arg(args, nargs, 2), &njs_str_value("newPath")); if (njs_slow_path(ret != NJS_OK)) { return ret; @@ -552,7 +491,7 @@ njs_fs_access(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_value_t retval, *path, *callback, *mode; path = njs_arg(args, nargs, 1); - ret = njs_fs_path_arg(vm, &file_path, path, &njs_str_value("path")); + ret = njs_fs_path(vm, &file_path, path, &njs_str_value("path")); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -610,13 +549,13 @@ njs_fs_symlink(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_value_t retval, *target, *path, *callback, *type; target = njs_arg(args, nargs, 1); - ret = njs_fs_path_arg(vm, &target_path, target, &njs_str_value("target")); + ret = njs_fs_path(vm, &target_path, target, &njs_str_value("target")); if (njs_slow_path(ret != NJS_OK)) { return ret; } path = njs_arg(args, nargs, 2); - ret = njs_fs_path_arg(vm, &file_path, path, &njs_str_value("path")); + ret = njs_fs_path(vm, &file_path, path, &njs_str_value("path")); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -666,7 +605,7 @@ njs_fs_unlink(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_value_t retval, *path, *callback; path = njs_arg(args, nargs, 1); - ret = njs_fs_path_arg(vm, &file_path, path, &njs_str_value("path")); + ret = njs_fs_path(vm, &file_path, path, &njs_str_value("path")); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -700,19 +639,15 @@ static njs_int_t njs_fs_realpath(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t calltype) { - u_char *resolved_path; - size_t size; - ssize_t length; - njs_int_t ret; - const char *file_path; - njs_value_t encoding, retval, *path, *callback, *options; - njs_fs_encoding_t enc; - char path_buf[MAXPATHLEN]; - - static const njs_value_t string_encoding = njs_string("encoding"); + njs_int_t ret; + njs_str_t s; + const char *file_path; + njs_value_t encode, retval, *path, *callback, *options; + const njs_buffer_encoding_t *encoding; + char path_buf[MAXPATHLEN]; path = njs_arg(args, nargs, 1); - ret = njs_fs_path_arg(vm, &file_path, path, &njs_str_value("path")); + ret = njs_fs_path(vm, &file_path, path, &njs_str_value("path")); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -732,11 +667,11 @@ njs_fs_realpath(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } } - njs_set_undefined(&encoding); + njs_set_undefined(&encode); switch (options->type) { case NJS_STRING: - encoding = *options; + encode = *options; break; case NJS_UNDEFINED: @@ -751,33 +686,34 @@ njs_fs_realpath(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } ret = njs_value_property(vm, options, njs_value_arg(&string_encoding), - &encoding); + &encode); if (njs_slow_path(ret == NJS_ERROR)) { return ret; } } - enc = njs_fs_encoding(vm, &encoding); - if (njs_slow_path(enc == NJS_FS_ENC_INVALID)) { - return NJS_ERROR; + 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; + } } - resolved_path = (u_char *) realpath(file_path, path_buf); - if (njs_slow_path(resolved_path == NULL)) { + s.start = (u_char *) realpath(file_path, path_buf); + if (njs_slow_path(s.start == NULL)) { ret = njs_fs_error(vm, "realpath", strerror(errno), path, errno, &retval); goto done; } - size = njs_strlen(resolved_path); - length = njs_utf8_length(resolved_path, size); - if (njs_slow_path(length < 0)) { - length = 0; - } + s.length = njs_strlen(s.start); - ret = njs_string_new(vm, &retval, resolved_path, size, length); - if (njs_slow_path(ret != NJS_OK)) { - return NJS_ERROR; + if (encoding == NULL) { + ret = njs_buffer_new(vm, &retval, s.start, s.length); + + } else { + ret = encoding->encode(vm, &retval, &s); } done: @@ -799,11 +735,8 @@ njs_fs_mkdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, const char *file_path; njs_value_t mode, recursive, retval, *path, *callback, *options; - static const njs_value_t string_mode = njs_string("mode"); - static const njs_value_t string_recursive = njs_string("recursive"); - path = njs_arg(args, nargs, 1); - ret = njs_fs_path_arg(vm, &file_path, path, &njs_str_value("path")); + ret = njs_fs_path(vm, &file_path, path, &njs_str_value("path")); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -878,10 +811,8 @@ njs_fs_rmdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, const char *file_path; njs_value_t recursive, retval, *path, *callback, *options; - static const njs_value_t string_recursive = njs_string("recursive"); - path = njs_arg(args, nargs, 1); - ret = njs_fs_path_arg(vm, &file_path, path, &njs_str_value("path")); + ret = njs_fs_path(vm, &file_path, path, &njs_str_value("path")); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -935,23 +866,20 @@ static njs_int_t njs_fs_readdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t calltype) { - DIR *dir; - u_char *d_name; - size_t size; - ssize_t length; - njs_int_t ret; - const char *dir_path; - njs_value_t encoding, types, ename, etype, retval, *path, *callback, - *options, *value; - njs_array_t *results; - struct dirent *entry; - njs_fs_encoding_t enc; - - static const njs_value_t string_encoding = njs_string("encoding"); + DIR *dir; + njs_str_t s; + njs_int_t ret; + const char *dir_path; + njs_value_t encode, types, ename, etype, retval, *path, + *callback, *options, *value; + njs_array_t *results; + struct dirent *entry; + const njs_buffer_encoding_t *encoding; + static const njs_value_t string_types = njs_string("withFileTypes"); path = njs_arg(args, nargs, 1); - ret = njs_fs_path_arg(vm, &dir_path, path, &njs_str_value("path")); + ret = njs_fs_path(vm, &dir_path, path, &njs_str_value("path")); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -971,11 +899,11 @@ njs_fs_readdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } njs_set_false(&types); - njs_set_undefined(&encoding); + njs_set_undefined(&encode); switch (options->type) { case NJS_STRING: - encoding = *options; + encode = *options; break; case NJS_UNDEFINED: @@ -990,7 +918,7 @@ njs_fs_readdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } ret = njs_value_property(vm, options, njs_value_arg(&string_encoding), - &encoding); + &encode); if (njs_slow_path(ret == NJS_ERROR)) { return ret; } @@ -1002,9 +930,12 @@ njs_fs_readdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } } - enc = njs_fs_encoding(vm, &encoding); - if (njs_slow_path(enc == NJS_FS_ENC_INVALID)) { - return NJS_ERROR; + 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; + } } results = njs_array_alloc(vm, 1, 0, NJS_ARRAY_SPARE); @@ -1033,41 +964,38 @@ njs_fs_readdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, goto done; } - d_name = (u_char *) entry->d_name; - - size = njs_strlen(d_name); - length = njs_utf8_length(d_name, size); - if (njs_slow_path(length < 0)) { - length = 0; - } + s.start = (u_char *) entry->d_name; + s.length = njs_strlen(s.start); - if ((length == 1 && d_name[0] == '.') - || (length == 2 && (d_name[0] == '.' && d_name[1] == '.'))) + if ((s.length == 1 && s.start[0] == '.') + || (s.length == 2 && (s.start[0] == '.' && s.start[1] == '.'))) { continue; } - if (njs_fast_path(!njs_is_true(&types))) { - ret = njs_array_string_add(vm, results, d_name, size, length); - if (njs_slow_path(ret != NJS_OK)) { - goto done; - } + value = njs_array_push(vm, results); + if (njs_slow_path(value == NULL)) { + goto done; + } - continue; + if (encoding == NULL) { + ret = njs_buffer_set(vm, &ename, s.start, s.length); + + } else { + ret = encoding->encode(vm, &ename, &s); } - ret = njs_string_new(vm, &ename, d_name, size, length); if (njs_slow_path(ret != NJS_OK)) { goto done; } - njs_set_number(&etype, njs_dentry_type(entry)); - - value = njs_array_push(vm, results); - if (njs_slow_path(value == NULL)) { - goto done; + if (njs_fast_path(!njs_is_true(&types))) { + *value = ename; + continue; } + njs_set_number(&etype, njs_dentry_type(entry)); + ret = njs_fs_dirent_create(vm, &ename, &etype, value); if (njs_slow_path(ret != NJS_OK)) { goto done; @@ -1099,12 +1027,12 @@ njs_fs_fd_read(njs_vm_t *vm, int fd, njs_str_t *data) if (size == 0) { size = 4096; + } - data->start = njs_mp_alloc(vm->mem_pool, size); - if (data->start == NULL) { - njs_memory_error(vm); - return NJS_ERROR; - } + data->start = njs_mp_alloc(vm->mem_pool, size); + if (data->start == NULL) { + njs_memory_error(vm); + return NJS_ERROR; } p = data->start; @@ -1474,6 +1402,61 @@ njs_fs_rmtree(njs_vm_t *vm, const char *path, njs_bool_t recursive, } +static njs_int_t +njs_fs_path(njs_vm_t *vm, const char **dst, const njs_value_t* src, + const njs_str_t *prop_name) +{ + u_char *data, *p, *start; + njs_typed_array_t *array; + njs_array_buffer_t *buffer; + + switch (src->type) { + case NJS_STRING: + *dst = njs_string_to_c_string(vm, njs_value_arg(src)); + if (njs_slow_path(*dst == NULL)) { + return NJS_ERROR; + } + + break; + + case NJS_TYPED_ARRAY: + case NJS_DATA_VIEW: + array = njs_typed_array(src); + buffer = array->buffer; + if (njs_slow_path(njs_is_detached_buffer(buffer))) { + njs_type_error(vm, "detached buffer"); + return NJS_ERROR; + } + + start = &buffer->u.u8[array->offset]; + + if (njs_slow_path(memchr(start, '\0', array->byte_length) != 0)) { + njs_type_error(vm, "\"%V\" must be a Buffer without null bytes", + prop_name); + return NJS_ERROR; + } + + data = njs_mp_alloc(vm->mem_pool, array->byte_length + 1); + if (njs_slow_path(data == NULL)) { + njs_memory_error(vm); + return NJS_ERROR; + } + + p = njs_cpymem(data, start, array->byte_length); + *p++ = '\0'; + + *dst = (char *) data; + break; + + default: + njs_type_error(vm, "\"%V\" must be a string or Buffer", prop_name); + return NJS_ERROR; + } + + return NJS_OK; +} + + static int njs_fs_flags(njs_vm_t *vm, njs_value_t *value, int default_flags) { @@ -1526,32 +1509,6 @@ njs_fs_mode(njs_vm_t *vm, njs_value_t *value, mode_t default_mode) } -static njs_fs_encoding_t -njs_fs_encoding(njs_vm_t *vm, njs_value_t *value) -{ - njs_str_t enc; - njs_int_t ret; - - if (njs_is_undefined(value)) { - return NJS_FS_ENC_NONE; - } - - ret = njs_value_to_string(vm, value, value); - if (njs_slow_path(ret != NJS_OK)) { - return NJS_FS_ENC_INVALID; - } - - njs_string_get(value, &enc); - - if (enc.length != 4 || memcmp(enc.start, "utf8", 4) != 0) { - njs_type_error(vm, "Unknown encoding: \"%V\"", &enc); - return NJS_FS_ENC_INVALID; - } - - return NJS_FS_ENC_UTF8; -} - - static njs_int_t njs_fs_error(njs_vm_t *vm, const char *syscall, const char *description, njs_value_t *path, int errn, njs_value_t *retval) diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index c6838146..661bf6a6 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -17013,145 +17013,146 @@ static njs_unit_test_t njs_test[] = /* require('fs').readFile() */ { njs_str("var fs = require('fs');" - "fs.readFile()"), - njs_str("TypeError: \"path\" must be a string") }, + "fs.readFile()"), + njs_str("TypeError: \"path\" must be a string or Buffer") }, { njs_str("var fs = require('fs');" - "fs.readFile('/njs_unknown_path')"), + "var path = Buffer.from('/broken'); path[3] = 0;" + "fs.readFile(path)"), + njs_str("TypeError: \"path\" must be a Buffer without null bytes") }, + + { njs_str("var fs = require('fs');" + "fs.readFile('/njs_unknown_path')"), njs_str("TypeError: \"callback\" must be a function") }, { njs_str("var fs = require('fs');" - "fs.readFile('/njs_unknown_path', 'utf8')"), + "fs.readFile('/njs_unknown_path', 'utf8')"), njs_str("TypeError: \"callback\" must be a function") }, { njs_str("var fs = require('fs');" - "fs.readFile('/njs_unknown_path', {flag:'xx'})"), + "fs.readFile('/njs_unknown_path', {flag:'xx'})"), njs_str("TypeError: \"callback\" must be a function") }, { njs_str("var fs = require('fs');" - "fs.readFile('/njs_unknown_path', {flag:'xx'}, 1)"), + "fs.readFile('/njs_unknown_path', {flag:'xx'}, 1)"), njs_str("TypeError: \"callback\" must be a function") }, { njs_str("var fs = require('fs');" - "fs.readFile('/njs_unknown_path', {flag:'xx'}, function () {})"), + "fs.readFile('/njs_unknown_path', {flag:'xx'}, function () {})"), njs_str("TypeError: Unknown file open flags: \"xx\"") }, { njs_str("var fs = require('fs');" - "fs.readFile('/njs_unknown_path', {encoding:'ascii'}, function () {})"), - njs_str("TypeError: Unknown encoding: \"ascii\"") }, + "fs.readFile('/njs_unknown_path', {encoding:'ascii'}, function () {})"), + njs_str("TypeError: \"ascii\" encoding is not supported") }, { njs_str("var fs = require('fs');" - "fs.readFile('/njs_unknown_path', 'ascii', function () {})"), - njs_str("TypeError: Unknown encoding: \"ascii\"") }, + "fs.readFile('/njs_unknown_path', 'ascii', function () {})"), + njs_str("TypeError: \"ascii\" encoding is not supported") }, /* require('fs').readFileSync() */ { njs_str("var fs = require('fs');" - "fs.readFileSync()"), - njs_str("TypeError: \"path\" must be a string") }, + "fs.readFileSync()"), + njs_str("TypeError: \"path\" must be a string or Buffer") }, { njs_str("var fs = require('fs');" - "fs.readFileSync({})"), - njs_str("TypeError: \"path\" must be a string") }, + "fs.readFileSync({})"), + njs_str("TypeError: \"path\" must be a string or Buffer") }, { njs_str("var fs = require('fs');" - "fs.readFileSync('/njs_unknown_path', {flag:'xx'})"), + "fs.readFileSync('/njs_unknown_path', {flag:'xx'})"), njs_str("TypeError: Unknown file open flags: \"xx\"") }, { njs_str("var fs = require('fs');" - "fs.readFileSync('/njs_unknown_path', {encoding:'ascii'})"), - njs_str("TypeError: Unknown encoding: \"ascii\"") }, + "fs.readFileSync(Buffer.from('/njs_unknown_path'), {encoding:'ascii'})"), + njs_str("TypeError: \"ascii\" encoding is not supported") }, { njs_str("var fs = require('fs');" - "fs.readFileSync('/njs_unknown_path', 'ascii')"), - njs_str("TypeError: Unknown encoding: \"ascii\"") }, + "fs.readFileSync('/njs_unknown_path', 'ascii')"), + njs_str("TypeError: \"ascii\" encoding is not supported") }, { njs_str("var fs = require('fs');" - "fs.readFileSync('/njs_unknown_path', true)"), + "fs.readFileSync('/njs_unknown_path', true)"), njs_str("TypeError: Unknown options type: \"boolean\" (a string or object required)") }, /* require('fs').writeFile() */ { njs_str("var fs = require('fs');" - "fs.writeFile()"), - njs_str("TypeError: \"path\" must be a string") }, + "fs.writeFile()"), + njs_str("TypeError: \"path\" must be a string or Buffer") }, { njs_str("var fs = require('fs');" - "fs.writeFile({}, '', function () {})"), - njs_str("TypeError: \"path\" must be a string") }, + "fs.writeFile({}, '', function () {})"), + njs_str("TypeError: \"path\" must be a string or Buffer") }, { njs_str("var fs = require('fs');" - "fs.writeFile('/njs_unknown_path')"), - njs_str("TypeError: \"data\" must be a string") }, + "fs.writeFile('/njs_unknown_path')"), + njs_str("TypeError: \"callback\" must be a function") }, { njs_str("var fs = require('fs');" - "fs.writeFile('/njs_unknown_path', '')"), + "fs.writeFile('/njs_unknown_path', '')"), njs_str("TypeError: \"callback\" must be a function") }, { njs_str("var fs = require('fs');" - "fs.writeFile('/njs_unknown_path', '', undefined)"), + "fs.writeFile('/njs_unknown_path', '', undefined)"), njs_str("TypeError: \"callback\" must be a function") }, { njs_str("var fs = require('fs');" - "fs.writeFile('/njs_unknown_path', '', 'utf8')"), + "fs.writeFile('/njs_unknown_path', '', 'utf8')"), njs_str("TypeError: \"callback\" must be a function") }, { njs_str("var fs = require('fs');" - "fs.writeFile('/njs_unknown_path', '', {flag:'xx'}, function () {})"), + "fs.writeFile('/njs_unknown_path', '', {flag:'xx'}, function () {})"), njs_str("TypeError: Unknown file open flags: \"xx\"") }, { njs_str("var fs = require('fs');" - "fs.writeFile('/njs_unknown_path', '', {encoding:'ascii'}, function () {})"), - njs_str("TypeError: Unknown encoding: \"ascii\"") }, + "fs.writeFile('/njs_unknown_path', '', {encoding:'ascii'}, function () {})"), + njs_str("TypeError: \"ascii\" encoding is not supported") }, { njs_str("var fs = require('fs');" - "fs.writeFile('/njs_unknown_path', '', 'ascii', function () {})"), - njs_str("TypeError: Unknown encoding: \"ascii\"") }, + "fs.writeFile('/njs_unknown_path', '', 'ascii', function () {})"), + njs_str("TypeError: \"ascii\" encoding is not supported") }, { njs_str("var fs = require('fs');" - "fs.writeFile('/njs_unknown_path', '', true, function () {})"), + "fs.writeFile('/njs_unknown_path', '', true, function () {})"), njs_str("TypeError: Unknown options type: \"boolean\" (a string or object required)") }, /* require('fs').writeFileSync() */ { njs_str("var fs = require('fs');" - "fs.writeFileSync()"), - njs_str("TypeError: \"path\" must be a string") }, - - { njs_str("var fs = require('fs');" - "fs.writeFileSync('/njs_unknown_path')"), - njs_str("TypeError: \"data\" must be a string") }, + "fs.writeFileSync()"), + njs_str("TypeError: \"path\" must be a string or Buffer") }, { njs_str("var fs = require('fs');" - "fs.writeFileSync({}, '')"), - njs_str("TypeError: \"path\" must be a string") }, + "fs.writeFileSync({}, '')"), + njs_str("TypeError: \"path\" must be a string or Buffer") }, { njs_str("var fs = require('fs');" - "fs.writeFileSync('/njs_unknown_path', '', {flag:'xx'})"), + "fs.writeFileSync('/njs_unknown_path', '', {flag:'xx'})"), njs_str("TypeError: Unknown file open flags: \"xx\"") }, { njs_str("var fs = require('fs');" - "fs.writeFileSync('/njs_unknown_path', '', {encoding:'ascii'})"), - njs_str("TypeError: Unknown encoding: \"ascii\"") }, + "fs.writeFileSync('/njs_unknown_path', '', {encoding:'ascii'})"), + njs_str("TypeError: \"ascii\" encoding is not supported") }, { njs_str("var fs = require('fs');" - "fs.writeFileSync('/njs_unknown_path', '', 'ascii')"), - njs_str("TypeError: Unknown encoding: \"ascii\"") }, + "fs.writeFileSync('/njs_unknown_path', '', 'ascii')"), + njs_str("TypeError: \"ascii\" encoding is not supported") }, { njs_str("var fs = require('fs');" - "fs.writeFileSync('/njs_unknown_path', '', true)"), + "fs.writeFileSync('/njs_unknown_path', '', true)"), njs_str("TypeError: Unknown options type: \"boolean\" (a string or object required)") }, /* require('fs').renameSync() */ { njs_str("var fs = require('fs');" "fs.renameSync()"), - njs_str("TypeError: \"oldPath\" must be a string") }, + njs_str("TypeError: \"oldPath\" must be a string or Buffer") }, { njs_str("var fs = require('fs');" "fs.renameSync('/njs_unknown_path')"), - njs_str("TypeError: \"newPath\" must be a string") }, + njs_str("TypeError: \"newPath\" must be a string or Buffer") }, { njs_str("var fs = require('fs');" "[undefined, null, false, NaN, Symbol(), {}, Object('/njs_unknown_path')]" @@ -17171,7 +17172,7 @@ static njs_unit_test_t njs_test[] = { njs_str("var fs = require('fs');" "fs.access()"), - njs_str("TypeError: \"path\" must be a string") }, + njs_str("TypeError: \"path\" must be a string or Buffer") }, { njs_str("var fs = require('fs');" "fs.access('/njs_unknown_path')"), @@ -17189,7 +17190,7 @@ static njs_unit_test_t njs_test[] = { njs_str("var fs = require('fs');" "fs.accessSync()"), - njs_str("TypeError: \"path\" must be a string") }, + njs_str("TypeError: \"path\" must be a string or Buffer") }, { njs_str("var fs = require('fs');" "fs.accessSync('/njs_unknown_path', 'fail')"), diff --git a/test/js/fs_appendFile.js b/test/js/fs_appendFile.js new file mode 100644 index 00000000..7a6fa397 --- /dev/null +++ b/test/js/fs_appendFile.js @@ -0,0 +1,61 @@ +var fs = require('fs'); +var fname = './build/test/fs_appendFile'; + +var argv = process.argv.slice(2); + +var data = (() => { + var value = argv[0]; + var type = argv[1]; + var offset = argv[2] ? parseInt(argv[2]) : 0; + + switch (type) { + case 'Buffer': + return Buffer.from(Buffer.from(value).buffer, offset); + case 'DataView': + return new DataView(Buffer.from(value).buffer, offset); + case 'Object': + return {toString(){return value}}; + case 'String': + return String(value); + case 'Symbol': + return Symbol(value); + case 'Uint8Array': + return new Uint8Array(Buffer.from(value).buffer, offset); + default: + throw new Error(`Unknown data type:${type}`); + } +})(); + +var options = (() => { + var encoding = argv[2]; + var mode = argv[3] ? parseInt(argv[3].slice(2), 8) : 0; + + if (encoding && mode) { + return {encoding, mode}; + + } else if (encoding) { + return encoding; + } + + return undefined; +})(); + +try { fs.unlinkSync(fname); } catch (e) {} + +function done(e) { + if (e) {throw e}; + var data = fs.readFileSync(fname); + console.log(String(data)); +} + +function append(cb) { + if (options) { + var path = Buffer.from(`@${fname}`).slice(1); + fs.appendFile(path, data, options, cb); + + } else { + fs.appendFile(fname, data, cb); + } +} + +append((e) => {if (e) {throw e}; append(done);}) diff --git a/test/js/fs_appendFileSync.js b/test/js/fs_appendFileSync.js new file mode 100644 index 00000000..b6372b8b --- /dev/null +++ b/test/js/fs_appendFileSync.js @@ -0,0 +1,59 @@ +var fs = require('fs'); +var fname = './build/test/fs_appendFileSync'; + +var argv = process.argv.slice(2); + +var data = (() => { + var value = argv[0]; + var type = argv[1]; + var offset = argv[2] ? parseInt(argv[2]) : 0; + + switch (type) { + case 'Buffer': + return Buffer.from(Buffer.from(value).buffer, offset); + case 'DataView': + return new DataView(Buffer.from(value).buffer, offset); + case 'Object': + return {toString(){return value}}; + case 'String': + return String(value); + case 'Symbol': + return Symbol(value); + case 'Uint8Array': + return new Uint8Array(Buffer.from(value).buffer, offset); + default: + throw new Error(`Unknown data type:${type}`); + } +})(); + +var options = (() => { + var encoding = argv[2]; + var mode = argv[3] ? parseInt(argv[3].slice(2), 8) : 0; + + if (encoding && mode) { + return {encoding, mode}; + + } else if (encoding) { + return encoding; + } + + return undefined; +})(); + +function append() { + if (options) { + var path = Buffer.from(`@${fname}`).slice(1); + fs.appendFileSync(path, data, options); + + } else { + fs.appendFileSync(fname, data); + } +} + +try { fs.unlinkSync(fname); } catch (e) {} + +append(); +append(); + +var ret = fs.readFileSync(fname); +console.log(String(ret)); diff --git a/test/js/fs_promises_001.js b/test/js/fs_promises_001.js index 477b2549..22a1efc5 100644 --- a/test/js/fs_promises_001.js +++ b/test/js/fs_promises_001.js @@ -45,11 +45,6 @@ Promise.resolve() } catch (e) { console.log('error 2 ok', e instanceof TypeError) } - try { - return fs.writeFile(fname); - } catch (e) { - console.log('error 3 ok', e instanceof TypeError) - } }) .then((data) => { console.log('errors ok'); diff --git a/test/js/fs_promises_007.js b/test/js/fs_promises_007.js index 3dccf275..e02796cb 100644 --- a/test/js/fs_promises_007.js +++ b/test/js/fs_promises_007.js @@ -96,6 +96,16 @@ var testSync = () => new Promise((resolve, reject) => { throw new Error('fs.readdirSync - error 6'); } + var dir_buffer = fs.readdirSync(dname, {encoding:'buffer'}); + if (dir_buffer.length != 3 || !(dir_buffer[0] instanceof Buffer)) { + throw new Error('fs.readdirSync - error 7'); + } + + var dir_buffer_types = fs.readdirSync(dname, {encoding:'buffer', withFileTypes: true}); + if (dir_buffer_types.length != 3 || !(dir_buffer_types[0].name instanceof Buffer)) { + throw new Error('fs.readdirSync - error 8'); + } + resolve(); } catch (e) { @@ -171,7 +181,7 @@ Promise.resolve() console.log('test fs.readdirSync'); }) .catch((e) => { - console.log('test fs.readdirSync failed', JSON.stringify(e)); + console.log('test fs.readdirSync failed', e, JSON.stringify(e)); }) .then(testCallback) @@ -179,7 +189,7 @@ Promise.resolve() console.log('test fs.readdir'); }) .catch((e) => { - console.log('test fs.readdir failed', JSON.stringify(e)); + console.log('test fs.readdir failed', e, JSON.stringify(e)); }) .then(() => { @@ -227,5 +237,5 @@ Promise.resolve() console.log('test fsp.readdir'); }) .catch((e) => { - console.log('test fsp.readdir failed', JSON.stringify(e)); + console.log('test fsp.readdir failed', e, JSON.stringify(e)); }); diff --git a/test/js/fs_readFile.js b/test/js/fs_readFile.js new file mode 100644 index 00000000..c7a97eaa --- /dev/null +++ b/test/js/fs_readFile.js @@ -0,0 +1,40 @@ +var fs = require('fs'); + +var argv = process.argv.slice(2); +var fname = argv[0]; + +var options = (() => { + var encoding = argv[1]; + var flags = argv[2]; + + if (encoding && flags) { + return {encoding, flags}; + + } else if (encoding) { + return encoding; + } + + return undefined; +})(); + +function type(v) { + if (v instanceof Buffer) { + return 'Buffer'; + } + + return typeof v; +} + +function done(e, data) { + if (e) {console.log(JSON.stringify(e))}; + console.log(String(data), type(data), data.length); +} + +if (options) { + var path = Buffer.from(`@${fname}`).slice(1); + fs.readFile(path, options, done); + +} else { + fs.readFile(fname, done); +} + diff --git a/test/js/fs_readFileSync.js b/test/js/fs_readFileSync.js new file mode 100644 index 00000000..2e4d811b --- /dev/null +++ b/test/js/fs_readFileSync.js @@ -0,0 +1,43 @@ +var fs = require('fs'); + +var argv = process.argv.slice(2); +var fname = argv[0]; + +var options = (() => { + var encoding = argv[1]; + var flags = argv[2]; + + if (encoding && flags) { + return {encoding, flags}; + + } else if (encoding) { + return encoding; + } + + return undefined; +})(); + +function type(v) { + if (v instanceof Buffer) { + return 'Buffer'; + } + + return typeof v; +} + +var data; + +try { + if (options) { + var path = Buffer.from(`@${fname}`).slice(1); + data = fs.readFileSync(path, options); + + } else { + data = fs.readFileSync(fname); + } + +} catch (e) { + console.log(JSON.stringify(e)); +} + +console.log(String(data), type(data), data.length); diff --git a/test/js/fs_writeFile.js b/test/js/fs_writeFile.js new file mode 100644 index 00000000..daa752bf --- /dev/null +++ b/test/js/fs_writeFile.js @@ -0,0 +1,57 @@ +var fs = require('fs'); +var fname = './build/test/fs_writeFile'; + +var argv = process.argv.slice(2); + +var data = (() => { + var value = argv[0]; + var type = argv[1]; + var offset = argv[2] ? parseInt(argv[2]) : 0; + + switch (type) { + case 'Buffer': + return Buffer.from(Buffer.from(value).buffer, offset); + case 'DataView': + return new DataView(Buffer.from(value).buffer, offset); + case 'Object': + return {toString(){return value}}; + case 'String': + return String(value); + case 'Symbol': + return Symbol(value); + case 'Uint8Array': + return new Uint8Array(Buffer.from(value).buffer, offset); + default: + throw new Error(`Unknown data type:${type}`); + } +})(); + +var options = (() => { + var encoding = argv[2]; + var mode = argv[3] ? parseInt(argv[3].slice(2), 8) : 0; + + if (encoding && mode) { + return {encoding, mode}; + + } else if (encoding) { + return encoding; + } + + return undefined; +})(); + +try { fs.unlinkSync(fname); } catch (e) {} + +function cb(e) { + if (e) {throw e}; + var data = fs.readFileSync(fname); + console.log(String(data)); +} + +if (options) { + var path = Buffer.from(`@${fname}`).slice(1); + fs.writeFile(path, data, options, cb); + +} else { + fs.writeFile(fname, data, cb); +} diff --git a/test/js/fs_writeFileSync.js b/test/js/fs_writeFileSync.js new file mode 100644 index 00000000..29621f2e --- /dev/null +++ b/test/js/fs_writeFileSync.js @@ -0,0 +1,54 @@ +var fs = require('fs'); +var fname = './build/test/fs_writeFileSync'; + +var argv = process.argv.slice(2); + +var data = (() => { + var value = argv[0]; + var type = argv[1]; + var offset = argv[2] ? parseInt(argv[2]) : 0; + + switch (type) { + case 'Buffer': + return Buffer.from(Buffer.from(value).buffer, offset); + case 'DataView': + return new DataView(Buffer.from(value).buffer, offset); + case 'Object': + return {toString(){return value}}; + case 'String': + return String(value); + case 'Symbol': + return Symbol(value); + case 'Uint8Array': + return new Uint8Array(Buffer.from(value).buffer, offset); + default: + throw new Error(`Unknown data type:${type}`); + } +})(); + +var options = (() => { + var encoding = argv[2]; + var mode = argv[3] ? parseInt(argv[3].slice(2), 8) : 0; + + if (encoding && mode) { + return {encoding, mode}; + + } else if (encoding) { + return encoding; + } + + return undefined; +})(); + +try { fs.unlinkSync(fname); } catch (e) {} + +if (options) { + var path = Buffer.from(`@${fname}`).slice(1); + fs.writeFileSync(path, data, options); + +} else { + fs.writeFileSync(fname, data); +} + +var ret = fs.readFileSync(fname); +console.log(String(ret)); diff --git a/test/njs_expect_test.exp b/test/njs_expect_test.exp index e891dcfe..f5b1ea6e 100644 --- a/test/njs_expect_test.exp +++ b/test/njs_expect_test.exp @@ -461,55 +461,22 @@ njs_test { # require('fs').readFile() -njs_test { - {"var fs = require('fs')\r\n" - "undefined\r\n>> "} - {"fs.readFile('test/fs/utf8', 'utf8', (...args) => void console.log(args.length))\r\n" - "undefined\r\n2\r\n>> "} -} - -njs_test { - {"var fs = require('fs')\r\n" - "undefined\r\n>> "} - {"fs.readFile('test/fs/utf8', 'utf8', function (e, data) {console.log(data[2]+data.length)})\r\n" - "undefined\r\nZ4\r\n>> "} -} +njs_run {"./test/js/fs_readFile.js" "test/fs/utf8"} "αβZγ Buffer 7" +njs_run {"./test/js/fs_readFile.js" "test/fs/utf8" "utf8"} "αβZγ string 4" +njs_run {"./test/js/fs_readFile.js" "test/fs/utf8" "utf8" "r+"} "αβZγ string 4" +njs_run {"./test/js/fs_readFile.js" "test/fs/nonexistent"} \ + "{\"errno\":2,\"code\":\"ENOENT\",\"path\":\"test/fs/nonexistent\",\"syscall\":\"open\"}" +njs_run {"./test/js/fs_readFile.js" "test/fs/non_utf8" "utf8"} "�� string 2" +njs_run {"./test/js/fs_readFile.js" "test/fs/non_utf8" "hex"} "8080 string 4" +njs_run {"./test/js/fs_readFile.js" "test/fs/non_utf8" "base64"} "gIA= string 4" njs_test { {"var fs = require('fs')\r\n" "undefined\r\n>> "} - {"fs.readFile('test/fs/utf8', function (e, data) {console.log(data[4]+data.length)})\r\n" - "undefined\r\nZ7\r\n>> "} -} - -njs_test { - {"var fs = require('fs')\r\n" - "undefined\r\n>> "} - {"fs.readFile('test/fs/utf8', {encoding:'utf8',flag:'r+'}, function (e, data) {console.log(data)})\r\n" - "undefined\r\nαβZγ\r\n>> "} -} - -njs_test { - {"var fs = require('fs')\r\n" - "undefined\r\n>> "} - {"fs.readFile('test/fs/ascii', function (e, data) {console.log(data[599])})\r\n" - "undefined\r\nx\r\n>> "} - {"fs.readFile('test/fs/ascii', {encoding:'utf8',flag:'r+'}, function (e, data) {console.log(data[599])})\r\n" - "undefined\r\nx\r\n>> "} -} - -njs_test { - {"var fs = require('fs'); \r\n" - "undefined\r\n>> "} - {"fs.readFile('test/fs/nonexistent', 'utf8', function (e) {console.log(JSON.stringify(e))})\r\n" - "undefined\r\n{\"errno\":2,\"code\":\"ENOENT\",\"path\":\"test/fs/nonexistent\",\"syscall\":\"open\"}\r\n>> "} -} - -njs_test { - {"var fs = require('fs'); \r\n" - "undefined\r\n>> "} - {"fs.readFile('test/fs/nonexistent', {encoding:'utf8', flag:'r+'}, function (e) {console.log(e)})\r\n" - "undefined\r\nError: No such file or directory\r\n>> "} + {"fs.readFile('test/fs/ascii', 'utf8', function (e, data) {console.log(data[599], data[600])})\r\n" + "undefined\r\nx undefined\r\n>> "} + {"fs.readFile('test/fs/ascii', {encoding:'utf8',flag:'r+'}, function (e, data) {console.log(data[599], data[600])})\r\n" + "undefined\r\nx undefined\r\n>> "} } njs_test { @@ -523,60 +490,20 @@ njs_test { # require('fs').readFileSync() -njs_test { - {"var fs = require('fs')\r\n" - "undefined\r\n>> "} - {"fs.readFileSync('test/fs/utf8').toString('base64')\r\n" - "'zrHOslrOsw=='\r\n>> "} -} - -njs_test { - {"var fs = require('fs')\r\n" - "undefined\r\n>> "} - {"fs.readFileSync('test/fs/utf8', 'utf8')[2]\r\n" - "'Z'\r\n>> "} -} - -njs_test { - {"var fs = require('fs')\r\n" - "undefined\r\n>> "} - {"fs.readFileSync('test/fs/utf8')[4]\r\n" - "'Z'\r\n>> "} -} +njs_run {"./test/js/fs_readFileSync.js" "test/fs/utf8"} "αβZγ Buffer 7" +njs_run {"./test/js/fs_readFileSync.js" "test/fs/utf8" "utf8"} "αβZγ string 4" +njs_run {"./test/js/fs_readFileSync.js" "test/fs/utf8" "utf8" "r+"} "αβZγ string 4" +njs_run {"./test/js/fs_readFileSync.js" "test/fs/nonexistent"} \ + "{\"errno\":2,\"code\":\"ENOENT\",\"path\":\"test/fs/nonexistent\",\"syscall\":\"open\"}" +njs_run {"./test/js/fs_readFileSync.js" "test/fs/non_utf8" "utf8"} "�� string 2" +njs_run {"./test/js/fs_readFileSync.js" "test/fs/non_utf8" "hex"} "8080 string 4" +njs_run {"./test/js/fs_readFileSync.js" "test/fs/non_utf8" "base64"} "gIA= string 4" njs_test { {"var fs = require('fs')\r\n" "undefined\r\n>> "} - {"fs.readFileSync('test/fs/utf8', {encoding:'utf8',flag:'r+'})\r\n" - "'αβZγ'\r\n>> "} -} - -njs_test { - {"var fs = require('fs'), fn = 'test/fs/ascii'\r\n" - "undefined\r\n>> "} - {"fs.readFileSync(fn)[599] + fs.readFileSync(fn, 'utf8')[599]\r\n" - "'xx'\r\n>> "} -} - -njs_test { - {"var fs = require('fs'); \r\n" - "undefined\r\n>> "} - {"try { fs.readFileSync('test/fs/nonexistent')} catch (e) {console.log(JSON.stringify(e))}\r\n" - "{\"errno\":2,\"code\":\"ENOENT\",\"path\":\"test/fs/nonexistent\",\"syscall\":\"open\"}\r\nundefined\r\n>> "} -} - -njs_test { - {"var fs = require('fs')\r\n" - "undefined\r\n>> "} - {"fs.readFileSync('test/fs/non_utf8').charCodeAt(1)\r\n" - "128"} -} - -njs_test { - {"var fs = require('fs')\r\n" - "undefined\r\n>> "} - {"fs.readFileSync('test/fs/non_utf8', 'utf8')\r\n" - "Error: Non-UTF8 file, convertion is not implemented"} + {"fs.readFileSync('test/fs/non_utf8', 'utf8').charCodeAt(1)\r\n" + "65533"} } njs_test { @@ -594,46 +521,19 @@ njs_test { # require('fs').writeFile() -exec rm -fr ./build/test/file2 +njs_run {"./test/js/fs_writeFile.js" "ABCD" "Buffer" "1"} "BCD" +njs_run {"./test/js/fs_writeFile.js" "ABC" "DataView"} "ABC" +njs_run {"./test/js/fs_writeFile.js" "414243" "Object" "hex"} "ABC" +njs_run {"./test/js/fs_writeFile.js" "ABC" "String"} "ABC" +njs_run {"./test/js/fs_writeFile.js" "ABC" "Symbol"} "TypeError: Cannot convert a Symbol value to a string*" +njs_run {"./test/js/fs_writeFile.js" "ABC" "Uint8Array"} "ABC" -njs_test { - {"var fs = require('fs'), fn = './build/test/file2';\r\n" - "undefined\r\n>> "} - {"function h1(e) {if (e) {throw e}; console.log(fs.readFileSync(fn))}\r\n" - "undefined\r\n>> "} - {"fs.writeFile(fn, 'ABC', h1)\r\n" - "undefined\r\nABC\r\n>> "} -} - -njs_test { - {"var fs = require('fs'), fn = './build/test/file2';\r\n" - "undefined\r\n>> "} - {"fs.writeFile(fn, 'ABC', (...args) => void console.log(args.length))\r\n" - "undefined\r\n1\r\n>> "} -} - -njs_test { - {"var fs = require('fs'), fn = './build/test/file2';\r\n" - "undefined\r\n>> "} - {"fs.writeFile(fn, 'ABC', 'utf8', function (e) { if (e) {throw e}; console.log(fs.readFileSync(fn))})\r\n" - "undefined\r\nABC\r\n>> "} -} - -njs_test { - {"var fs = require('fs'), fn = './build/test/file2';\r\n" - "undefined\r\n>> "} - {"fs.writeFile(fn, 'ABC', {encoding:'utf8', mode:0o666}, function (e) { if (e) {throw e}; console.log(fs.readFileSync(fn))})\r\n" - "undefined\r\nABC\r\n>> "} -} - -exec rm -fr ./build/test/wo_file - -njs_test { - {"var fs = require('fs'), fn = './build/test/wo_file';\r\n" - "undefined\r\n>> "} - {"fs.writeFile(fn, 'ABC', {mode:0o222}, function (e) {console.log(fs.readFileSync(fn))})\r\n" - "Error: Permission denied"} -} +njs_run {"./test/js/fs_writeFile.js" "ABC" "String" "utf8"} "ABC" +njs_run {"./test/js/fs_writeFile.js" "ABC" "String" "utf8" "0o666"} "ABC" +njs_run {"./test/js/fs_writeFile.js" "ABC" "String" "utf8" "0o222"} "Error: Permission denied*" +njs_run {"./test/js/fs_writeFile.js" "414243" "String" "hex"} "ABC" +njs_run {"./test/js/fs_writeFile.js" "QUJD" "String" "base64"} "ABC" +njs_run {"./test/js/fs_writeFile.js" "QUJD" "String" "base64url"} "ABC" njs_test { {"var fs = require('fs')\r\n" @@ -644,25 +544,19 @@ njs_test { # require('fs').writeFileSync() -exec rm -fr ./build/test/file2 - -njs_test { - {"var fs = require('fs'), fn = './build/test/file2';\r\n" - "undefined\r\n>> "} - {"fs.writeFileSync(fn, 'ABC')\r\n" - "undefined\r\n>> "} - {"fs.readFileSync(fn)\r\n" - "'ABC'\r\n>> "} -} +njs_run {"./test/js/fs_writeFileSync.js" "ABCD" "Buffer" "1"} "BCD" +njs_run {"./test/js/fs_writeFileSync.js" "ABC" "DataView"} "ABC" +njs_run {"./test/js/fs_writeFileSync.js" "414243" "Object" "hex"} "ABC" +njs_run {"./test/js/fs_writeFileSync.js" "ABC" "String"} "ABC" +njs_run {"./test/js/fs_writeFileSync.js" "ABC" "Symbol"} "TypeError: Cannot convert a Symbol value to a string*" +njs_run {"./test/js/fs_writeFileSync.js" "ABC" "Uint8Array"} "ABC" -njs_test { - {"var fs = require('fs'), fn = './build/test/file2';\r\n" - "undefined\r\n>> "} - {"fs.writeFileSync(fn, 'ABC', 'utf8')\r\n" - "undefined\r\n>> "} - {"fs.readFileSync(fn)\r\n" - "'ABC'\r\n>> "} -} +njs_run {"./test/js/fs_writeFileSync.js" "ABC" "String" "utf8"} "ABC" +njs_run {"./test/js/fs_writeFileSync.js" "ABC" "String" "utf8" "0o666"} "ABC" +njs_run {"./test/js/fs_writeFileSync.js" "ABC" "String" "utf8" "0o222"} "Error: Permission denied*" +njs_run {"./test/js/fs_writeFileSync.js" "78797a" "String" "hex"} "xyz" +njs_run {"./test/js/fs_writeFileSync.js" "eHl6" "String" "base64"} "xyz" +njs_run {"./test/js/fs_writeFileSync.js" "eHl6" "String" "base64url"} "xyz" njs_test { {"var fs = require('fs'), fn = './build/test/file2';\r\n" @@ -671,57 +565,41 @@ njs_test { "undefined\r\n>> "} {"fs.writeFileSync(fn, 'ABC')\r\n" "undefined\r\n>> "} - {"fs.readFileSync(fn)\r\n" + {"fs.readFileSync(fn, 'utf8')\r\n" "'ABC'\r\n>> "} } -njs_test { - {"var fs = require('fs'), fn = './build/test/file2';\r\n" - "undefined\r\n>> "} - {"fs.writeFileSync(fn, 'ABC', {encoding:'utf8', mode:0o666})\r\n" - "undefined\r\n>> "} - {"fs.readFileSync(fn)\r\n" - "'ABC'\r\n>> "} -} - -exec rm -fr ./build/test/wo_file - -njs_test { - {"var fs = require('fs'), fn = './build/test/wo_file';\r\n" - "undefined\r\n>> "} - {"fs.writeFileSync(fn, 'ABC', {mode:0o222}); fs.readFileSync(fn)\r\n" - "Error: Permission denied"} -} - # require('fs').appendFile() -exec rm -fr ./build/test/file2 +njs_run {"./test/js/fs_appendFile.js" "ABCD" "Buffer" "1"} "BCDBCD" +njs_run {"./test/js/fs_appendFile.js" "ABC" "DataView"} "ABCABC" +njs_run {"./test/js/fs_appendFile.js" "414243" "Object" "hex"} "ABCABC" +njs_run {"./test/js/fs_appendFile.js" "ABC" "String"} "ABCABC" +njs_run {"./test/js/fs_appendFile.js" "ABC" "Symbol"} "TypeError: Cannot convert a Symbol value to a string*" +njs_run {"./test/js/fs_appendFile.js" "ABC" "Uint8Array"} "ABCABC" -njs_test { - {"var fs = require('fs'), fn = './build/test/file2';\r\n" - "undefined\r\n>> "} - {"function h1(e) {console.log(fs.readFileSync(fn))}\r\n" - "undefined\r\n>> "} - {"function h2(e) {fs.appendFile(fn, 'ABC', h1)}\r\n" - "undefined\r\n>> "} - {"fs.appendFile(fn, 'ABC', h2)\r\n" - "undefined\r\nABCABC\r\n>> "} -} +njs_run {"./test/js/fs_appendFile.js" "ABC" "String" "utf8"} "ABC" +njs_run {"./test/js/fs_appendFile.js" "ABC" "String" "utf8" "0o666"} "ABC" +njs_run {"./test/js/fs_appendFile.js" "ABC" "String" "utf8" "0o222"} "Error: Permission denied*" +njs_run {"./test/js/fs_appendFile.js" "414243" "String" "hex"} "ABC" +njs_run {"./test/js/fs_appendFile.js" "QUJD" "String" "base64"} "ABC" +njs_run {"./test/js/fs_appendFile.js" "QUJD" "String" "base64url"} "ABC" # require('fs').appendFileSync() -exec rm -fr ./build/test/file2 +njs_run {"./test/js/fs_appendFileSync.js" "ABCD" "Buffer" "1"} "BCDBCD" +njs_run {"./test/js/fs_appendFileSync.js" "ABC" "DataView"} "ABCABC" +njs_run {"./test/js/fs_appendFileSync.js" "414243" "Object" "hex"} "ABCABC" +njs_run {"./test/js/fs_appendFileSync.js" "ABC" "String"} "ABCABC" +njs_run {"./test/js/fs_appendFileSync.js" "ABC" "Symbol"} "TypeError: Cannot convert a Symbol value to a string*" +njs_run {"./test/js/fs_appendFileSync.js" "ABC" "Uint8Array"} "ABCABC" -njs_test { - {"var fs = require('fs'), fn = './build/test/file2';\r\n" - "undefined\r\n>> "} - {"fs.appendFileSync(fn, 'ABC')\r\n" - "undefined\r\n>> "} - {"fs.appendFileSync(fn, 'ABC')\r\n" - "undefined\r\n>> "} - {"fs.readFileSync(fn)\r\n" - "'ABCABC'\r\n>> "} -} +njs_run {"./test/js/fs_appendFileSync.js" "ABC" "String" "utf8"} "ABC" +njs_run {"./test/js/fs_appendFileSync.js" "ABC" "String" "utf8" "0o666"} "ABC" +njs_run {"./test/js/fs_appendFileSync.js" "ABC" "String" "utf8" "0o222"} "Error: Permission denied*" +njs_run {"./test/js/fs_appendFileSync.js" "414243" "String" "hex"} "ABC" +njs_run {"./test/js/fs_appendFileSync.js" "QUJD" "String" "base64"} "ABC" +njs_run {"./test/js/fs_appendFileSync.js" "QUJD" "String" "base64url"} "ABC" # require('fs').renameSync() @@ -734,17 +612,30 @@ njs_test { "undefined\r\n>> "} {"fs.renameSync(fn1, fn2)\r\n" "undefined\r\n>> "} - {"fs.readFileSync(fn2)\r\n" + {"String(fs.readFileSync(fn2))\r\n" "'ABC'\r\n>> "} } njs_test { - {"var fs = require('fs')\r\n" + {"var fs = require('fs'), fn = './build/test/file2'\r\n" "undefined\r\n>> "} - {"fs.renameSync('build/test/file2', 'test/fs/')\r\n" + {"fs.writeFileSync(fn, 'ABC')\r\n" + "undefined\r\n>> "} + {"fs.renameSync(fn, 'test/fs/')\r\n" "Error: Not a directory*"} } +# require('fs').realpathSync() + +njs_test { + {"var fs = require('fs')\r\n" + "undefined\r\n>> "} + {"fs.realpathSync('./build/test/..').endsWith('build')\r\n" + "true\r\n>> "} + {"fs.realpathSync('./build/test/..', {encoding:'buffer'}) instanceof Buffer\r\n" + "true\r\n>> "} +} + njs_run {"-c" "setTimeout(() => {console.log('A'.repeat(1024))}, 0); ref"} \ "^Thrown: ReferenceError: \"ref\" is not defined @@ -1110,7 +1001,6 @@ short circut ok true chain ok true error 1 ok true error 2 ok true -error 3 ok true errors ok" njs_run {"./test/js/fs_promises_002.js"} \ -- 2.47.3