[njs] Introduced fs.access and friends.

Dmitry Volyntsev xeioex at nginx.com
Fri Feb 7 14:35:06 UTC 2020


details:   https://hg.nginx.org/njs/rev/1f3e045ea017
branches:  
changeset: 1322:1f3e045ea017
user:      Artem S. Povalyukhin <artem.povaluhin at gmail.com>
date:      Sun Jan 26 21:56:23 2020 +0300
description:
Introduced fs.access and friends.

diffstat:

 src/njs_fs.c                    |  137 ++++++++++++++++++++++++++++++++++++++++
 src/test/njs_interactive_test.c |    5 +-
 src/test/njs_unit_test.c        |   48 ++++++++++++++
 test/js/fs_promises_001.js      |    4 +-
 test/js/fs_promises_002.js      |   71 ++++++++++++++++++++
 test/njs_expect_test.exp        |    7 +-
 6 files changed, 268 insertions(+), 4 deletions(-)

diffs (374 lines):

diff -r 03ec7b441da8 -r 1f3e045ea017 src/njs_fs.c
--- a/src/njs_fs.c	Sat Jan 25 21:55:50 2020 +0300
+++ b/src/njs_fs.c	Sun Jan 26 21:56:23 2020 +0300
@@ -466,6 +466,68 @@ njs_fs_rename_sync(njs_vm_t *vm, njs_val
 
 
 static njs_int_t
+njs_fs_access(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t calltype)
+{
+    int          md;
+    njs_int_t    ret;
+    const char  *file_path;
+    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"));
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    callback = NULL;
+    mode = njs_arg(args, nargs, 2);
+
+    if (calltype == NJS_FS_CALLBACK) {
+        callback = njs_arg(args, nargs, njs_min(nargs - 1, 3));
+        if (!njs_is_function(callback)) {
+            njs_type_error(vm, "\"callback\" must be a function");
+            return NJS_ERROR;
+        }
+
+        if (mode == callback) {
+            mode = njs_value_arg(&njs_value_undefined);
+        }
+    }
+
+    switch (mode->type) {
+    case NJS_UNDEFINED:
+        md = F_OK;
+        break;
+
+    case NJS_NUMBER:
+        md = njs_number(mode);
+        break;
+
+    default:
+        njs_type_error(vm, "\"mode\" must be a number");
+        return NJS_ERROR;
+    }
+
+    ret = access(file_path, md);
+    if (njs_slow_path(ret != 0)) {
+        ret = njs_fs_error(vm, "access", strerror(errno), path, errno, &retval);
+        goto done;
+    }
+
+    njs_set_undefined(&retval);
+
+done:
+
+    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)
 {
     u_char   *p, *end, *start;
@@ -810,6 +872,14 @@ static const njs_object_prop_t  njs_fs_p
         .writable = 1,
         .configurable = 1,
     },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("access"),
+        .value = njs_native_function2(njs_fs_access, 0, NJS_FS_PROMISE),
+        .writable = 1,
+        .configurable = 1,
+    },
 };
 
 
@@ -827,6 +897,50 @@ njs_fs_promises(njs_vm_t *vm, njs_object
 }
 
 
