]> git.kaiwu.me - njs.git/commitdiff
Added fs.mkdir(), fs.rmdir() and friends.
authorArtem S. Povalyukhin <artem.povaluhin@gmail.com>
Tue, 12 May 2020 09:31:19 +0000 (12:31 +0300)
committerArtem S. Povalyukhin <artem.povaluhin@gmail.com>
Tue, 12 May 2020 09:31:19 +0000 (12:31 +0300)
src/njs_fs.c
test/js/fs_promises_005.js [new file with mode: 0644]
test/njs_expect_test.exp

index 9d3b9cb75ff3eee8632a72376f356a3b13edb7c4..7e0cbcaf7bc1a70cdccfd59de81152e8a95a6444 100644 (file)
@@ -728,6 +728,168 @@ done:
 }
 
 
+static njs_int_t
+njs_fs_mkdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t calltype)
+{
+    mode_t       md;
+    njs_int_t    ret;
+    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"));
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    callback = NULL;
+    options = njs_arg(args, nargs, 2);
+
+    if (njs_slow_path(calltype == NJS_FS_CALLBACK)) {
+        callback = njs_arg(args, nargs, njs_min(nargs - 1, 3));
+        if (!njs_is_function(callback)) {
+            njs_type_error(vm, "\"callback\" must be a function");
+            return NJS_ERROR;
+        }
+        if (options == callback) {
+            options = njs_value_arg(&njs_value_undefined);
+        }
+    }
+
+    njs_set_undefined(&mode);
+    njs_set_false(&recursive);
+
+    switch (options->type) {
+    case NJS_NUMBER:
+        mode = *options;
+        break;
+
+    case NJS_UNDEFINED:
+        break;
+
+    default:
+        if (!njs_is_object(options)) {
+            njs_type_error(vm, "Unknown options type: \"%s\" "
+                           "(a number or object required)",
+                           njs_type_string(options->type));
+            return NJS_ERROR;
+        }
+
+        ret = njs_value_property(vm, options, njs_value_arg(&string_mode),
+                                 &mode);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            return ret;
+        }
+
+        ret = njs_value_property(vm, options, njs_value_arg(&string_recursive),
+                                 &recursive);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            return ret;
+        }
+    }
+
+    md = njs_fs_mode(vm, &mode, 0777);
+    if (njs_slow_path(md == (mode_t) -1)) {
+        return NJS_ERROR;
+    }
+
+    if (njs_is_true(&recursive)) {
+        njs_type_error(vm, "\"options.recursive\" is not supported");
+        return NJS_ERROR;
+    }
+
+    njs_set_undefined(&retval);
+
+    ret = mkdir(file_path, md);
+    if (njs_slow_path(ret != 0)) {
+        ret = njs_fs_error(vm, "mkdir", strerror(errno), path, errno,
+                           &retval);
+    }
+
+    if (ret == NJS_OK) {
+        return njs_fs_result(vm, &retval, calltype, callback, 1);
+    }
+
+    return NJS_ERROR;
+}
+
+
+static njs_int_t
+njs_fs_rmdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t calltype)
+{
+    njs_int_t    ret;
+    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"));
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    callback = NULL;
+    options = njs_arg(args, nargs, 2);
+
+    if (njs_slow_path(calltype == NJS_FS_CALLBACK)) {
+        callback = njs_arg(args, nargs, njs_min(nargs - 1, 3));
+        if (!njs_is_function(callback)) {
+            njs_type_error(vm, "\"callback\" must be a function");
+            return NJS_ERROR;
+        }
+        if (options == callback) {
+            options = njs_value_arg(&njs_value_undefined);
+        }
+    }
+
+    njs_set_false(&recursive);
+
+    switch (options->type) {
+    case NJS_UNDEFINED:
+        break;
+
+    default:
+        if (!njs_is_object(options)) {
+            njs_type_error(vm, "Unknown options type: \"%s\" "
+                           "(an object required)",
+                           njs_type_string(options->type));
+            return NJS_ERROR;
+        }
+
+        ret = njs_value_property(vm, options, njs_value_arg(&string_recursive),
+                                 &recursive);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            return ret;
+        }
+    }
+
+    if (njs_is_true(&recursive)) {
+        njs_type_error(vm, "\"options.recursive\" is not supported");
+        return NJS_ERROR;
+    }
+
+    njs_set_undefined(&retval);
+
+    ret = rmdir(file_path);
+    if (njs_slow_path(ret != 0)) {
+        ret = njs_fs_error(vm, "rmdir", strerror(errno), path, errno,
+                           &retval);
+    }
+
+    if (ret == NJS_OK) {
+        return njs_fs_result(vm, &retval, calltype, callback, 1);
+    }
+
+    return NJS_ERROR;
+}
+
+
 static njs_int_t
 njs_fs_fd_read(njs_vm_t *vm, int fd, njs_str_t *data)
 {
@@ -1101,6 +1263,22 @@ static const njs_object_prop_t  njs_fs_promises_properties[] =
         .configurable = 1,
     },
 
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("mkdir"),
+        .value = njs_native_function2(njs_fs_mkdir, 0, NJS_FS_PROMISE),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("rmdir"),
+        .value = njs_native_function2(njs_fs_rmdir, 0, NJS_FS_PROMISE),
+        .writable = 1,
+        .configurable = 1,
+    },
+
     {
         .type = NJS_PROPERTY,
         .name = njs_string("symlink"),
@@ -1330,6 +1508,38 @@ static const njs_object_prop_t  njs_fs_object_properties[] =
         .writable = 1,
         .configurable = 1,
     },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("mkdir"),
