Skip to content

Commit d71a881

Browse files
committed
Introduced fs.access and friends.
1 parent 096f5aa commit d71a881

File tree

6 files changed

+268
-4
lines changed

6 files changed

+268
-4
lines changed

src/njs_fs.c

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,68 @@ njs_fs_rename_sync(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
465465
}
466466

467467

468+
static njs_int_t
469+
njs_fs_access(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
470+
njs_index_t calltype)
471+
{
472+
int md;
473+
njs_int_t ret;
474+
const char *file_path;
475+
njs_value_t retval, *path, *callback, *mode;
476+
477+
path = njs_arg(args, nargs, 1);
478+
ret = njs_fs_path_arg(vm, &file_path, path, &njs_str_value("path"));
479+
if (njs_slow_path(ret != NJS_OK)) {
480+
return ret;
481+
}
482+
483+
callback = NULL;
484+
mode = njs_arg(args, nargs, 2);
485+
486+
if (calltype == NJS_FS_CALLBACK) {
487+
callback = njs_arg(args, nargs, njs_min(nargs - 1, 3));
488+
if (!njs_is_function(callback)) {
489+
njs_type_error(vm, "\"callback\" must be a function");
490+
return NJS_ERROR;
491+
}
492+
493+
if (mode == callback) {
494+
mode = njs_value_arg(&njs_value_undefined);
495+
}
496+
}
497+
498+
switch (mode->type) {
499+
case NJS_UNDEFINED:
500+
md = F_OK;
501+
break;
502+
503+
case NJS_NUMBER:
504+
md = njs_number(mode);
505+
break;
506+
507+
default:
508+
njs_type_error(vm, "\"mode\" must be a number");
509+
return NJS_ERROR;
510+
}
511+
512+
ret = access(file_path, md);
513+
if (njs_slow_path(ret != 0)) {
514+
ret = njs_fs_error(vm, "access", strerror(errno), path, errno, &retval);
515+
goto done;
516+
}
517+
518+
njs_set_undefined(&retval);
519+
520+
done:
521+
522+
if (ret == NJS_OK) {
523+
return njs_fs_result(vm, &retval, calltype, callback, 1);
524+
}
525+
526+
return NJS_ERROR;
527+
}
528+
529+
468530
static njs_int_t
469531
njs_fs_fd_read(njs_vm_t *vm, int fd, njs_str_t *data)
470532
{
@@ -810,6 +872,14 @@ static const njs_object_prop_t njs_fs_promises_properties[] =
810872
.writable = 1,
811873
.configurable = 1,
812874
},
875+
876+
{
877+
.type = NJS_PROPERTY,
878+
.name = njs_string("access"),
879+
.value = njs_native_function2(njs_fs_access, 0, NJS_FS_PROMISE),
880+
.writable = 1,
881+
.configurable = 1,
882+
},
813883
};
814884

815885

@@ -827,6 +897,50 @@ njs_fs_promises(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value,
827897
}
828898

829899