+static const njs_object_prop_t  njs_fs_constants_properties[] =
+{
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("F_OK"),
+        .value = njs_value(NJS_NUMBER, 0, F_OK),
+        .enumerable = 1,
+    },
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("R_OK"),
+        .value = njs_value(NJS_NUMBER, 1, R_OK),
+        .enumerable = 1,
+    },
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("W_OK"),
+        .value = njs_value(NJS_NUMBER, 1, W_OK),
+        .enumerable = 1,
+    },
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("X_OK"),
+        .value = njs_value(NJS_NUMBER, 1, X_OK),
+        .enumerable = 1,
+    },
+};
+
+
+static const njs_object_init_t  njs_fs_constants_init = {
+    njs_fs_constants_properties,
+    njs_nitems(njs_fs_constants_properties),
+};
+
+
+static njs_int_t
+njs_fs_constants(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value,
+    njs_value_t *unused, njs_value_t *retval)
+{
+    return njs_object_prop_init(vm, &njs_fs_constants_init, prop, value,
+                                retval);
+}
+
+
 static const njs_object_prop_t  njs_fs_object_properties[] =
 {
     {
@@ -838,12 +952,35 @@ static const njs_object_prop_t  njs_fs_o
 
     {
         .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("constants"),
+        .value = njs_prop_handler(njs_fs_constants),
+        .enumerable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
         .name = njs_string("promises"),
         .value = njs_prop_handler(njs_fs_promises),
     },
 
     {
         .type = NJS_PROPERTY,
+        .name = njs_string("access"),
+        .value = njs_native_function2(njs_fs_access, 0, NJS_FS_CALLBACK),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("accessSync"),
+        .value = njs_native_function2(njs_fs_access, 0, NJS_FS_DIRECT),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
         .name = njs_string("readFile"),
         .value = njs_native_function2(njs_fs_read_file, 0, NJS_FS_CALLBACK),
         .writable = 1,
diff -r 03ec7b441da8 -r 1f3e045ea017 src/test/njs_interactive_test.c
--- a/src/test/njs_interactive_test.c	Sat Jan 25 21:55:50 2020 +0300
+++ b/src/test/njs_interactive_test.c	Sun Jan 26 21:56:23 2020 +0300
@@ -233,7 +233,10 @@ static njs_interactive_test_t  njs_test[
                  "    at main (native)\n") },
 
     { njs_str("var fs = require('fs');"
-              "['readFile',"
+              "["
+              " 'access',"
+              " 'accessSync',"
+              " 'readFile',"
               " 'readFileSync',"
               " 'writeFile',"
               " 'writeFileSync',"
diff -r 03ec7b441da8 -r 1f3e045ea017 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Sat Jan 25 21:55:50 2020 +0300
+++ b/src/test/njs_unit_test.c	Sun Jan 26 21:56:23 2020 +0300
@@ -15991,9 +15991,39 @@ static njs_unit_test_t  njs_test[] =
               ".every((x) => x === true)"),
       njs_str("true")},
 
+    /* require('fs').access() */
+
+    { njs_str("var fs = require('fs');"
+              "fs.access()"),
+      njs_str("TypeError: \"path\" must be a string") },
+
+    { njs_str("var fs = require('fs');"
+              "fs.access('/njs_unknown_path')"),
+      njs_str("TypeError: \"callback\" must be a function") },
+
+    { njs_str("var fs = require('fs');"
+              "fs.access('/njs_unknown_path', fs.constants.F_OK)"),
+      njs_str("TypeError: \"callback\" must be a function") },
+
+    { njs_str("var fs = require('fs');"
+              "fs.access('/njs_unknown_path', 'fail', function () {})"),
+      njs_str("TypeError: \"mode\" must be a number") },
+
+    /* require('fs').accessSync() */
+
+    { njs_str("var fs = require('fs');"
+              "fs.accessSync()"),
+      njs_str("TypeError: \"path\" must be a string") },
+
+    { njs_str("var fs = require('fs');"
+              "fs.accessSync('/njs_unknown_path', 'fail')"),
+      njs_str("TypeError: \"mode\" must be a number") },
+
     { njs_str("var "
               "fs = require('fs'),"
               "func = ["
+                "'access',"
+                "'accessSync',"
                 "'readFile',"
                 "'readFileSync',"
                 "'writeFile',"
@@ -16018,6 +16048,7 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("var "
               "fs = require('fs').promises,"
               "func = ["
+                "'access',"
                 "'readFile',"
                 "'writeFile',"
                 "'appendFile',"
@@ -16025,6 +16056,23 @@ static njs_unit_test_t  njs_test[] =
               "func.every((x) => typeof fs[x] == 'function')"),
       njs_str("true")},
 
+    /* require('fs').constants */
+
+    { njs_str("var fs = require('fs');"
+              "typeof fs.constants"),
+      njs_str("object") },
+
+    { njs_str("var "
+              "fsc = require('fs').constants,"
+              "items = ["
+                "'F_OK',"
+                "'R_OK',"
+                "'W_OK',"
+                "'X_OK',"
+              "];"
+              "items.every((x) => typeof fsc[x] == 'number')"),
+      njs_str("true")},
+
     /* require('crypto').createHash() */
 
     { njs_str("var h = require('crypto').createHash('sha1');"
diff -r 03ec7b441da8 -r 1f3e045ea017 test/js/fs_promises_001.js
--- a/test/js/fs_promises_001.js	Sat Jan 25 21:55:50 2020 +0300
+++ b/test/js/fs_promises_001.js	Sun Jan 26 21:56:23 2020 +0300
@@ -15,10 +15,10 @@ Promise.resolve()
     return fs.readFile(fname).then(fs.readFile);
 })
 .then((data) => {
-    console.log('short citcut ok', data == fname);
+    console.log('short circut ok', data == fname);
 })
 .catch((e) => {
-    console.log('short citcut failed', e);
+    console.log('short circut failed', e);
 })
 .then(() => {
     var read = fs.readFile.bind(fs, fname, 'utf8');
diff -r 03ec7b441da8 -r 1f3e045ea017 test/js/fs_promises_002.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/js/fs_promises_002.js	Sun Jan 26 21:56:23 2020 +0300
@@ -0,0 +1,71 @@
+var fs = require('fs');
+var fsp  = fs.promises;
+var fname = '/tmp/njs_fs_promises_002';
+
+var testSync = new Promise((resolve, reject) => {
+    var failed = false;
+    try {
+        fs.writeFileSync(fname, fname);
+
+        fs.accessSync(fname);
+        fs.accessSync(fname, fs.constants.R_OK | fs.constants.W_OK);
+
+        try {
+            fs.accessSync(fname + '___');
+            failed = true;
+        } catch(e) {
+            failed = (e.syscall != 'access');
+            // TODO: e.code != 'ENOENT'
+        }
+        resolve(failed);
+    } catch (e) {
+        reject(e);
+    }
+});
+
+var testCallback = new Promise((resolve, reject) => {
+    var failed = false;
+
+    fs.writeFileSync(fname, fname);
+
+    fs.access(fname, (err) => {
+        failed = (err !== undefined);
+        fs.access(fname, fs.constants.R_OK | fs.constants.W_OK, (err) => {
+            failed |= (err !== undefined);
+            fs.access(fname + '___', (err) => {
+                failed |= ((err === undefined) || (err.syscall != 'access'));
+                resolve(failed);
+            });
+        });
+    });
+});
+
+Promise.resolve()
+.then(() => testSync)
+.then((failed) => {
+    console.log('testSync ok', !failed);
+})
+.catch((e) => {
+    console.log('testSync failed', e);
+})
+.then(() => testCallback)
+.then((failed) => {
+    console.log('testCallback ok', !failed);
+})
+.catch((e) => {
+    console.log('testCallback failed', e);
+})
+.then(() => {
+    fs.writeFileSync(fname, fname);
+
+    return fsp.access(fname)
+        .then(() => fsp.access(fname, fs.constants.R_OK | fs.constants.W_OK))
+        .then(() => fsp.access(fname + '___'));
+})
+.then(() => {
+    console.log('testPromise failed');
+})
+.catch((e) => {
+    console.log('testPromise ok', (e.syscall == 'access') && (e.path == fname + '___'));
+})
+;
diff -r 03ec7b441da8 -r 1f3e045ea017 test/njs_expect_test.exp
--- a/test/njs_expect_test.exp	Sat Jan 25 21:55:50 2020 +0300
+++ b/test/njs_expect_test.exp	Sun Jan 26 21:56:23 2020 +0300
@@ -1064,9 +1064,14 @@ PatchedPromise async done"
 
 njs_run {"./test/js/fs_promises_001.js"} \
 "init ok true
-short citcut ok true
+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"} \
+"testSync ok true
+testCallback ok true
+testPromise ok true"


More information about the nginx-devel mailing list