+        .value = njs_native_function2(njs_fs_mkdir, 0, NJS_FS_CALLBACK),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("mkdirSync"),
+        .value = njs_native_function2(njs_fs_mkdir, 0, NJS_FS_DIRECT),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("rmdir"),
+        .value = njs_native_function2(njs_fs_rmdir, 0, NJS_FS_CALLBACK),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("rmdirSync"),
+        .value = njs_native_function2(njs_fs_rmdir, 0, NJS_FS_DIRECT),
+        .writable = 1,
+        .configurable = 1,
+    },
 };
 
 
diff --git a/test/js/fs_promises_005.js b/test/js/fs_promises_005.js
new file mode 100644 (file)
index 0000000..544e204
--- /dev/null
@@ -0,0 +1,143 @@
+var fs = require('fs');
+var fsp  = fs.promises;
+var rname = './build/test/';
+var dname = rname + 'fs_promises_005';
+var dname_utf8 = rname + 'fs_promises_αβγ_005';
+var fname = (d) => d + '/fs_promises_005_file';
+
+
+var testSync = () => new Promise((resolve, reject) => {
+    try {
+        try { fs.unlinkSync(fname(dname)); } catch (e) {}
+        try { fs.unlinkSync(fname(dname_utf8)); } catch (e) {}
+        try { fs.rmdirSync(dname); } catch (e) {}
+        try { fs.rmdirSync(dname_utf8); } catch (e) {}
+
+        fs.mkdirSync(dname);
+
+        try {
+            fs.mkdirSync(dname);
+
+        } catch (e) {
+            if (e.syscall != 'mkdir' || e.code != 'EEXIST') {
+                throw e;
+            }
+        }
+
+        fs.writeFileSync(fname(dname), fname(dname));
+
+        try {
+            fs.rmdirSync(dname);
+
+        } catch (e) {
+            if (e.syscall != 'rmdir'
+                || (e.code != 'ENOTEMPTY' && e.code != 'EEXIST'))
+            {
+                throw e;
+            }
+        }
+
+        fs.unlinkSync(fname(dname));
+
+        fs.rmdirSync(dname);
+
+        fs.mkdirSync(dname_utf8, 0o555);
+
+        try {
+            fs.writeFileSync(fname(dname_utf8), fname(dname_utf8));
+
+        } catch (e) {
+            if (e.syscall != 'open' || e.code != 'EACCES') {
+                throw e;
+            }
+        }
+
+        try {
+            fs.unlinkSync(dname_utf8);
+
+        } catch (e) {
+            if (e.syscall != 'unlink' || (e.code != 'EISDIR' && e.code != 'EPERM')) {
+                throw e;
+            }
+        }
+
+        fs.rmdirSync(dname_utf8);
+
+        resolve();
+
+    } catch (e) {
+        reject(e);
+    }
+});
+
+
+var testCallback = () => new Promise((resolve, reject) => {
+    try {
+        try { fs.unlinkSync(fname(dname)); } catch (e) {}
+        try { fs.unlinkSync(fname(dname_utf8)); } catch (e) {}
+        try { fs.rmdirSync(dname); } catch (e) {}
+        try { fs.rmdirSync(dname_utf8); } catch (e) {}
+
+        fs.mkdir(dname, (err) => {
+            if (err) {
+                reject(err);
+            }
+
+            fs.mkdir(dname, (err) => {
+                if (!err || err.code != 'EEXIST') {
+                    reject(new Error('fs.mkdir error 1'));
+                }
+
+                fs.rmdir(dname, (err) => {
+                    if (err) {
+                        reject(err);
+                    }
+
+                    resolve();
+                });
+            });
+        });
+
+    } catch (e) {
+        reject(e);
+    }
+});
+
+
+Promise.resolve()
+.then(testSync)
+.then(() => {
+    console.log('test fs.mkdirSync');
+})
+.catch((e) => {
+    console.log('test fs.mkdirSync failed', JSON.stringify(e));
+})
+
+.then(testCallback)
+.then(() => {
+    console.log('test fs.mkdir');
+})
+.catch((e) => {
+    console.log('test fs.mkdir failed', JSON.stringify(e));
+})
+
+.then(() => {
+    try { fs.unlinkSync(fname(dname)); } catch (e) {}
+    try { fs.unlinkSync(fname(dname_utf8)); } catch (e) {}
+    try { fs.rmdirSync(dname); } catch (e) {}
+    try { fs.rmdirSync(dname_utf8); } catch (e) {}
+})
+.then(() => fsp.mkdir(dname))
+.then(() => fsp.mkdir(dname))
+.catch((e) => {
+    if (e.syscall != 'mkdir' || e.code != 'EEXIST') {
+        throw e;
+    }
+})
+.then(() => fsp.rmdir(dname))
+.then(() => {
+    console.log('test fsp.mkdir');
+})
+.catch((e) => {
+    console.log('test fsp.mkdir failed', JSON.stringify(e));
+});
index 6abc00adf5dae6c73ec587fd1837d9f4ea5d09f1..73614b454356c719cad5b780340577abd7be455c 100644 (file)
@@ -1130,3 +1130,8 @@ njs_run {"./test/js/fs_promises_004.js"} \
 "test fs.symlinkSync
 test fs.symlink
 test fsp.symlink"
+
+njs_run {"./test/js/fs_promises_005.js"} \
+"test fs.mkdirSync
+test fs.mkdir
+test fsp.mkdir"