900+
static const njs_object_prop_t njs_fs_constants_properties[] =
901+
{
902+
{
903+
.type = NJS_PROPERTY,
904+
.name = njs_string("F_OK"),
905+
.value = njs_value(NJS_NUMBER, 0, F_OK),
906+
.enumerable = 1,
907+
},
908+
{
909+
.type = NJS_PROPERTY,
910+
.name = njs_string("R_OK"),
911+
.value = njs_value(NJS_NUMBER, 1, R_OK),
912+
.enumerable = 1,
913+
},
914+
{
915+
.type = NJS_PROPERTY,
916+
.name = njs_string("W_OK"),
917+
.value = njs_value(NJS_NUMBER, 1, W_OK),
918+
.enumerable = 1,
919+
},
920+
{
921+
.type = NJS_PROPERTY,
922+
.name = njs_string("X_OK"),
923+
.value = njs_value(NJS_NUMBER, 1, X_OK),
924+
.enumerable = 1,
925+
},
926+
};
927+
928+
929+
static const njs_object_init_t njs_fs_constants_init = {
930+
njs_fs_constants_properties,
931+
njs_nitems(njs_fs_constants_properties),
932+
};
933+
934+
935+
static njs_int_t
936+
njs_fs_constants(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value,
937+
njs_value_t *unused, njs_value_t *retval)
938+
{
939+
return njs_object_prop_init(vm, &njs_fs_constants_init, prop, value,
940+
retval);
941+
}
942+
943+
830944
static const njs_object_prop_t njs_fs_object_properties[] =
831945
{
832946
{
@@ -836,12 +950,35 @@ static const njs_object_prop_t njs_fs_object_properties[] =
836950
.configurable = 1,
837951
},
838952

953+
{
954+
.type = NJS_PROPERTY_HANDLER,
955+
.name = njs_string("constants"),
956+
.value = njs_prop_handler(njs_fs_constants),
957+
.enumerable = 1,
958+
},
959+
839960
{
840961
.type = NJS_PROPERTY_HANDLER,
841962
.name = njs_string("promises"),
842963
.value = njs_prop_handler(njs_fs_promises),
843964
},
844965

966+
{
967+
.type = NJS_PROPERTY,
968+
.name = njs_string("access"),
969+
.value = njs_native_function2(njs_fs_access, 0, NJS_FS_CALLBACK),
970+
.writable = 1,
971+
.configurable = 1,
972+
},
973+
974+
{
975+
.type = NJS_PROPERTY,
976+
.name = njs_string("accessSync"),
977+
.value = njs_native_function2(njs_fs_access, 0, NJS_FS_DIRECT),
978+
.writable = 1,
979+
.configurable = 1,
980+
},
981+
845982
{
846983
.type = NJS_PROPERTY,
847984
.name = njs_string("readFile"),

src/test/njs_interactive_test.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,10 @@ static njs_interactive_test_t njs_test[] =
233233
" at main (native)\n") },
234234

235235
{ njs_str("var fs = require('fs');"
236-
"['readFile',"
236+
"["
237+
" 'access',"
238+
" 'accessSync',"
239+
" 'readFile',"
237240
" 'readFileSync',"
238241
" 'writeFile',"
239242
" 'writeFileSync',"

src/test/njs_unit_test.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15991,9 +15991,39 @@ static njs_unit_test_t njs_test[] =
1599115991
".every((x) => x === true)"),
1599215992
njs_str("true")},
1599315993

