typedef enum {
NJS_FS_STAT,
NJS_FS_LSTAT,
+ NJS_FS_FSTAT,
} njs_fs_statmode_t;
} njs_stat_prop_t;
+typedef struct {
+ njs_int_t fd;
+ njs_vm_t *vm;
+} njs_filehandle_t;
+
+
+typedef struct {
+ njs_int_t bytes;
+ njs_value_t buffer;
+} njs_bytes_struct_t;
+
+
typedef njs_int_t (*njs_file_tree_walk_cb_t)(const char *, const struct stat *,
njs_ftw_type_t);
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,
+static njs_int_t njs_fs_open(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t calltype);
+static njs_int_t njs_fs_close(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_read_file(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);
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,
+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_write_file(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,
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_filehandle_close(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused);
+static njs_int_t njs_fs_filehandle_value_of(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused);
+static njs_int_t njs_fs_filehandle_create(njs_vm_t *vm, int fd,
+ njs_bool_t shadow, njs_value_t *retval);
+
+static njs_int_t njs_fs_bytes_read_create(njs_vm_t *vm, int bytes,
+ njs_value_t *buffer, njs_value_t *retval);
+static njs_int_t njs_fs_bytes_written_create(njs_vm_t *vm, int bytes,
+ njs_value_t *buffer, 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,
.writable = 1,
.configurable = 1,
.u.method = {
- .native = njs_fs_write,
+ .native = njs_fs_write_file,
.magic8 = njs_fs_magic(NJS_FS_CALLBACK, NJS_FS_APPEND),
}
},
.writable = 1,
.configurable = 1,
.u.method = {
- .native = njs_fs_write,
+ .native = njs_fs_write_file,
.magic8 = njs_fs_magic(NJS_FS_DIRECT, NJS_FS_APPEND),
}
},
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("closeSync"),
+ .writable = 1,
+ .configurable = 1,
+ .u.method = {
+ .native = njs_fs_close,
+ .magic8 = NJS_FS_DIRECT,
+ }
+ },
+
{
.flags = NJS_EXTERN_PROPERTY,
.name.string = njs_str("constants"),
}
},
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("fstatSync"),
+ .writable = 1,
+ .configurable = 1,
+ .u.method = {
+ .native = njs_fs_stat,
+ .magic8 = njs_fs_magic(NJS_FS_DIRECT, NJS_FS_FSTAT),
+ }
+ },
+
{
.flags = NJS_EXTERN_METHOD,
.name.string = njs_str("lstat"),
}
},
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("openSync"),
+ .writable = 1,
+ .configurable = 1,
+ .u.method = {
+ .native = njs_fs_open,
+ .magic8 = NJS_FS_DIRECT,
+ }
+ },
+
{
.flags = NJS_EXTERN_PROPERTY,
.name.string = njs_str("promises"),
.writable = 1,
.configurable = 1,
.u.method = {
- .native = njs_fs_read,
+ .native = njs_fs_read_file,
.magic8 = NJS_FS_CALLBACK,
}
},
.name.string = njs_str("readFileSync"),
.writable = 1,
.configurable = 1,
+ .u.method = {
+ .native = njs_fs_read_file,
+ .magic8 = NJS_FS_DIRECT,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("readSync"),
+ .writable = 1,
+ .configurable = 1,
.u.method = {
.native = njs_fs_read,
.magic8 = NJS_FS_DIRECT,
.writable = 1,
.configurable = 1,
.u.method = {
- .native = njs_fs_write,
+ .native = njs_fs_write_file,
.magic8 = njs_fs_magic(NJS_FS_CALLBACK, NJS_FS_TRUNC),
}
},
.writable = 1,
.configurable = 1,
.u.method = {
- .native = njs_fs_write,
+ .native = njs_fs_write_file,
.magic8 = njs_fs_magic(NJS_FS_DIRECT, NJS_FS_TRUNC),
}
},
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("writeSync"),
+ .writable = 1,
+ .configurable = 1,
+ .u.method = {
+ .native = njs_fs_write,
+ .magic8 = NJS_FS_DIRECT,
+ }
+ },
+
};
};
+static njs_external_t njs_ext_filehandle[] = {
+
+ {
+ .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL,
+ .name.symbol = NJS_SYMBOL_TO_STRING_TAG,
+ .u.property = {
+ .value = "FileHandle",
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("close"),
+ .writable = 1,
+ .configurable = 1,
+ .u.method = {
+ .native = njs_fs_filehandle_close,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_PROPERTY,
+ .name.string = njs_str("fd"),
+ .enumerable = 1,
+ .u.property = {
+ .handler = njs_external_property,
+ .magic32 = offsetof(njs_filehandle_t, fd),
+ .magic16 = NJS_EXTERN_TYPE_INT,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("read"),
+ .writable = 1,
+ .configurable = 1,
+ .u.method = {
+ .native = njs_fs_read,
+ .magic8 = NJS_FS_PROMISE,
+ }
+ },
+
+ {
+ .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_PROMISE, NJS_FS_FSTAT),
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("valueOf"),
+ .writable = 1,
+ .configurable = 1,
+ .u.method = {
+ .native = njs_fs_filehandle_value_of,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("write"),
+ .writable = 1,
+ .configurable = 1,
+ .u.method = {
+ .native = njs_fs_write,
+ .magic8 = NJS_FS_PROMISE,
+ }
+ },
+
+};
+
+
+static njs_external_t njs_ext_bytes_read[] = {
+
+ {
+ .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL,
+ .name.symbol = NJS_SYMBOL_TO_STRING_TAG,
+ .u.property = {
+ .value = "BytesRead",
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_PROPERTY,
+ .name.string = njs_str("buffer"),
+ .enumerable = 1,
+ .u.property = {
+ .handler = njs_external_property,
+ .magic32 = offsetof(njs_bytes_struct_t, buffer),
+ .magic16 = NJS_EXTERN_TYPE_VALUE,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_PROPERTY,
+ .name.string = njs_str("bytesRead"),
+ .enumerable = 1,
+ .u.property = {
+ .handler = njs_external_property,
+ .magic32 = offsetof(njs_bytes_struct_t, bytes),
+ .magic16 = NJS_EXTERN_TYPE_INT,
+ }
+ },
+
+};
+
+
+static njs_external_t njs_ext_bytes_written[] = {
+
+ {
+ .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL,
+ .name.symbol = NJS_SYMBOL_TO_STRING_TAG,
+ .u.property = {
+ .value = "BytesWritten",
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_PROPERTY,
+ .name.string = njs_str("buffer"),
+ .enumerable = 1,
+ .u.property = {
+ .handler = njs_external_property,
+ .magic32 = offsetof(njs_bytes_struct_t, buffer),
+ .magic16 = NJS_EXTERN_TYPE_VALUE,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_PROPERTY,
+ .name.string = njs_str("bytesWritten"),
+ .enumerable = 1,
+ .u.property = {
+ .handler = njs_external_property,
+ .magic32 = offsetof(njs_bytes_struct_t, bytes),
+ .magic16 = NJS_EXTERN_TYPE_INT,
+ }
+ },
+
+};
+
+
static njs_int_t njs_fs_stats_proto_id;
static njs_int_t njs_fs_dirent_proto_id;
+static njs_int_t njs_fs_filehandle_proto_id;
+static njs_int_t njs_fs_bytes_read_proto_id;
+static njs_int_t njs_fs_bytes_written_proto_id;
njs_module_t njs_fs_module = {
}
+static njs_int_t
+njs_fs_open(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t calltype)
+{
+ int fd, flags;
+ mode_t md;
+ njs_int_t ret;
+ const char *path;
+ njs_value_t retval, *value;
+ 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;
+ }
+
+ value = njs_arg(args, nargs, 2);
+ if (njs_is_function(value)) {
+ value = njs_value_arg(&njs_value_undefined);
+ }
+
+ flags = njs_fs_flags(vm, value, O_RDONLY);
+ if (njs_slow_path(flags == -1)) {
+ return NJS_ERROR;
+ }
+
+ value = njs_arg(args, nargs, 3);
+ if (njs_is_function(value)) {
+ value = njs_value_arg(&njs_value_undefined);
+ }
+
+ md = njs_fs_mode(vm, value, 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;
+ }
+
+ ret = njs_fs_filehandle_create(vm, fd, calltype == NJS_FS_DIRECT, &retval);
+ if (njs_slow_path(ret != NJS_OK)) {
+ goto done;
+ }
+
+ if (calltype == NJS_FS_DIRECT) {
+ njs_value_number_set(&retval, fd);
+ }
+
+done:
+
+ if (ret == NJS_OK) {
+ return njs_fs_result(vm, &retval, calltype, NULL, 2);
+ }
+
+ if (fd != -1) {
+ (void) close(fd);
+ }
+
+ return NJS_ERROR;
+}
+
+
+static njs_int_t
+njs_fs_close(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t calltype)
+{
+ int64_t fd;
+ njs_int_t ret;
+ njs_value_t retval, *fh;
+
+ fh = njs_arg(args, nargs, 1);
+
+ ret = njs_value_to_integer(vm, fh, &fd);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ njs_set_undefined(&retval);
+
+ ret = close((int) fd);
+ if (njs_slow_path(ret != 0)) {
+ ret = njs_fs_error(vm, "close", strerror(errno), NULL, errno, &retval);
+ }
+
+ if (ret == NJS_OK) {
+ return njs_fs_result(vm, &retval, calltype, NULL, 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)
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_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;
+ }
+ }
+
+ md = njs_fs_mode(vm, &mode, 0777);
+ if (njs_slow_path(md == (mode_t) -1)) {
+ return NJS_ERROR;
+ }
+
+ 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)
+{
+ int64_t fd, length, pos, offset;
+ ssize_t n;
+ njs_int_t ret;
+ njs_str_t data;
+ njs_uint_t fd_offset;
+ njs_value_t retval, *buffer, *value;
+ njs_typed_array_t *array;
+ njs_array_buffer_t *array_buffer;
+
+ fd_offset = !!(calltype == NJS_FS_DIRECT);
+
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, fd_offset), &fd);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ pos = -1;
+
+ /*
+ * fh.read(buffer, offset[, length[, position]])
+ * fs.readSync(fd, buffer, offset[, length[, position]])
+ */
+
+ buffer = njs_arg(args, nargs, fd_offset + 1);
+ array = njs_buffer_slot(vm, buffer, "buffer");
+ if (njs_slow_path(array == NULL)) {
+ return NJS_ERROR;
+ }
+
+ array_buffer = njs_typed_array_writable(vm, array);
+ if (njs_slow_path(array_buffer == NULL)) {
+ return NJS_ERROR;
+ }
+
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, fd_offset + 2),
+ &offset);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ if (njs_slow_path(offset < 0 || (size_t) offset > array->byte_length)) {
+ njs_range_error(vm, "offset is out of range (must be <= %z)",
+ array->byte_length);
+ return NJS_ERROR;
+ }
+
+ data.length = array->byte_length - offset;
+ data.start = &array_buffer->u.u8[array->offset + offset];
+
+ value = njs_arg(args, nargs, fd_offset + 3);
+
+ if (njs_is_defined(value)) {
+ ret = njs_value_to_integer(vm, value, &length);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ if (njs_slow_path(length < 0 || (size_t) length > data.length)) {
+ njs_range_error(vm, "length is out of range (must be <= %z)",
+ data.length);
+ return NJS_ERROR;
}
- ret = njs_value_property(vm, options, njs_value_arg(&string_recursive),
- &recursive);
- if (njs_slow_path(ret == NJS_ERROR)) {
+ data.length = length;
+ }
+
+ value = njs_arg(args, nargs, fd_offset + 4);
+
+ if (!njs_is_null_or_undefined(value)) {
+ ret = njs_value_to_integer(vm, value, &pos);
+ if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
}
- md = njs_fs_mode(vm, &mode, 0777);
- if (njs_slow_path(md == (mode_t) -1)) {
- return NJS_ERROR;
+ if (pos == -1) {
+ n = read(fd, data.start, data.length);
+
+ } else {
+ n = pread(fd, data.start, data.length, pos);
}
- ret = njs_fs_make_path(vm, path, md, njs_is_true(&recursive), &retval);
+ if (njs_slow_path(n == -1)) {
+ ret = njs_fs_error(vm, "read", strerror(errno), NULL, errno, &retval);
+ goto done;
+ }
+
+ if (calltype == NJS_FS_PROMISE) {
+ ret = njs_fs_bytes_read_create(vm, n, buffer, &retval);
+ if (njs_slow_path(ret != NJS_OK)) {
+ goto done;
+ }
+
+ } else {
+ njs_value_number_set(&retval, n);
+ }
+
+done:
if (ret == NJS_OK) {
- return njs_fs_result(vm, &retval, calltype, callback, 1);
+ return njs_fs_result(vm, &retval, calltype, NULL, 1);
}
return NJS_ERROR;
static njs_int_t
-njs_fs_read(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+njs_fs_read_file(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t calltype)
{
int fd, flags;
njs_fs_stat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t magic)
{
+ int64_t fd;
njs_int_t ret;
+ njs_uint_t fd_offset;
njs_bool_t throw;
struct stat sb;
const char *path;
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)) {
- return NJS_ERROR;
+ fd = -1;
+ path = NULL;
+ calltype = magic & 3;
+
+ if ((magic >> 2) != NJS_FS_FSTAT) {
+ path = njs_fs_path(vm, path_buf, njs_arg(args, nargs, 1), "path");
+ if (njs_slow_path(path == NULL)) {
+ return NJS_ERROR;
+ }
+
+ options = njs_arg(args, nargs, 2);
+
+ } else {
+ fd_offset = !!(calltype == NJS_FS_DIRECT);
+ ret = njs_value_to_integer(vm, njs_argument(args, fd_offset), &fd);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ options = njs_arg(args, nargs, fd_offset + 1);
}
callback = NULL;
- calltype = magic & 3;
- options = njs_arg(args, nargs, 2);
if (njs_slow_path(calltype == NJS_FS_CALLBACK)) {
callback = njs_arg(args, nargs, njs_min(nargs - 1, 3));
}
}
- ret = ((magic >> 2) == NJS_FS_STAT) ? stat(path, &sb) : lstat(path, &sb);
+ switch (magic >> 2) {
+ case NJS_FS_STAT:
+ ret = stat(path, &sb);
+ break;
+
+ case NJS_FS_LSTAT:
+ ret = lstat(path, &sb);
+ break;
+
+ case NJS_FS_FSTAT:
+ default:
+ ret = fstat(fd, &sb);
+ break;
+ }
+
if (njs_slow_path(ret != 0)) {
if (errno != ENOENT || throw) {
ret = njs_fs_error(vm,
static njs_int_t
njs_fs_write(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t calltype)
+{
+ int64_t fd, length, pos, offset;
+ ssize_t n;
+ njs_int_t ret;
+ njs_str_t data;
+ njs_uint_t fd_offset;
+ njs_value_t retval, *buffer, *value;
+ const njs_buffer_encoding_t *encoding;
+
+ fd_offset = !!(calltype == NJS_FS_DIRECT);
+
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, fd_offset), &fd);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ buffer = njs_arg(args, nargs, fd_offset + 1);
+
+ pos = -1;
+ encoding = NULL;
+
+ /*
+ * fs.writeSync(fd, string[, position[, encoding]])
+ * fh.write(string[, position[, encoding]])
+ */
+
+ if (njs_is_string(buffer)) {
+ value = njs_arg(args, nargs, fd_offset + 2);
+
+ if (!njs_is_null_or_undefined(value)) {
+ ret = njs_value_to_integer(vm, value, &pos);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+ }
+
+ encoding = njs_buffer_encoding(vm, njs_arg(args, nargs, fd_offset + 3));
+ if (njs_slow_path(encoding == NULL)) {
+ return NJS_ERROR;
+ }
+
+ ret = njs_buffer_decode_string(vm, buffer, &retval, encoding);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ njs_string_get(&retval, &data);
+
+ goto process;
+ }
+
+ /*
+ * fh.write(buffer, offset[, length[, position]])
+ * fs.writeSync(fd, buffer, offset[, length[, position]])
+ */
+
+ ret = njs_vm_value_to_bytes(vm, &data, buffer);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, fd_offset + 2),
+ &offset);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ if (njs_slow_path(offset < 0 || (size_t) offset > data.length)) {
+ njs_range_error(vm, "offset is out of range (must be <= %z)",
+ data.length);
+ return NJS_ERROR;
+ }
+
+ data.length -= offset;
+ data.start += offset;
+
+ value = njs_arg(args, nargs, fd_offset + 3);
+
+ if (njs_is_defined(value)) {
+ ret = njs_value_to_integer(vm, value, &length);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ if (njs_slow_path(length < 0 || (size_t) length > data.length)) {
+ njs_range_error(vm, "length is out of range (must be <= %z)",
+ data.length);
+ return NJS_ERROR;
+ }
+
+ data.length = length;
+ }
+
+ value = njs_arg(args, nargs, fd_offset + 4);
+
+ if (!njs_is_null_or_undefined(value)) {
+ ret = njs_value_to_integer(vm, value, &pos);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+ }
+
+process:
+
+ if (pos == -1) {
+ n = write(fd, data.start, data.length);
+
+ } else {
+ n = pwrite(fd, data.start, data.length, pos);
+ }
+
+ if (njs_slow_path(n == -1)) {
+ ret = njs_fs_error(vm, "write", strerror(errno), NULL, errno, &retval);
+ goto done;
+ }
+
+ if (njs_slow_path((size_t) n != data.length)) {
+ ret = njs_fs_error(vm, "write", "failed to write all the data", NULL,
+ 0, &retval);
+ goto done;
+ }
+
+ if (calltype == NJS_FS_PROMISE) {
+ ret = njs_fs_bytes_written_create(vm, n, buffer, &retval);
+ if (njs_slow_path(ret != NJS_OK)) {
+ goto done;
+ }
+
+ } else {
+ njs_value_number_set(&retval, n);
+ }
+
+done:
+
+ if (ret == NJS_OK) {
+ return njs_fs_result(vm, &retval, calltype, NULL, 1);
+ }
+
+ return NJS_ERROR;
+}
+
+
+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;
}
+static njs_int_t
+njs_fs_filehandle_close(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ njs_value_t retval;
+ njs_filehandle_t *fh;
+
+ fh = njs_vm_external(vm, njs_fs_filehandle_proto_id, njs_argument(args, 0));
+ if (njs_slow_path(fh == NULL)) {
+ njs_type_error(vm, "\"this\" is not a filehandle object");
+ return NJS_ERROR;
+ }
+
+ if (njs_slow_path(fh->fd == -1)) {
+ njs_type_error(vm, "file was already closed");
+ return NJS_ERROR;
+ }
+
+ (void) close(fh->fd);
+ fh->fd = -1;
+
+ njs_set_undefined(&retval);
+
+ return njs_fs_result(vm, &retval, NJS_FS_PROMISE, NULL, 1);
+}
+
+
+static njs_int_t
+njs_fs_filehandle_value_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ njs_filehandle_t *fh;
+
+ fh = njs_vm_external(vm, njs_fs_filehandle_proto_id, njs_argument(args, 0));
+ if (njs_slow_path(fh == NULL)) {
+ njs_type_error(vm, "\"this\" is not a filehandle object");
+ return NJS_ERROR;
+ }
+
+ njs_set_number(njs_vm_retval(vm), fh->fd);
+
+ return NJS_OK;
+}
+
+
+static void
+njs_fs_filehandle_cleanup(void *data)
+{
+ njs_filehandle_t *fh = data;
+
+ if (fh->vm != NULL && fh->fd != -1) {
+ njs_vm_warn(fh->vm, "closing file description %d on cleanup\n", fh->fd);
+ (void) close(fh->fd);
+ }
+}
+
+
+static njs_int_t
+njs_fs_filehandle_create(njs_vm_t *vm, int fd, njs_bool_t shadow,
+ njs_value_t *retval)
+{
+ njs_filehandle_t *fh;
+ njs_mp_cleanup_t *cln;
+
+ fh = njs_mp_alloc(vm->mem_pool, sizeof(njs_filehandle_t));
+ if (njs_slow_path(fh == NULL)) {
+ njs_memory_error(vm);
+ return NJS_ERROR;
+ }
+
+ fh->fd = fd;
+ fh->vm = !shadow ? vm : NULL;
+
+ cln = njs_mp_cleanup_add(njs_vm_memory_pool(vm), 0);
+ if (cln == NULL) {
+ njs_memory_error(vm);
+ return NJS_ERROR;
+ }
+
+ cln->handler = njs_fs_filehandle_cleanup;
+ cln->data = fh;
+
+ return njs_vm_external_create(vm, retval, njs_fs_filehandle_proto_id,
+ fh, 0);
+}
+
+
+static njs_int_t
+njs_fs_bytes_read_create(njs_vm_t *vm, int bytes, njs_value_t *buffer,
+ njs_value_t *retval)
+{
+ njs_bytes_struct_t *bs;
+
+ bs = njs_mp_alloc(vm->mem_pool, sizeof(njs_bytes_struct_t));
+ if (njs_slow_path(bs == NULL)) {
+ njs_memory_error(vm);
+ return NJS_ERROR;
+ }
+
+ bs->bytes = bytes;
+ njs_value_assign(&bs->buffer, buffer);
+
+ return njs_vm_external_create(vm, retval, njs_fs_bytes_read_proto_id,
+ bs, 0);
+}
+
+
+static njs_int_t
+njs_fs_bytes_written_create(njs_vm_t *vm, int bytes, njs_value_t *buffer,
+ njs_value_t *retval)
+{
+ njs_bytes_struct_t *bs;
+
+ bs = njs_mp_alloc(vm->mem_pool, sizeof(njs_bytes_struct_t));
+ if (njs_slow_path(bs == NULL)) {
+ njs_memory_error(vm);
+ return NJS_ERROR;
+ }
+
+ bs->bytes = bytes;
+ njs_value_assign(&bs->buffer, buffer);
+
+ return njs_vm_external_create(vm, retval, njs_fs_bytes_written_proto_id,
+ bs, 0);
+}
+
+
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),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readSync"),
.value = njs_native_function2(njs_fs_read, 0, NJS_FS_PROMISE),
.writable = 1,
.configurable = 1,
{
.type = NJS_PROPERTY,
.name = njs_string("appendFile"),
- .value = njs_native_function2(njs_fs_write, 0,
+ .value = njs_native_function2(njs_fs_write_file, 0,
njs_fs_magic(NJS_FS_PROMISE, NJS_FS_APPEND)),
.writable = 1,
.configurable = 1,
{
.type = NJS_PROPERTY,
.name = njs_string("writeFile"),
- .value = njs_native_function2(njs_fs_write, 0,
+ .value = njs_native_function2(njs_fs_write_file, 0,
njs_fs_magic(NJS_FS_PROMISE, NJS_FS_TRUNC)),
.writable = 1,
.configurable = 1,
.configurable = 1,
},
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("open"),
+ .value = njs_native_function2(njs_fs_open, 0, NJS_FS_PROMISE),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("close"),
+ .value = njs_native_function2(njs_fs_close, 0, NJS_FS_PROMISE),
+ .writable = 1,
+ .configurable = 1,
+ },
+
{
.type = NJS_PROPERTY,
.name = njs_string("rename"),
.configurable = 1,
},
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("fstat"),
+ .value = njs_native_function2(njs_fs_stat, 0,
+ njs_fs_magic(NJS_FS_PROMISE, NJS_FS_FSTAT)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
{
.type = NJS_PROPERTY,
.name = njs_string("lstat"),
return NJS_ERROR;
}
+ njs_fs_filehandle_proto_id = njs_vm_external_prototype(vm,
+ njs_ext_filehandle,
+ njs_nitems(njs_ext_filehandle));
+ if (njs_slow_path(njs_fs_filehandle_proto_id < 0)) {
+ return NJS_ERROR;
+ }
+
+ njs_fs_bytes_read_proto_id = njs_vm_external_prototype(vm,
+ njs_ext_bytes_read,
+ njs_nitems(njs_ext_bytes_read));
+ if (njs_slow_path(njs_fs_bytes_written_proto_id < 0)) {
+ return NJS_ERROR;
+ }
+
+ njs_fs_bytes_written_proto_id = njs_vm_external_prototype(vm,
+ njs_ext_bytes_written,
+ njs_nitems(njs_ext_bytes_written));
+ if (njs_slow_path(njs_fs_bytes_written_proto_id < 0)) {
+ return NJS_ERROR;
+ }
+
proto_id = njs_vm_external_prototype(vm, njs_ext_fs,
njs_nitems(njs_ext_fs));
if (njs_slow_path(proto_id < 0)) {
function p(args, default_opts) {
let params = Object.assign({}, default_opts, args);
- let fname = params.args[0];
+ if (params.args) {
+ let fname = params.args[0];
- if (fname[0] == '@') {
- let gen = `${test_dir}/fs_test_${Math.round(Math.random() * 1000000)}`;
- params.args = params.args.map(v => v);
- params.args[0] = gen + fname.slice(1);
+ if (fname[0] == '@') {
+ let gen = `${test_dir}/fs_test_${Math.round(Math.random() * 1000000)}`;
+ params.args = params.args.map(v => v);
+ params.args[0] = gen + fname.slice(1);
+ }
}
return params;
return data;
}
-async function read_test(params) {
+async function readfile_test(params) {
let data = await method("readFile", params).catch(e => ({error:e}));
if (params.slice && !data.error) {
return 'SUCCESS';
}
-let read_tests = () => [
+let readfile_tests = () => [
{ args: ["test/fs/utf8"], expected: Buffer.from("αβZγ") },
{ args: [Buffer.from("@test/fs/utf8").slice(1)], expected: Buffer.from("αβZγ") },
{ args: ["test/fs/utf8", "utf8"], expected: "αβZγ" },
let readFile_tsuite = {
name: "fs readFile",
skip: () => (!has_fs() || !has_buffer()),
- T: read_test,
+ T: readfile_test,
prepare_args: p,
opts: { type: "callback" },
- get tests() { return read_tests() },
+ get tests() { return readfile_tests() },
};
let readFileSync_tsuite = {
name: "fs readFileSync",
skip: () => (!has_fs() || !has_buffer()),
- T: read_test,
+ T: readfile_test,
prepare_args: p,
opts: { type: "sync" },
- get tests() { return read_tests() },
+ get tests() { return readfile_tests() },
};
let readFileP_tsuite = {
name: "fsp readFile",
skip: () => (!has_fs() || !has_buffer()),
- T: read_test,
+ T: readfile_test,
prepare_args: p,
opts: { type: "promise" },
- get tests() { return read_tests() },
+ get tests() { return readfile_tests() },
};
-async function write_test(params) {
+async function writefile_test(params) {
let fname = params.args[0];
try { fs.unlinkSync(fname); } catch (e) {}
return 'SUCCESS';
}
-let write_tests = () => [
+let writefile_tests = () => [
{ args: ["@", Buffer.from(Buffer.alloc(4).fill(65).buffer, 1)],
expected: Buffer.from("AAA") },
{ args: ["@", Buffer.from("XYZ"), "utf8"], expected: Buffer.from("XYZ") },
let writeFile_tsuite = {
name: "fs writeFile",
skip: () => (!has_fs() || !has_buffer()),
- T: write_test,
+ T: writefile_test,
prepare_args: p,
opts: { type: "callback" },
- get tests() { return write_tests() },
+ get tests() { return writefile_tests() },
};
let writeFileSync_tsuite = {
name: "fs writeFileSync",
skip: () => (!has_fs() || !has_buffer()),
- T: write_test,
+ T: writefile_test,
prepare_args: p,
opts: { type: "sync" },
- get tests() { return write_tests() },
+ get tests() { return writefile_tests() },
};
let writeFileP_tsuite = {
name: "fsp writeFile",
skip: () => (!has_fs() || !has_buffer()),
- T: write_test,
+ T: writefile_test,
prepare_args: p,
opts: { type: "promise" },
- get tests() { return write_tests() },
+ get tests() { return writefile_tests() },
};
async function append_test(params) {
get tests() { return realpath_tests() },
};
-async function stat_test(params) {
+async function method_test(params) {
if (params.init) {
params.init(params);
}
- let stat = await method(params.method, params).catch(e => ({error:e}));
+ let ret = await method(params.method, params).catch(e => ({error:e}));
- if (params.check && !params.check(stat, params)) {
+ if (params.check && !params.check(ret, params)) {
throw Error(`${params.method} failed check`);
}
let stat_tsuite = {
name: "fs stat",
skip: () => (!has_fs() || !has_fs_symbolic_link() || !has_buffer()),
- T: stat_test,
+ T: method_test,
prepare_args: p,
opts: { type: "callback", method: "stat" },
get tests() { return stat_tests() },
let statSync_tsuite = {
name: "fs statSync",
skip: () => (!has_fs() || !has_fs_symbolic_link() || !has_buffer()),
- T: stat_test,
+ T: method_test,
prepare_args: p,
opts: { type: "sync", method: "stat" },
get tests() { return stat_tests() },
let statP_tsuite = {
name: "fsp stat",
skip: () => (!has_fs() || !has_fs_symbolic_link() || !has_buffer()),
- T: stat_test,
+ T: method_test,
prepare_args: p,
opts: { type: "promise", method: "stat" },
get tests() { return stat_tests() },
let lstat_tsuite = {
name: "fs lstat",
skip: () => (!has_fs() || !has_fs_symbolic_link() || !has_buffer()),
- T: stat_test,
+ T: method_test,
prepare_args: p,
opts: { type: "callback", method: "lstat" },
get tests() { return stat_tests() },
let lstatSync_tsuite = {
name: "fs lstatSync",
skip: () => (!has_fs() || !has_fs_symbolic_link() || !has_buffer()),
- T: stat_test,
+ T: method_test,
prepare_args: p,
opts: { type: "sync", method: "lstat" },
get tests() { return stat_tests() },
let lstatP_tsuite = {
name: "fsp lstat",
skip: () => (!has_fs() || !has_fs_symbolic_link() || !has_buffer()),
- T: stat_test,
+ T: method_test,
prepare_args: p,
opts: { type: "promise", method: "lstat" },
get tests() { return stat_tests() },
};
+let open_check = (fh, params) => {
+ if (params.type == 'promise') {
+
+ try {
+ if (typeof fh.fd != 'number') {
+ throw Error(`filehandle.fd:${fh.fd} is not an instance of Number`);
+ }
+
+ ['read', 'write', 'close', 'valueof'].every(v => {
+ if (typeof fh[v] != 'function') {
+ throw Error(`filehandle.close:${fh[v]} is not an instance of function`);
+ }
+ });
+
+ let mode = fs.fstatSync(fh.fd).mode & 0o777;
+ if (params.mode && params.mode != mode) {
+ throw Error(`opened mode ${mode} != ${params.mode}`);
+ }
+
+ } finally {
+ fh.close();
+ }
+
+ } else {
+
+ try {
+ if (typeof fh != 'number') {
+ throw Error(`fd:${fh} is not an instance of Number`);
+ }
+
+ let mode = fs.fstatSync(fh).mode & 0o777;
+ if (params.mode && params.mode != mode) {
+ throw Error(`opened mode ${mode} != ${params.mode}`);
+ }
+
+ } finally {
+ fs.closeSync(fh);
+ }
+ }
+
+ return true;
+};
+
+let open_tests = () => [
+ {
+ args: ["test/fs/ascii"],
+ check: open_check,
+ },
+
+ {
+ args: ["@", 'w', 0o600],
+ mode: 0o600,
+ check: open_check,
+ },
+
+ {
+ args: ["@", 'a', 0o700],
+ mode: 0o700,
+ check: open_check,
+ },
+
+ {
+ args: ["@", 'r'],
+ check: (err, params) => {
+ let e = err.error;
+
+ if (e.syscall != params.method) {
+ throw Error(`${e.syscall} unexpected syscall`);
+ }
+
+ if (e.code != "ENOENT") {
+ throw Error(`${e.code} unexpected code`);
+ }
+
+ return true;
+ },
+ },
+
+ {
+ args: ["/invalid_path"],
+ check: (err, params) => {
+ let e = err.error;
+
+ if (e.syscall != params.method) {
+ throw Error(`${e.syscall} unexpected syscall`);
+ }
+
+ if (e.code != "ENOENT") {
+ throw Error(`${e.code} unexpected code`);
+ }
+
+ return true;
+ },
+ },
+];
+
+let openSync_tsuite = {
+ name: "fs openSync",
+ skip: () => (!has_fs() || !has_buffer()),
+ T: method_test,
+ prepare_args: p,
+ opts: { type: "sync", method: "open" },
+ get tests() { return open_tests() },
+};
+
+let openP_tsuite = {
+ name: "fsp open",
+ skip: () => (!has_fs() || !has_buffer()),
+ T: method_test,
+ prepare_args: p,
+ opts: { type: "promise", method: "open" },
+ get tests() { return open_tests() },
+};
+
+let close_tests = () => [
+
+ {
+ args: [ fs.openSync("test/fs/ascii") ],
+ check: (undef, params) => undef === undefined,
+ },
+
+ {
+ args: [ (() => { let fd = fs.openSync("test/fs/ascii"); fs.closeSync(fd); return fd})() ],
+ check: (err, params) => {
+ let e = err.error;
+
+ if (e.syscall != params.method) {
+ throw Error(`${e.syscall} unexpected syscall`);
+ }
+
+ if (e.code != "EBADF") {
+ throw Error(`${e.code} unexpected code`);
+ }
+
+ return true;
+ },
+ },
+];
+
+let closeSync_tsuite = {
+ name: "fs closeSync",
+ skip: () => (!has_fs() || !has_buffer()),
+ T: method_test,
+ prepare_args: p,
+ opts: { type: "sync", method: "close" },
+ get tests() { return close_tests() },
+};
+
+function read_test(params) {
+ let fd, err;
+
+ let fn = `${test_dir}/fs_read_test_${Math.round(Math.random() * 1000000)}`;
+ let out = [];
+
+ fs.writeFileSync(fn, params.content);
+
+ try {
+ fd = fs.openSync(fn);
+
+ let buffer = Buffer.alloc(4);
+ buffer.fill('#');
+
+ for (var i = 0; i < params.read.length; i++) {
+ let args = params.read[i].map(v => v);
+ args.unshift(buffer);
+ args.unshift(fd);
+
+ let bytesRead = fs.readSync.apply(null, args);
+
+ out.push([bytesRead, Buffer.from(buffer)]);
+ }
+
+ } catch (e) {
+ if (!e.syscall && !params.check) {
+ throw e;
+ }
+
+ err = e;
+
+ } finally {
+ fs.closeSync(fd);
+ }
+
+ if (!err && params.expected) {
+ let expected = params.expected;
+
+ if (out.length != expected.length) {
+ throw Error(`unexpected readSync number of outputs ${out.length} != ${expected.length}`);
+ }
+
+ for (var i = 0; i < expected.length; i++) {
+ if (expected[i][0] != out[i][0]) {
+ throw Error(`unexpected readSync bytesRead:${out[i][0]} != ${expected[i][0]}`);
+ }
+
+ if (expected[i][1].compare(out[i][1]) != 0) {
+ throw Error(`unexpected readSync buffer:${out[i][1]} != ${expected[i][1]}`);
+ }
+ }
+
+ }
+
+ if (params.check && !params.check(err, params)) {
+ throw Error(`${params.method} failed check`);
+ }
+
+ return 'SUCCESS';
+}
+
+async function readFh_test(params) {
+ let fh, err;
+
+ let fn = `${test_dir}/fs_read_test_${Math.round(Math.random() * 1000000)}`;
+ let out = [];
+
+ fs.writeFileSync(fn, params.content);
+
+ try {
+ fh = await fs.promises.open(fn);
+
+ let buffer = Buffer.alloc(4);
+ buffer.fill('#');
+
+ for (var i = 0; i < params.read.length; i++) {
+ let args = params.read[i].map(v => v);
+ args.unshift(buffer);
+
+ let bs = await fh.read.apply(fh, args);
+
+ out.push([bs.bytesRead, Buffer.from(bs.buffer)]);
+ }
+
+ } catch (e) {
+ if (!e.syscall && !params.check) {
+ throw e;
+ }
+
+ err = e;
+
+ } finally {
+ await fh.close();
+ }
+
+ if (!err && params.expected) {
+ let expected = params.expected;
+
+ if (out.length != expected.length) {
+ throw Error(`unexpected read number of outputs ${out.length} != ${expected.length}`);
+ }
+
+ for (var i = 0; i < expected.length; i++) {
+ if (expected[i][0] != out[i][0]) {
+ throw Error(`unexpected read bytesRead:${out[i][0]} != ${expected[i][0]}`);
+ }
+
+ if (expected[i][1].compare(out[i][1]) != 0) {
+ throw Error(`unexpected read buffer:${out[i][1]} != ${expected[i][1]}`);
+ }
+ }
+
+ }
+
+ if (params.check && !params.check(err, params)) {
+ throw Error(`${params.method} failed check`);
+ }
+
+ return 'SUCCESS';
+}
+
+let read_tests = () => [
+
+ {
+ content: "ABC",
+ read: [ [0, 3], ],
+ expected: [ [3, Buffer.from("ABC#")], ],
+ },
+
+ {
+ content: "ABC",
+ read: [ [1, 2], ],
+ expected: [ [2, Buffer.from("#AB#")], ],
+ },
+
+ {
+ content: "ABC",
+ read: [ [1, 2, 1], ],
+ expected: [ [2, Buffer.from("#BC#")], ],
+ },
+
+ {
+ content: "__ABCDE",
+ read: [
+ [0, 4],
+ [0, 4],
+ [2, 2, 0],
+ [0, 4, null],
+ ],
+ expected: [
+ [4, Buffer.from("__AB")],
+ [3, Buffer.from("CDEB")],
+ [2, Buffer.from("CD__")],
+ [0, Buffer.from("CD__")],
+ ],
+ },
+
+ {
+ content: "ABC",
+ read: [ [0, 5], ],
+ check: (err, params) => {
+ if (err.name != "RangeError") {
+ throw Error(`${err.code} unexpected exception`);
+ }
+
+ return true;
+ },
+ },
+
+ {
+ content: "ABC",
+ read: [ [2, 3], ],
+ check: (err, params) => {
+ if (err.name != "RangeError") {
+ throw Error(`${err.code} unexpected exception`);
+ }
+
+ return true;
+ },
+ },
+
+];
+
+let readSync_tsuite = {
+ name: "fs readSync",
+ skip: () => (!has_fs() || !has_buffer()),
+ T: read_test,
+ prepare_args: p,
+ opts: {},
+ get tests() { return read_tests() },
+};
+
+let readFh_tsuite = {
+ name: "fh read",
+ skip: () => (!has_fs() || !has_buffer()),
+ T: readFh_test,
+ prepare_args: p,
+ opts: {},
+ get tests() { return read_tests() },
+};
+
+function write_test(params) {
+ let fd, err;
+
+ try {
+ fd = fs.openSync.apply(null, params.args);
+
+ for (var i = 0; i < params.write.length; i++) {
+ let args = params.write[i].map(v => v);
+ args.unshift(fd);
+
+ let bytesWritten = fs.writeSync.apply(null, args);
+
+ if (params.written && bytesWritten != params.written) {
+ throw Error(`bw.bytesWritten unexpected value:${bw.bytesWritten}`);
+ }
+ }
+
+ } catch (e) {
+ if (!e.syscall && !params.check) {
+ throw e;
+ }
+
+ err = e;
+
+ } finally {
+ fs.closeSync(fd);
+ }
+
+ if (!err && params.expected) {
+ let data = fs.readFileSync(params.args[0]);
+
+ if (data.compare(params.expected) != 0) {
+ throw Error(`fh.write unexpected data:${data}`);
+ }
+ }
+
+ if (params.check && !params.check(err, params)) {
+ throw Error(`${params.method} failed check`);
+ }
+
+ return 'SUCCESS';
+}
+
+async function writeFh_test(params) {
+ let fh, err;
+
+ try {
+ fh = await fs.promises.open.apply(null, params.args);
+
+ for (var i = 0; i < params.write.length; i++) {
+ let bw = await fh.write.apply(fh, params.write[i]);
+
+ if (params.written && bw.bytesWritten != params.written) {
+ throw Error(`bw.bytesWritten unexpected value:${bw.bytesWritten}`);
+ }
+
+ if (params.buffer
+ && (typeof params.buffer == 'string'
+ && params.buffer != bw.buffer
+ || typeof params.buffer == 'object'
+ && params.buffer.compare(bw.buffer) != 0))
+ {
+ throw Error(`bw.buffer unexpected value:${bw.buffer}`);
+ }
+ }
+
+ } catch (e) {
+ if (!e.syscall && !params.check) {
+ throw e;
+ }
+
+ err = e;
+
+ } finally {
+ await fh.close();
+ }
+
+ if (!err && params.expected) {
+ let data = fs.readFileSync(params.args[0]);
+
+ if (data.compare(params.expected) != 0) {
+ throw Error(`fh.write unexpected data:${data}`);
+ }
+ }
+
+ if (params.check && !params.check(err, params)) {
+ throw Error(`${params.method} failed check`);
+ }
+
+ return 'SUCCESS';
+}
+
+let write_tests = () => [
+
+ {
+ args: ["@", 'w'],
+ write: [ ["ABC", undefined], ["DE", null], ["F"], ],
+ expected: Buffer.from("ABCDEF"),
+ },
+
+ {
+ args: ["@", 'w'],
+ write: [ ["XXXXXX"], ["YYYY", 1], ["ZZ", 2], ],
+ expected: Buffer.from("XYZZYX"),
+ },
+
+ {
+ args: ["@", 'w'],
+ write: [ ["ABC", null, 'utf8'] ],
+ written: 3,
+ buffer: 'ABC',
+ expected: Buffer.from("ABC"),
+ },
+
+ {
+ args: ["test/fs/ascii"],
+ write: [ ["ABC"] ],
+ check: (err, params) => {
+ let e = err;
+
+ if (e.syscall != 'write') {
+ throw Error(`${e.syscall} unexpected syscall`);
+ }
+
+ if (e.code != "EBADF") {
+ throw Error(`${e.code} unexpected code`);
+ }
+
+ return true;
+ },
+ },
+
+ {
+ args: ["@", 'w'],
+ write: [ [Buffer.from("ABC"), 0, 3],
+ [Buffer.from("DE"), 0, 2, null],
+ [Buffer.from("F"), 0, 1], ],
+ expected: Buffer.from("ABCDEF"),
+ },
+
+ {
+ args: ["@", 'w'],
+ write: [ [Buffer.from("__XXXXXX"), 2],
+ [Buffer.from("__YYYY__"), 2, 4, 1],
+ [Buffer.from("ZZ"), 0, 2, 2], ],
+ expected: Buffer.from("XYZZYX"),
+ },
+
+ {
+ args: ["@", 'w'],
+ write: [ [Buffer.from("__ABC__"), 2, 3] ],
+ written: 3,
+ buffer: Buffer.from('__ABC__'),
+ expected: Buffer.from("ABC"),
+ },
+
+ {
+ args: ["@", 'w'],
+ write: [ [Buffer.from("__ABC__"), 7] ],
+ written: 0,
+ },
+
+ {
+ args: ["@", 'w'],
+ write: [ [Buffer.from("__ABC__"), 8] ],
+ check: (err, params) => {
+ if (err.name != "RangeError") {
+ throw Error(`${err.code} unexpected exception`);
+ }
+
+ return true;
+ },
+ },
+
+ {
+ args: ["@", 'w'],
+ write: [ [Buffer.from("__ABC__"), 7, 1] ],
+ check: (err, params) => {
+ if (err.name != "RangeError") {
+ throw Error(`${err.code} unexpected exception`);
+ }
+
+ return true;
+ },
+ },
+];
+
+let writeSync_tsuite = {
+ name: "fs writeSync",
+ skip: () => (!has_fs() || !has_buffer()),
+ T: write_test,
+ prepare_args: p,
+ opts: {},
+ get tests() { return write_tests() },
+};
+
+let writeFh_tsuite = {
+ name: "fh write",
+ skip: () => (!has_fs() || !has_buffer()),
+ T: writeFh_test,
+ prepare_args: p,
+ opts: {},
+ get tests() { return write_tests() },
+};
+
run([
readFile_tsuite,
readFileSync_tsuite,
lstat_tsuite,
lstatSync_tsuite,
lstatP_tsuite,
+ openSync_tsuite,
+ openP_tsuite,
+ readSync_tsuite,
+ readFh_tsuite,
+ writeSync_tsuite,
+ writeFh_tsuite,
+ closeSync_tsuite,
])
.then($DONE, $DONE);