MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add fs module access and readdir support

+208 -42
+1
include/modules/fs.h
··· 6 6 jsval_t fs_library(struct js *js); 7 7 int has_pending_fs_ops(void); 8 8 9 + void init_fs_module(void); 9 10 void fs_poll_events(void); 10 11 void fs_gc_update_roots(GC_FWD_ARGS); 11 12
+1
src/main.c
··· 217 217 init_symbol_module(); 218 218 init_builtin_module(); 219 219 init_buffer_module(); 220 + init_fs_module(); 220 221 init_atomics_module(); 221 222 init_crypto_module(); 222 223 init_fetch_module();
+194 -42
src/modules/fs.c
··· 10 10 #include <utarray.h> 11 11 #include <errno.h> 12 12 13 - #include "modules/fs.h" 14 - #include "modules/symbol.h" 15 13 #include "ant.h" 14 + #include "internal.h" 16 15 #include "runtime.h" 16 + 17 + #include "modules/fs.h" 18 + #include "modules/symbol.h" 17 19 18 20 typedef enum { 19 21 FS_OP_READ, ··· 24 26 FS_OP_STAT, 25 27 FS_OP_READ_BYTES, 26 28 FS_OP_EXISTS, 27 - FS_OP_READDIR 29 + FS_OP_READDIR, 30 + FS_OP_ACCESS 28 31 } fs_op_type_t; 29 32 30 33 typedef struct fs_request_s { ··· 65 68 if (*p == req) { 66 69 utarray_erase(pending_requests, i, 1); 67 70 break; 68 - } 69 - i++; 71 + } i++; 70 72 } 71 73 } 72 74 ··· 81 83 result = js_mkstr(req->js, req->data, req->data_len); 82 84 } else if (req->op_type == FS_OP_STAT) { 83 85 result = js_mkundef(); 84 - } else { 85 - result = js_mkundef(); 86 - } 86 + } else result = js_mkundef(); 87 87 js_resolve_promise(req->js, req->promise, result); 88 88 } 89 89 ··· 267 267 } 268 268 269 269 jsval_t stat_obj = js_mkobj(req->js); 270 - js_set(req->js, stat_obj, "size", js_mknum((double)uv_req->statbuf.st_size)); 271 - js_set(req->js, stat_obj, "mode", js_mknum((double)uv_req->statbuf.st_mode)); 272 - js_set(req->js, stat_obj, "isFile", S_ISREG(uv_req->statbuf.st_mode) ? js_mktrue() : js_mkfalse()); 273 - js_set(req->js, stat_obj, "isDirectory", S_ISDIR(uv_req->statbuf.st_mode) ? js_mktrue() : js_mkfalse()); 270 + jsval_t proto = js_get_ctor_proto(req->js, "Stats", 5); 271 + if (js_type(proto) == JS_OBJ) js_set_proto(req->js, stat_obj, proto); 272 + 273 + uv_stat_t *st = &uv_req->statbuf; 274 + js_set_slot(req->js, stat_obj, SLOT_DATA, js_mknum((double)st->st_mode)); 275 + js_set(req->js, stat_obj, "size", js_mknum((double)st->st_size)); 276 + js_set(req->js, stat_obj, "mode", js_mknum((double)st->st_mode)); 277 + js_set(req->js, stat_obj, "uid", js_mknum((double)st->st_uid)); 278 + js_set(req->js, stat_obj, "gid", js_mknum((double)st->st_gid)); 274 279 275 280 req->completed = 1; 276 281 js_resolve_promise(req->js, req->promise, stat_obj); ··· 288 293 free_fs_request(req); 289 294 } 290 295 296 + static void on_access_complete(uv_fs_t *uv_req) { 297 + fs_request_t *req = (fs_request_t *)uv_req->data; 298 + 299 + if (uv_req->result < 0) { 300 + req->failed = 1; 301 + req->error_msg = strdup(uv_strerror(uv_req->result)); 302 + req->completed = 1; 303 + complete_request(req); 304 + return; 305 + } 306 + 307 + req->completed = 1; 308 + js_resolve_promise(req->js, req->promise, js_mkundef()); 309 + remove_pending_request(req); 310 + free_fs_request(req); 311 + } 312 + 291 313 static void on_readdir_complete(uv_fs_t *uv_req) { 292 314 fs_request_t *req = (fs_request_t *)uv_req->data; 293 315 ··· 454 476 req->uv_req.data = req; 455 477 456 478 utarray_push_back(pending_requests, &req); 457 - 458 479 int result = uv_fs_open(fs_loop, &req->uv_req, req->path, O_RDONLY, 0, on_open_for_read); 459 480 460 481 if (result < 0) { ··· 488 509 req->uv_req.data = req; 489 510 490 511 utarray_push_back(pending_requests, &req); 491 - 492 512 int result = uv_fs_open(fs_loop, &req->uv_req, req->path, O_RDONLY, 0, on_open_for_read); 493 513 494 514 if (result < 0) { ··· 694 714 req->uv_req.data = req; 695 715 696 716 utarray_push_back(pending_requests, &req); 697 - 698 - int result = uv_fs_open(fs_loop, &req->uv_req, req->path, 699 - O_WRONLY | O_CREAT | O_TRUNC, 0644, on_open_for_write); 717 + int result = uv_fs_open(fs_loop, &req->uv_req, req->path, O_WRONLY | O_CREAT | O_TRUNC, 0644, on_open_for_write); 700 718 701 719 if (result < 0) { 702 720 req->failed = 1; ··· 753 771 req->uv_req.data = req; 754 772 755 773 utarray_push_back(pending_requests, &req); 756 - 757 774 int result = uv_fs_unlink(fs_loop, &req->uv_req, req->path, on_unlink_complete); 758 775 759 776 if (result < 0) { ··· 843 860 req->uv_req.data = req; 844 861 845 862 utarray_push_back(pending_requests, &req); 846 - 847 863 int result = uv_fs_mkdir(fs_loop, &req->uv_req, req->path, mode, on_mkdir_complete); 848 864 849 865 if (result < 0) { ··· 905 921 req->uv_req.data = req; 906 922 907 923 utarray_push_back(pending_requests, &req); 908 - 909 924 int result = uv_fs_rmdir(fs_loop, &req->uv_req, req->path, on_rmdir_complete); 910 925 911 926 if (result < 0) { ··· 920 935 921 936 static jsval_t stat_isFile(struct js *js, jsval_t *args, int nargs) { 922 937 jsval_t this = js_getthis(js); 923 - jsval_t val = js_get(js, this, "_isFile"); 924 - return js_type(val) == JS_TRUE ? js_mktrue() : js_mkfalse(); 938 + jsval_t mode_val = js_get_slot(js, this, SLOT_DATA); 939 + 940 + if (js_type(mode_val) != JS_NUM) return js_mkfalse(); 941 + mode_t mode = (mode_t)js_getnum(mode_val); 942 + 943 + return S_ISREG(mode) ? js_mktrue() : js_mkfalse(); 925 944 } 926 945 927 946 static jsval_t stat_isDirectory(struct js *js, jsval_t *args, int nargs) { 928 947 jsval_t this = js_getthis(js); 929 - jsval_t val = js_get(js, this, "_isDirectory"); 930 - return js_type(val) == JS_TRUE ? js_mktrue() : js_mkfalse(); 948 + jsval_t mode_val = js_get_slot(js, this, SLOT_DATA); 949 + 950 + if (js_type(mode_val) != JS_NUM) return js_mkfalse(); 951 + mode_t mode = (mode_t)js_getnum(mode_val); 952 + 953 + return S_ISDIR(mode) ? js_mktrue() : js_mkfalse(); 954 + } 955 + 956 + static jsval_t stat_isSymbolicLink(struct js *js, jsval_t *args, int nargs) { 957 + jsval_t this = js_getthis(js); 958 + jsval_t mode_val = js_get_slot(js, this, SLOT_DATA); 959 + 960 + if (js_type(mode_val) != JS_NUM) return js_mkfalse(); 961 + mode_t mode = (mode_t)js_getnum(mode_val); 962 + 963 + return S_ISLNK(mode) ? js_mktrue() : js_mkfalse(); 964 + } 965 + 966 + static jsval_t create_stats_object(struct js *js, struct stat *st) { 967 + jsval_t stat_obj = js_mkobj(js); 968 + jsval_t proto = js_get_ctor_proto(js, "Stats", 5); 969 + if (js_type(proto) == JS_OBJ) js_set_proto(js, stat_obj, proto); 970 + 971 + js_set_slot(js, stat_obj, SLOT_DATA, js_mknum((double)st->st_mode)); 972 + js_set(js, stat_obj, "size", js_mknum((double)st->st_size)); 973 + js_set(js, stat_obj, "mode", js_mknum((double)st->st_mode)); 974 + js_set(js, stat_obj, "uid", js_mknum((double)st->st_uid)); 975 + js_set(js, stat_obj, "gid", js_mknum((double)st->st_gid)); 976 + 977 + return stat_obj; 978 + } 979 + 980 + static const char *errno_to_code(int err_num) { 981 + switch (err_num) { 982 + case ENOENT: return "ENOENT"; 983 + case EACCES: return "EACCES"; 984 + case ENOTDIR: return "ENOTDIR"; 985 + case ELOOP: return "ELOOP"; 986 + case ENAMETOOLONG: return "ENAMETOOLONG"; 987 + case EOVERFLOW: return "EOVERFLOW"; 988 + case EROFS: return "EROFS"; 989 + case ETXTBSY: return "ETXTBSY"; 990 + case EEXIST: return "EEXIST"; 991 + case ENOTEMPTY: return "ENOTEMPTY"; 992 + case EISDIR: return "EISDIR"; 993 + case EBUSY: return "EBUSY"; 994 + case EINVAL: return "EINVAL"; 995 + case EPERM: return "EPERM"; 996 + case EIO: return "EIO"; 997 + default: return "UNKNOWN"; 998 + } 931 999 } 932 1000 933 1001 static jsval_t builtin_fs_statSync(struct js *js, jsval_t *args, int nargs) { ··· 947 1015 free(path_cstr); 948 1016 949 1017 if (result != 0) { 950 - char err_msg[256]; 951 - snprintf(err_msg, sizeof(err_msg), "Failed to stat file: %s", strerror(errno)); 952 - return js_mkerr(js, err_msg); 1018 + const char *code = errno_to_code(errno); 1019 + jsval_t err = js_mkerr(js, "Failed to stat file: %s", strerror(errno)); 1020 + js_set(js, js->thrown_value, "code", js_mkstr(js, code, strlen(code))); 1021 + return err; 953 1022 } 954 1023 955 - jsval_t stat_obj = js_mkobj(js); 956 - js_set(js, stat_obj, "size", js_mknum((double)st.st_size)); 957 - js_set(js, stat_obj, "mode", js_mknum((double)st.st_mode)); 958 - js_set(js, stat_obj, "_isFile", S_ISREG(st.st_mode) ? js_mktrue() : js_mkfalse()); 959 - js_set(js, stat_obj, "_isDirectory", S_ISDIR(st.st_mode) ? js_mktrue() : js_mkfalse()); 960 - js_set(js, stat_obj, "isFile", js_mkfun(stat_isFile)); 961 - js_set(js, stat_obj, "isDirectory", js_mkfun(stat_isDirectory)); 962 - 963 - return stat_obj; 1024 + return create_stats_object(js, &st); 964 1025 } 965 1026 966 1027 static jsval_t builtin_fs_stat(struct js *js, jsval_t *args, int nargs) { ··· 984 1045 req->uv_req.data = req; 985 1046 986 1047 utarray_push_back(pending_requests, &req); 987 - 988 1048 int result = uv_fs_stat(fs_loop, &req->uv_req, req->path, on_stat_complete); 989 1049 990 1050 if (result < 0) { ··· 1037 1097 req->uv_req.data = req; 1038 1098 1039 1099 utarray_push_back(pending_requests, &req); 1040 - 1041 1100 int result = uv_fs_stat(fs_loop, &req->uv_req, req->path, on_exists_complete); 1042 1101 1043 1102 if (result < 0) { ··· 1050 1109 return req->promise; 1051 1110 } 1052 1111 1112 + static jsval_t builtin_fs_accessSync(struct js *js, jsval_t *args, int nargs) { 1113 + if (nargs < 1) return js_mkerr(js, "accessSync() requires a path argument"); 1114 + 1115 + if (js_type(args[0]) != JS_STR) return js_mkerr(js, "accessSync() path must be a string"); 1116 + 1117 + size_t path_len; 1118 + char *path = js_getstr(js, args[0], &path_len); 1119 + if (!path) return js_mkerr(js, "Failed to get path string"); 1120 + 1121 + int mode = F_OK; 1122 + if (nargs >= 2 && js_type(args[1]) == JS_NUM) { 1123 + mode = (int)js_getnum(args[1]); 1124 + } 1125 + 1126 + char *path_cstr = strndup(path, path_len); 1127 + if (!path_cstr) return js_mkerr(js, "Out of memory"); 1128 + 1129 + int result = access(path_cstr, mode); 1130 + free(path_cstr); 1131 + 1132 + if (result != 0) { 1133 + const char *code = errno_to_code(errno); 1134 + jsval_t err = js_mkerr(js, "Access denied: %s", strerror(errno)); 1135 + js_set(js, js->thrown_value, "code", js_mkstr(js, code, strlen(code))); 1136 + return err; 1137 + } 1138 + 1139 + return js_mkundef(); 1140 + } 1141 + 1142 + static jsval_t builtin_fs_access(struct js *js, jsval_t *args, int nargs) { 1143 + if (nargs < 1) return js_mkerr(js, "access() requires a path argument"); 1144 + 1145 + if (js_type(args[0]) != JS_STR) return js_mkerr(js, "access() path must be a string"); 1146 + 1147 + size_t path_len; 1148 + char *path = js_getstr(js, args[0], &path_len); 1149 + if (!path) return js_mkerr(js, "Failed to get path string"); 1150 + 1151 + int mode = F_OK; 1152 + if (nargs >= 2 && js_type(args[1]) == JS_NUM) { 1153 + mode = (int)js_getnum(args[1]); 1154 + } 1155 + 1156 + ensure_fs_loop(); 1157 + 1158 + fs_request_t *req = calloc(1, sizeof(fs_request_t)); 1159 + if (!req) return js_mkerr(js, "Out of memory"); 1160 + 1161 + req->js = js; 1162 + req->op_type = FS_OP_ACCESS; 1163 + req->promise = js_mkpromise(js); 1164 + req->path = strndup(path, path_len); 1165 + req->uv_req.data = req; 1166 + 1167 + utarray_push_back(pending_requests, &req); 1168 + int result = uv_fs_access(fs_loop, &req->uv_req, req->path, mode, on_access_complete); 1169 + 1170 + if (result < 0) { 1171 + req->failed = 1; 1172 + req->error_msg = strdup(uv_strerror(result)); 1173 + req->completed = 1; 1174 + complete_request(req); 1175 + } 1176 + 1177 + return req->promise; 1178 + } 1179 + 1053 1180 static jsval_t builtin_fs_readdirSync(struct js *js, jsval_t *args, int nargs) { 1054 1181 if (nargs < 1) return js_mkerr(js, "readdirSync() requires a path argument"); 1055 1182 ··· 1106 1233 req->uv_req.data = req; 1107 1234 1108 1235 utarray_push_back(pending_requests, &req); 1109 - 1110 1236 int result = uv_fs_scandir(fs_loop, &req->uv_req, req->path, 0, on_readdir_complete); 1111 1237 1112 1238 if (result < 0) { ··· 1119 1245 return req->promise; 1120 1246 } 1121 1247 1248 + void init_fs_module(void) { 1249 + struct js *js = rt->js; 1250 + jsval_t glob = js_glob(js); 1251 + 1252 + jsval_t stats_ctor = js_mkobj(js); 1253 + jsval_t stats_proto = js_mkobj(js); 1254 + 1255 + js_set(js, stats_proto, "isFile", js_mkfun(stat_isFile)); 1256 + js_set(js, stats_proto, "isDirectory", js_mkfun(stat_isDirectory)); 1257 + js_set(js, stats_proto, "isSymbolicLink", js_mkfun(stat_isSymbolicLink)); 1258 + js_set(js, stats_proto, get_toStringTag_sym_key(), js_mkstr(js, "Stats", 5)); 1259 + 1260 + js_mkprop_fast(js, stats_ctor, "prototype", 9, stats_proto); 1261 + js_mkprop_fast(js, stats_ctor, "name", 4, js_mkstr(js, "Stats", 5)); 1262 + js_set_descriptor(js, stats_ctor, "name", 4, 0); 1263 + 1264 + js_set(js, glob, "Stats", js_obj_to_func(stats_ctor)); 1265 + } 1266 + 1122 1267 jsval_t fs_library(struct js *js) { 1123 1268 jsval_t lib = js_mkobj(js); 1124 1269 ··· 1141 1286 js_set(js, lib, "statSync", js_mkfun(builtin_fs_statSync)); 1142 1287 js_set(js, lib, "exists", js_mkfun(builtin_fs_exists)); 1143 1288 js_set(js, lib, "existsSync", js_mkfun(builtin_fs_existsSync)); 1289 + js_set(js, lib, "access", js_mkfun(builtin_fs_access)); 1290 + js_set(js, lib, "accessSync", js_mkfun(builtin_fs_accessSync)); 1144 1291 js_set(js, lib, "readdir", js_mkfun(builtin_fs_readdir)); 1145 1292 js_set(js, lib, "readdirSync", js_mkfun(builtin_fs_readdirSync)); 1146 1293 js_set(js, lib, get_toStringTag_sym_key(), js_mkstr(js, "fs", 2)); 1294 + 1295 + jsval_t constants = js_mkobj(js); 1296 + js_set(js, constants, "F_OK", js_mknum(F_OK)); 1297 + js_set(js, constants, "R_OK", js_mknum(R_OK)); 1298 + js_set(js, constants, "W_OK", js_mknum(W_OK)); 1299 + js_set(js, constants, "X_OK", js_mknum(X_OK)); 1300 + js_set(js, lib, "constants", constants); 1147 1301 1148 1302 return lib; 1149 1303 } ··· 1165 1319 unsigned int len = utarray_len(pending_requests); 1166 1320 for (unsigned int i = 0; i < len; i++) { 1167 1321 fs_request_t **reqp = (fs_request_t **)utarray_eltptr(pending_requests, i); 1168 - if (reqp && *reqp) { 1169 - (*reqp)->promise = fwd_val(ctx, (*reqp)->promise); 1170 - } 1322 + if (reqp && *reqp) { (*reqp)->promise = fwd_val(ctx, (*reqp)->promise); } 1171 1323 } 1172 1324 }
+12
src/types/modules/fs.d.ts
··· 2 2 interface Stats { 3 3 size: number; 4 4 mode: number; 5 + uid: number; 6 + gid: number; 5 7 isFile(): boolean; 6 8 isDirectory(): boolean; 9 + isSymbolicLink(): boolean; 7 10 } 11 + 12 + const constants: { 13 + F_OK: number; 14 + R_OK: number; 15 + W_OK: number; 16 + X_OK: number; 17 + }; 8 18 9 19 function readFile(path: string): Promise<string>; 10 20 function readFileSync(path: string): string; ··· 25 35 function statSync(path: string): Stats; 26 36 function exists(path: string): Promise<boolean>; 27 37 function existsSync(path: string): boolean; 38 + function access(path: string, mode?: number): Promise<void>; 39 + function accessSync(path: string, mode?: number): void; 28 40 function readdir(path: string): Promise<string[]>; 29 41 function readdirSync(path: string): string[]; 30 42 }