15994+
/* require('fs').access() */
15995+
15996+
{ njs_str("var fs = require('fs');"
15997+
"fs.access()"),
15998+
njs_str("TypeError: \"path\" must be a string") },
15999+
16000+
{ njs_str("var fs = require('fs');"
16001+
"fs.access('/njs_unknown_path')"),
16002+
njs_str("TypeError: \"callback\" must be a function") },
16003+
16004+
{ njs_str("var fs = require('fs');"
16005+
"fs.access('/njs_unknown_path', fs.constants.F_OK)"),
16006+
njs_str("TypeError: \"callback\" must be a function") },
16007+
16008+
{ njs_str("var fs = require('fs');"
16009+
"fs.access('/njs_unknown_path', 'fail', function () {})"),
16010+
njs_str("TypeError: \"mode\" must be a number") },
16011+
16012+
/* require('fs').accessSync() */
16013+
16014+
{ njs_str("var fs = require('fs');"
16015+
"fs.accessSync()"),
16016+
njs_str("TypeError: \"path\" must be a string") },
16017+
16018+
{ njs_str("var fs = require('fs');"
16019+
"fs.accessSync('/njs_unknown_path', 'fail')"),
16020+
njs_str("TypeError: \"mode\" must be a number") },
16021+
1599416022
{ njs_str("var "
1599516023
"fs = require('fs'),"
1599616024
"func = ["
16025+
"'access',"
16026+
"'accessSync',"
1599716027
"'readFile',"
1599816028
"'readFileSync',"
1599916029
"'writeFile',"
@@ -16018,13 +16048,31 @@ static njs_unit_test_t njs_test[] =
1601816048
{ njs_str("var "
1601916049
"fs = require('fs').promises,"
1602016050
"func = ["
16051+
"'access',"
1602116052
"'readFile',"
1602216053
"'writeFile',"
1602316054
"'appendFile',"
1602416055
"];"
1602516056
"func.every((x) => typeof fs[x] == 'function')"),
1602616057
njs_str("true")},
1602716058

16059+
/* require('fs').constants */
16060+
16061+
{ njs_str("var fs = require('fs');"
16062+
"typeof fs.constants"),
16063+
njs_str("object") },
16064+
16065+
{ njs_str("var "
16066+
"fsc = require('fs').constants,"
16067+
"items = ["
16068+
"'F_OK',"
16069+
"'R_OK',"
16070+
"'W_OK',"
16071+
"'X_OK',"
16072+
"];"
16073+
"items.every((x) => typeof fsc[x] == 'number')"),
16074+
njs_str("true")},
16075+
1602816076
/* require('crypto').createHash() */
1602916077

1603016078
{ njs_str("var h = require('crypto').createHash('sha1');"

test/js/fs_promises_001.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ Promise.resolve()
1515
return fs.readFile(fname).then(fs.readFile);
1616
})
1717
.then((data) => {
18-
console.log('short citcut ok', data == fname);
18+
console.log('short circut ok', data == fname);
1919
})
2020
.catch((e) => {
21-
console.log('short citcut failed', e);
21+
console.log('short circut failed', e);
2222
})
2323
.then(() => {
2424
var read = fs.readFile.bind(fs, fname, 'utf8');

test/js/fs_promises_002.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
var fs = require('fs');
2+
var fsp = fs.promises;
3+
var fname = '/tmp/njs_fs_promises_002';
4+
5+
var testSync = new Promise((resolve, reject) => {
6+
var failed = false;
7+
try {
8+
fs.writeFileSync(fname, fname);
9+
10+
fs.accessSync(fname);
11+
fs.accessSync(fname, fs.constants.R_OK | fs.constants.W_OK);
12+
13+
try {
14+
fs.accessSync(fname + '___');
15+
failed = true;
16+
} catch(e) {
17+
failed = (e.syscall != 'access');
18+
// TODO: e.code != 'ENOENT'
19+
}
20+
resolve(failed);
21+
} catch (e) {
22+
reject(e);
23+
}
24+
});
25+
26+
var testCallback = new Promise((resolve, reject) => {
27+
var failed = false;
28+
29+
fs.writeFileSync(fname, fname);
30+
31+
fs.access(fname, (err) => {
32+
failed = (err !== undefined);
33+
fs.access(fname, fs.constants.R_OK | fs.constants.W_OK, (err) => {
34+
failed |= (err !== undefined);
35+
fs.access(fname + '___', (err) => {
36+
failed |= ((err === undefined) || (err.syscall != 'access'));
37+
resolve(failed);
38+
});
39+
});
40+
});
41+
});
42+
43+
Promise.resolve()
44+
.then(() => testSync)
45+
.then((failed) => {
46+
console.log('testSync ok', !failed);
47+
})
48+
.catch((e) => {
49+
console.log('testSync failed', e);
50+
})
51+
.then(() => testCallback)
52+
.then((failed) => {
53+
console.log('testCallback ok', !failed);
54+
})
55+
.catch((e) => {
56+
console.log('testCallback failed', e);
57+
})
58+
.then(() => {
59+
fs.writeFileSync(fname, fname);
60+
61+
return fsp.access(fname)
62+
.then(() => fsp.access(fname, fs.constants.R_OK | fs.constants.W_OK))
63+
.then(() => fsp.access(fname + '___'));
64+
})
65+
.then(() => {
66+
console.log('testPromise failed');
67+
})
68+
.catch((e) => {
69+
console.log('testPromise ok', (e.syscall == 'access') && (e.path == fname + '___'));
70+
})
71+
;

test/njs_expect_test.exp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1064,9 +1064,14 @@ PatchedPromise async done"
10641064

10651065
njs_run {"./test/js/fs_promises_001.js"} \
10661066
"init ok true
1067-
short citcut ok true
1067+
short circut ok true
10681068
chain ok true
10691069
error 1 ok true
10701070
error 2 ok true
10711071
error 3 ok true
10721072
errors ok"
1073+
1074+
njs_run {"./test/js/fs_promises_002.js"} \
1075+
"testSync ok true
1076+
testCallback ok true
1077+
testPromise ok true"

0 commit comments

Comments
 (0)