xbintsc 0.3.12 → 0.3.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -3
- package/README.zh-CN.md +18 -3
- package/dist/src/codegen/generator/calls/access.js +13 -0
- package/dist/src/codegen/generator/calls/access.js.map +1 -1
- package/dist/src/codegen/generator/calls/invocation.js +8 -2
- package/dist/src/codegen/generator/calls/invocation.js.map +1 -1
- package/dist/src/codegen/generator/context.d.ts +23 -0
- package/dist/src/codegen/generator/context.js +91 -17
- package/dist/src/codegen/generator/context.js.map +1 -1
- package/dist/src/codegen/generator/expressions/primary.js +5 -0
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
- package/dist/src/driver/compiler.d.ts +7 -0
- package/dist/src/driver/compiler.js +41 -5
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/modules.d.ts +1 -1
- package/dist/src/driver/modules.js +235 -25
- package/dist/src/driver/modules.js.map +1 -1
- package/dist/src/extensions/node/fs/fs-ops.d.ts +5 -2
- package/dist/src/extensions/node/fs/fs-ops.js +45 -6
- package/dist/src/extensions/node/fs/fs-ops.js.map +1 -1
- package/dist/src/extensions/node/fs/index.d.ts +6 -2
- package/dist/src/extensions/node/fs/index.js +22 -3
- package/dist/src/extensions/node/fs/index.js.map +1 -1
- package/dist/src/extensions/node/fs-promises/index.d.ts +4 -3
- package/dist/src/extensions/node/fs-promises/index.js +31 -3
- package/dist/src/extensions/node/fs-promises/index.js.map +1 -1
- package/dist/tests/cli/main.test.js +17 -0
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/driver/compiler.test.js +93 -2
- package/dist/tests/driver/compiler.test.js.map +1 -1
- package/dist/tests/driver/modules.test.js +91 -4
- package/dist/tests/driver/modules.test.js.map +1 -1
- package/dist/tests/e2e/compile-node.test.js +240 -0
- package/dist/tests/e2e/compile-node.test.js.map +1 -1
- package/dist/tests/e2e/compile.test.js +12 -0
- package/dist/tests/e2e/compile.test.js.map +1 -1
- package/dist/tests/e2e/harness.js +11 -8
- package/dist/tests/e2e/harness.js.map +1 -1
- package/dist/tests/e2e/node-modules.test.js +1 -1
- package/dist/tests/e2e/node-modules.test.js.map +1 -1
- package/dist/tests/e2e/npm-modules.test.d.ts +9 -0
- package/dist/tests/e2e/npm-modules.test.js +55 -0
- package/dist/tests/e2e/npm-modules.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage.test.d.ts +11 -0
- package/dist/tests/e2e/runtime-coverage.test.js +646 -0
- package/dist/tests/e2e/runtime-coverage.test.js.map +1 -0
- package/package.json +3 -2
- package/runtime/ext_node/buffer/parts/prototype.inc +7 -0
- package/runtime/ext_node/buffer/parts/search.inc +8 -4
- package/runtime/ext_node/child_process/child_process.c +5 -0
- package/runtime/ext_node/fs/constants.c +113 -0
- package/runtime/ext_node/fs/copy_ops.c +145 -0
- package/runtime/ext_node/fs/dir.c +101 -0
- package/runtime/ext_node/fs/fd_ops.c +405 -0
- package/runtime/ext_node/fs/fs_common.h +388 -5
- package/runtime/ext_node/fs/fs_ops.c +100 -139
- package/runtime/ext_node/fs/glob.c +232 -0
- package/runtime/ext_node/fs/link_ops.c +91 -0
- package/runtime/ext_node/fs/meta_ops.c +403 -0
- package/runtime/ext_node/fs/promises.c +275 -60
- package/runtime/ext_node/fs/read_file.c +8 -4
- package/runtime/ext_node/fs/watch.c +52 -0
- package/runtime/ext_node/fs/write_file.c +20 -11
- package/runtime/ext_node/stream/stream.c +19 -2
- package/runtime/rt.h +9 -0
- package/runtime/xt_io.c +21 -0
- package/scripts/coverage-runtime.ts +338 -0
- package/src/codegen/generator/calls/access.ts +15 -0
- package/src/codegen/generator/calls/invocation.ts +8 -2
- package/src/codegen/generator/context.ts +112 -21
- package/src/codegen/generator/expressions/primary.ts +5 -0
- package/src/driver/compiler.ts +42 -5
- package/src/driver/modules.ts +251 -26
- package/src/extensions/node/fs/fs-ops.ts +48 -6
- package/src/extensions/node/fs/index.ts +25 -3
- package/src/extensions/node/fs-promises/index.ts +33 -4
|
@@ -10,11 +10,347 @@
|
|
|
10
10
|
#ifndef XT_NODE_FS_COMMON_H
|
|
11
11
|
#define XT_NODE_FS_COMMON_H
|
|
12
12
|
|
|
13
|
-
#include "
|
|
13
|
+
#include "rt_internal.h"
|
|
14
14
|
|
|
15
|
+
#include <errno.h>
|
|
15
16
|
#include <stdio.h>
|
|
16
17
|
#include <stdlib.h>
|
|
17
18
|
#include <string.h>
|
|
19
|
+
#include <time.h>
|
|
20
|
+
|
|
21
|
+
/* -- platform shims ------------------------------------------------------- */
|
|
22
|
+
|
|
23
|
+
#if defined(_WIN32)
|
|
24
|
+
#include <direct.h>
|
|
25
|
+
#include <fcntl.h>
|
|
26
|
+
#include <io.h>
|
|
27
|
+
#include <sys/stat.h>
|
|
28
|
+
#include <sys/types.h>
|
|
29
|
+
|
|
30
|
+
/* Stat results are filled from Win32 directly. The CRT's `_stat` converts the
|
|
31
|
+
* FILETIME through the *local* time zone before producing `time_t`, so a time
|
|
32
|
+
* near the Unix epoch (e.g. `utimesSync(path, 1000, 2000)`) maps to 1969 on a
|
|
33
|
+
* machine west of UTC and the CRT reports an unrepresentable `st_mtime` (-1).
|
|
34
|
+
* Reading the Win32 FILETIME and converting it to Unix seconds in UTC like
|
|
35
|
+
* libuv/Node keeps the values exact and timezone independent. */
|
|
36
|
+
typedef struct {
|
|
37
|
+
long long st_size;
|
|
38
|
+
unsigned int st_mode;
|
|
39
|
+
unsigned int st_uid;
|
|
40
|
+
unsigned int st_gid;
|
|
41
|
+
unsigned int st_dev;
|
|
42
|
+
unsigned long long st_ino;
|
|
43
|
+
unsigned int st_nlink;
|
|
44
|
+
unsigned int st_rdev;
|
|
45
|
+
long long st_mtime; /* seconds since the Unix epoch */
|
|
46
|
+
long long st_atime;
|
|
47
|
+
long long st_ctime;
|
|
48
|
+
} xt_fs_stat_t;
|
|
49
|
+
|
|
50
|
+
int xt_fs_win_stat(const char *path, xt_fs_stat_t *out);
|
|
51
|
+
int xt_fs_win_lstat(const char *path, xt_fs_stat_t *out);
|
|
52
|
+
int xt_fs_win_fstat(int fd, xt_fs_stat_t *out);
|
|
53
|
+
#define xt_fs_stat_fn xt_fs_win_stat
|
|
54
|
+
#define xt_fs_lstat_fn xt_fs_win_lstat
|
|
55
|
+
#define xt_fs_fstat_fn xt_fs_win_fstat
|
|
56
|
+
#define xt_fs_access _access
|
|
57
|
+
#define xt_fs_mkdir_mode(path, mode) _mkdir(path)
|
|
58
|
+
#define xt_fs_mkdir_one(path) _mkdir(path)
|
|
59
|
+
#define xt_fs_rmdir_one(path) _rmdir(path)
|
|
60
|
+
#define XT_FS_OPEN _open
|
|
61
|
+
#define XT_FS_CLOSE _close
|
|
62
|
+
#define XT_FS_READ _read
|
|
63
|
+
#define XT_FS_WRITE _write
|
|
64
|
+
|
|
65
|
+
#ifndef S_ISREG
|
|
66
|
+
#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
|
|
67
|
+
#endif
|
|
68
|
+
#ifndef S_ISDIR
|
|
69
|
+
#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
|
|
70
|
+
#endif
|
|
71
|
+
#ifndef S_ISLNK
|
|
72
|
+
#define S_ISLNK(m) 0
|
|
73
|
+
#endif
|
|
74
|
+
#ifndef S_ISFIFO
|
|
75
|
+
#define S_ISFIFO(m) 0
|
|
76
|
+
#endif
|
|
77
|
+
#ifndef S_ISSOCK
|
|
78
|
+
#define S_ISSOCK(m) 0
|
|
79
|
+
#endif
|
|
80
|
+
#ifndef S_ISBLK
|
|
81
|
+
#define S_ISBLK(m) 0
|
|
82
|
+
#endif
|
|
83
|
+
#ifndef S_ISCHR
|
|
84
|
+
#define S_ISCHR(m) (((m) & _S_IFMT) == _S_IFCHR)
|
|
85
|
+
#endif
|
|
86
|
+
#ifndef F_OK
|
|
87
|
+
#define F_OK 0
|
|
88
|
+
#endif
|
|
89
|
+
#else
|
|
90
|
+
#include <fcntl.h>
|
|
91
|
+
#include <sys/stat.h>
|
|
92
|
+
#include <sys/types.h>
|
|
93
|
+
#include <unistd.h>
|
|
94
|
+
|
|
95
|
+
typedef struct stat xt_fs_stat_t;
|
|
96
|
+
#define xt_fs_stat_fn stat
|
|
97
|
+
#define xt_fs_lstat_fn lstat
|
|
98
|
+
#define xt_fs_access access
|
|
99
|
+
#define xt_fs_mkdir_mode(path, mode) mkdir((path), (mode))
|
|
100
|
+
#define xt_fs_mkdir_one(path) mkdir(path, 0777)
|
|
101
|
+
#define xt_fs_rmdir_one(path) rmdir(path)
|
|
102
|
+
#define XT_FS_OPEN open
|
|
103
|
+
#define XT_FS_CLOSE close
|
|
104
|
+
#define XT_FS_READ read
|
|
105
|
+
#define XT_FS_WRITE write
|
|
106
|
+
#endif
|
|
107
|
+
|
|
108
|
+
/* -- directory iteration -------------------------------------------------- */
|
|
109
|
+
|
|
110
|
+
#if defined(_WIN32)
|
|
111
|
+
/* Directory iteration backed by the CRT's _findfirst/_findnext. */
|
|
112
|
+
typedef struct {
|
|
113
|
+
intptr_t handle;
|
|
114
|
+
struct _finddata_t entry;
|
|
115
|
+
} xt_fs_dir;
|
|
116
|
+
|
|
117
|
+
static inline int xt_fs_dir_open(xt_fs_dir *dir, const char *path) {
|
|
118
|
+
size_t length = strlen(path);
|
|
119
|
+
char *pattern = (char *)malloc(length + 3);
|
|
120
|
+
if (!pattern) return 0;
|
|
121
|
+
memcpy(pattern, path, length);
|
|
122
|
+
pattern[length] = '/';
|
|
123
|
+
pattern[length + 1] = '*';
|
|
124
|
+
pattern[length + 2] = '\0';
|
|
125
|
+
dir->handle = _findfirst(pattern, &dir->entry);
|
|
126
|
+
free(pattern);
|
|
127
|
+
return dir->handle != -1;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
static inline int xt_fs_dir_next(xt_fs_dir *dir) { return _findnext(dir->handle, &dir->entry) == 0; }
|
|
131
|
+
static inline const char *xt_fs_dir_name(xt_fs_dir *dir) { return dir->entry.name; }
|
|
132
|
+
static inline void xt_fs_dir_close(xt_fs_dir *dir) { _findclose(dir->handle); }
|
|
133
|
+
#else
|
|
134
|
+
#include <dirent.h>
|
|
135
|
+
|
|
136
|
+
typedef struct {
|
|
137
|
+
DIR *handle;
|
|
138
|
+
struct dirent *entry;
|
|
139
|
+
} xt_fs_dir;
|
|
140
|
+
|
|
141
|
+
static inline int xt_fs_dir_open(xt_fs_dir *dir, const char *path) {
|
|
142
|
+
dir->handle = opendir(path);
|
|
143
|
+
dir->entry = NULL;
|
|
144
|
+
return dir->handle != NULL;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
static inline int xt_fs_dir_next(xt_fs_dir *dir) {
|
|
148
|
+
dir->entry = readdir(dir->handle);
|
|
149
|
+
return dir->entry != NULL;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
static inline const char *xt_fs_dir_name(xt_fs_dir *dir) { return dir->entry->d_name; }
|
|
153
|
+
static inline void xt_fs_dir_close(xt_fs_dir *dir) { closedir(dir->handle); }
|
|
154
|
+
#endif
|
|
155
|
+
|
|
156
|
+
/* -- errors --------------------------------------------------------------- */
|
|
157
|
+
|
|
158
|
+
/* Node's `err.code` for the errno values the fs module can raise. */
|
|
159
|
+
static inline const char *xt_fs_errno_name(int err) {
|
|
160
|
+
switch (err) {
|
|
161
|
+
case ENOENT: return "ENOENT";
|
|
162
|
+
case EACCES: return "EACCES";
|
|
163
|
+
case EEXIST: return "EEXIST";
|
|
164
|
+
case ENOTDIR: return "ENOTDIR";
|
|
165
|
+
case EISDIR: return "EISDIR";
|
|
166
|
+
case EPERM: return "EPERM";
|
|
167
|
+
case EINVAL: return "EINVAL";
|
|
168
|
+
case EBADF: return "EBADF";
|
|
169
|
+
case ENOSPC: return "ENOSPC";
|
|
170
|
+
case EROFS: return "EROFS";
|
|
171
|
+
case EMFILE: return "EMFILE";
|
|
172
|
+
#ifdef ENOTEMPTY
|
|
173
|
+
case ENOTEMPTY: return "ENOTEMPTY";
|
|
174
|
+
#endif
|
|
175
|
+
#ifdef ELOOP
|
|
176
|
+
case ELOOP: return "ELOOP";
|
|
177
|
+
#endif
|
|
178
|
+
#ifdef ENAMETOOLONG
|
|
179
|
+
case ENAMETOOLONG: return "ENAMETOOLONG";
|
|
180
|
+
#endif
|
|
181
|
+
#ifdef EXDEV
|
|
182
|
+
case EXDEV: return "EXDEV";
|
|
183
|
+
#endif
|
|
184
|
+
default: return "UNKNOWN";
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/* Build a Node-shaped Error (`code`/`errno`/`syscall`/`path`/`message`). */
|
|
189
|
+
static inline xt_value xt_fs_error_object(int err, const char *syscall, const char *path) {
|
|
190
|
+
const char *code = xt_fs_errno_name(err);
|
|
191
|
+
char buffer[1024];
|
|
192
|
+
snprintf(buffer, sizeof(buffer), "%s: %s, %s '%s'", code, strerror(err), syscall ? syscall : "",
|
|
193
|
+
path ? path : "");
|
|
194
|
+
xt_value error = xt_object_new();
|
|
195
|
+
((xt_object *)XT_GET_PTR(error))->header.kind = XT_OBJECT_KIND_ERROR;
|
|
196
|
+
xt_object_set(error, xt_string_from_cstr("name"), xt_string_from_cstr("Error"));
|
|
197
|
+
xt_object_set(error, xt_string_from_cstr("message"), xt_string_from_cstr(buffer));
|
|
198
|
+
xt_object_set(error, xt_string_from_cstr("code"), xt_string_from_cstr(code));
|
|
199
|
+
xt_object_set(error, xt_string_from_cstr("errno"), xt_number((double)(-err)));
|
|
200
|
+
if (syscall) xt_object_set(error, xt_string_from_cstr("syscall"), xt_string_from_cstr(syscall));
|
|
201
|
+
if (path) xt_object_set(error, xt_string_from_cstr("path"), xt_string_from_cstr(path));
|
|
202
|
+
return error;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* Raise `errno` (captured by the caller right after a failed syscall). */
|
|
206
|
+
static inline void xt_fs_raise_errno(int err, const char *syscall, const char *path) {
|
|
207
|
+
xt_throw(xt_fs_error_object(err, syscall, path));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
static inline void xt_fs_raise_path(const char *syscall, const char *path) {
|
|
211
|
+
xt_fs_raise_errno(errno, syscall, path);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* -- time helpers --------------------------------------------------------- */
|
|
215
|
+
|
|
216
|
+
/* Node accepts a Date or a number of seconds; Date stores milliseconds. */
|
|
217
|
+
static inline double xt_fs_time_seconds(xt_value value) {
|
|
218
|
+
if (XT_IS_OBJECT(value) && ((xt_object *)XT_GET_PTR(value))->header.kind == XT_OBJECT_KIND_DATE) {
|
|
219
|
+
return ((xt_date *)XT_GET_PTR(value))->time / 1000.0;
|
|
220
|
+
}
|
|
221
|
+
return xt_to_number(value);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/* -- open-flag parsing ---------------------------------------------------- */
|
|
225
|
+
|
|
226
|
+
#if defined(_WIN32)
|
|
227
|
+
#define XT_FS_BINARY_FLAG _O_BINARY
|
|
228
|
+
#define XT_FS_RDONLY _O_RDONLY
|
|
229
|
+
#define XT_FS_WRONLY _O_WRONLY
|
|
230
|
+
#define XT_FS_RDWR _O_RDWR
|
|
231
|
+
#define XT_FS_CREAT _O_CREAT
|
|
232
|
+
#define XT_FS_TRUNC _O_TRUNC
|
|
233
|
+
#define XT_FS_APPEND _O_APPEND
|
|
234
|
+
#define XT_FS_EXCL _O_EXCL
|
|
235
|
+
#else
|
|
236
|
+
#define XT_FS_BINARY_FLAG 0
|
|
237
|
+
#define XT_FS_RDONLY O_RDONLY
|
|
238
|
+
#define XT_FS_WRONLY O_WRONLY
|
|
239
|
+
#define XT_FS_RDWR O_RDWR
|
|
240
|
+
#define XT_FS_CREAT O_CREAT
|
|
241
|
+
#define XT_FS_TRUNC O_TRUNC
|
|
242
|
+
#define XT_FS_APPEND O_APPEND
|
|
243
|
+
#define XT_FS_EXCL O_EXCL
|
|
244
|
+
#endif
|
|
245
|
+
|
|
246
|
+
/* Translate a Node flag string (`"r"`, `"w+"`, `"a"`, ...) or number. */
|
|
247
|
+
static inline int xt_fs_parse_flags(xt_value value) {
|
|
248
|
+
if (XT_IS_STRING(value)) {
|
|
249
|
+
const char *flag = xt_string_data(value);
|
|
250
|
+
if (!flag) return XT_FS_RDONLY | XT_FS_BINARY_FLAG;
|
|
251
|
+
int plus = strchr(flag, '+') != NULL;
|
|
252
|
+
int excl = strchr(flag, 'x') != NULL;
|
|
253
|
+
int base;
|
|
254
|
+
if (flag[0] == 'a') base = XT_FS_APPEND | XT_FS_CREAT;
|
|
255
|
+
else if (flag[0] == 'w') base = XT_FS_CREAT | XT_FS_TRUNC;
|
|
256
|
+
else base = 0; /* 'r' and the numeric path below */
|
|
257
|
+
base |= (plus || flag[0] == 'w' || flag[0] == 'a') ? XT_FS_RDWR : XT_FS_RDONLY;
|
|
258
|
+
if (excl) base |= XT_FS_EXCL;
|
|
259
|
+
return base | XT_FS_BINARY_FLAG;
|
|
260
|
+
}
|
|
261
|
+
return (int)xt_to_number(value) | XT_FS_BINARY_FLAG;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/* -- shared object builders (defined in fs_ops.c) ------------------------- */
|
|
265
|
+
|
|
266
|
+
xt_value xt_node_stat_result(const xt_fs_stat_t *info);
|
|
267
|
+
xt_value xt_node_dirent_result(const char *dir, const char *name);
|
|
268
|
+
|
|
269
|
+
/* -- synchronous fs builtins (one translation unit per group) ------------- */
|
|
270
|
+
|
|
271
|
+
xt_value xt_node_read_text_file(int32_t argc, xt_value *argv);
|
|
272
|
+
xt_value xt_node_write_file(int32_t argc, xt_value *argv);
|
|
273
|
+
xt_value xt_node_append_file(int32_t argc, xt_value *argv);
|
|
274
|
+
xt_value xt_node_exists(int32_t argc, xt_value *argv);
|
|
275
|
+
xt_value xt_node_mkdir(int32_t argc, xt_value *argv);
|
|
276
|
+
xt_value xt_node_read_dir(int32_t argc, xt_value *argv);
|
|
277
|
+
xt_value xt_node_rm(int32_t argc, xt_value *argv);
|
|
278
|
+
xt_value xt_node_unlink(int32_t argc, xt_value *argv);
|
|
279
|
+
xt_value xt_node_rmdir(int32_t argc, xt_value *argv);
|
|
280
|
+
xt_value xt_node_rename(int32_t argc, xt_value *argv);
|
|
281
|
+
xt_value xt_node_copy_file(int32_t argc, xt_value *argv);
|
|
282
|
+
xt_value xt_node_realpath(int32_t argc, xt_value *argv);
|
|
283
|
+
xt_value xt_node_stat(int32_t argc, xt_value *argv);
|
|
284
|
+
xt_value xt_node_lstat(int32_t argc, xt_value *argv);
|
|
285
|
+
xt_value xt_node_cp(int32_t argc, xt_value *argv);
|
|
286
|
+
|
|
287
|
+
/* fd_ops.c */
|
|
288
|
+
xt_value xt_node_open(int32_t argc, xt_value *argv);
|
|
289
|
+
xt_value xt_node_close(int32_t argc, xt_value *argv);
|
|
290
|
+
xt_value xt_node_read(int32_t argc, xt_value *argv);
|
|
291
|
+
xt_value xt_node_write(int32_t argc, xt_value *argv);
|
|
292
|
+
xt_value xt_node_readv(int32_t argc, xt_value *argv);
|
|
293
|
+
xt_value xt_node_writev(int32_t argc, xt_value *argv);
|
|
294
|
+
xt_value xt_node_fstat(int32_t argc, xt_value *argv);
|
|
295
|
+
xt_value xt_node_fsync(int32_t argc, xt_value *argv);
|
|
296
|
+
xt_value xt_node_fdatasync(int32_t argc, xt_value *argv);
|
|
297
|
+
xt_value xt_node_ftruncate(int32_t argc, xt_value *argv);
|
|
298
|
+
xt_value xt_node_fchmod(int32_t argc, xt_value *argv);
|
|
299
|
+
xt_value xt_node_fchown(int32_t argc, xt_value *argv);
|
|
300
|
+
xt_value xt_node_futimes(int32_t argc, xt_value *argv);
|
|
301
|
+
|
|
302
|
+
/* meta_ops.c */
|
|
303
|
+
xt_value xt_node_access(int32_t argc, xt_value *argv);
|
|
304
|
+
xt_value xt_node_chmod(int32_t argc, xt_value *argv);
|
|
305
|
+
xt_value xt_node_chown(int32_t argc, xt_value *argv);
|
|
306
|
+
xt_value xt_node_lchmod(int32_t argc, xt_value *argv);
|
|
307
|
+
xt_value xt_node_lchown(int32_t argc, xt_value *argv);
|
|
308
|
+
xt_value xt_node_truncate(int32_t argc, xt_value *argv);
|
|
309
|
+
xt_value xt_node_utimes(int32_t argc, xt_value *argv);
|
|
310
|
+
xt_value xt_node_lutimes(int32_t argc, xt_value *argv);
|
|
311
|
+
xt_value xt_node_statfs(int32_t argc, xt_value *argv);
|
|
312
|
+
xt_value xt_node_mkdtemp(int32_t argc, xt_value *argv);
|
|
313
|
+
|
|
314
|
+
/* link_ops.c */
|
|
315
|
+
xt_value xt_node_link(int32_t argc, xt_value *argv);
|
|
316
|
+
xt_value xt_node_symlink(int32_t argc, xt_value *argv);
|
|
317
|
+
xt_value xt_node_readlink(int32_t argc, xt_value *argv);
|
|
318
|
+
|
|
319
|
+
/* dir.c */
|
|
320
|
+
xt_value xt_node_opendir(int32_t argc, xt_value *argv);
|
|
321
|
+
|
|
322
|
+
/* glob.c */
|
|
323
|
+
xt_value xt_node_glob(int32_t argc, xt_value *argv);
|
|
324
|
+
|
|
325
|
+
/* watch.c */
|
|
326
|
+
xt_value xt_node_watch(int32_t argc, xt_value *argv);
|
|
327
|
+
xt_value xt_node_watch_file(int32_t argc, xt_value *argv);
|
|
328
|
+
xt_value xt_node_unwatch_file(int32_t argc, xt_value *argv);
|
|
329
|
+
|
|
330
|
+
/* constants.c */
|
|
331
|
+
xt_value xt_fs_constants(void);
|
|
332
|
+
xt_value xt_fs_promises(void);
|
|
333
|
+
|
|
334
|
+
/* A promise wrapper over a synchronous builtin: an immediately settled
|
|
335
|
+
* promise that is rejected (rather than throwing) when the builtin raises. */
|
|
336
|
+
static inline xt_value xt_fs_promisify(xt_value (*fn)(int32_t, xt_value *), int32_t argc, xt_value *argv) {
|
|
337
|
+
void *frame = xt_try_enter();
|
|
338
|
+
if (xt_try_setjmp(frame) == 0) {
|
|
339
|
+
xt_value result = fn(argc, argv);
|
|
340
|
+
xt_try_leave(frame);
|
|
341
|
+
return xt_promise_resolve(result);
|
|
342
|
+
}
|
|
343
|
+
xt_value exception = xt_try_exception(frame);
|
|
344
|
+
xt_try_leave(frame);
|
|
345
|
+
return xt_promise_reject(exception);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/* -- Buffer bridge (defined in buffer/parts/prototype.inc) ---------------- */
|
|
349
|
+
|
|
350
|
+
int xt_node_is_buffer(xt_value value);
|
|
351
|
+
unsigned char *xt_node_buffer_bytes(xt_value value, size_t *outLength);
|
|
352
|
+
uint32_t xt_node_buffer_length(xt_value value);
|
|
353
|
+
void xt_node_buffer_set(xt_value value, uint32_t index, unsigned char byte);
|
|
18
354
|
|
|
19
355
|
static const char xt_fs_base64_alphabet[] =
|
|
20
356
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
@@ -37,6 +373,15 @@ static inline int xt_fs_is_base64(const char *encoding) {
|
|
|
37
373
|
return encoding && strcmp(encoding, "base64") == 0;
|
|
38
374
|
}
|
|
39
375
|
|
|
376
|
+
static inline int xt_fs_is_base64url(const char *encoding) {
|
|
377
|
+
return encoding && strcmp(encoding, "base64url") == 0;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
static inline int xt_fs_is_utf16(const char *encoding) {
|
|
381
|
+
return encoding && (strcmp(encoding, "utf16le") == 0 || strcmp(encoding, "ucs2") == 0 ||
|
|
382
|
+
strcmp(encoding, "ucs-2") == 0 || strcmp(encoding, "utf-16le") == 0);
|
|
383
|
+
}
|
|
384
|
+
|
|
40
385
|
static inline xt_value xt_fs_encode_hex(const unsigned char *data, size_t length) {
|
|
41
386
|
static const char digits[] = "0123456789abcdef";
|
|
42
387
|
char *buffer = (char *)malloc(length * 2 + 1);
|
|
@@ -82,9 +427,42 @@ static inline xt_value xt_fs_encode_base64(const unsigned char *data, size_t len
|
|
|
82
427
|
}
|
|
83
428
|
|
|
84
429
|
/* Encode bytes for `readFileSync` according to `encoding` (default raw UTF-8). */
|
|
430
|
+
static inline xt_value xt_fs_encode_base64url(const unsigned char *data, size_t length) {
|
|
431
|
+
size_t outLength = ((length + 2) / 3) * 4 + 1;
|
|
432
|
+
char *buffer = (char *)malloc(outLength);
|
|
433
|
+
if (!buffer) return xt_undefined();
|
|
434
|
+
size_t i = 0, j = 0;
|
|
435
|
+
while (i + 2 < length) {
|
|
436
|
+
uint32_t n = ((uint32_t)data[i] << 16) | ((uint32_t)data[i + 1] << 8) | (uint32_t)data[i + 2];
|
|
437
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 18) & 63];
|
|
438
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 12) & 63];
|
|
439
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 6) & 63];
|
|
440
|
+
buffer[j++] = xt_fs_base64_alphabet[n & 63];
|
|
441
|
+
i += 3;
|
|
442
|
+
}
|
|
443
|
+
if (length - i == 1) {
|
|
444
|
+
uint32_t n = (uint32_t)data[i] << 16;
|
|
445
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 18) & 63];
|
|
446
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 12) & 63];
|
|
447
|
+
} else if (length - i == 2) {
|
|
448
|
+
uint32_t n = ((uint32_t)data[i] << 16) | ((uint32_t)data[i + 1] << 8);
|
|
449
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 18) & 63];
|
|
450
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 12) & 63];
|
|
451
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 6) & 63];
|
|
452
|
+
}
|
|
453
|
+
for (size_t k = 0; k < j; k++) {
|
|
454
|
+
if (buffer[k] == '+') buffer[k] = '-';
|
|
455
|
+
else if (buffer[k] == '/') buffer[k] = '_';
|
|
456
|
+
}
|
|
457
|
+
xt_value result = xt_string_new(buffer, j);
|
|
458
|
+
free(buffer);
|
|
459
|
+
return result;
|
|
460
|
+
}
|
|
461
|
+
|
|
85
462
|
static inline xt_value xt_fs_encode_bytes(const unsigned char *data, size_t length, const char *encoding) {
|
|
86
463
|
if (xt_fs_is_hex(encoding)) return xt_fs_encode_hex(data, length);
|
|
87
464
|
if (xt_fs_is_base64(encoding)) return xt_fs_encode_base64(data, length);
|
|
465
|
+
if (xt_fs_is_base64url(encoding)) return xt_fs_encode_base64url(data, length);
|
|
88
466
|
return xt_string_new((const char *)data, length);
|
|
89
467
|
}
|
|
90
468
|
|
|
@@ -92,8 +470,8 @@ static inline int xt_fs_base64_value(char c) {
|
|
|
92
470
|
if (c >= 'A' && c <= 'Z') return c - 'A';
|
|
93
471
|
if (c >= 'a' && c <= 'z') return c - 'a' + 26;
|
|
94
472
|
if (c >= '0' && c <= '9') return c - '0' + 52;
|
|
95
|
-
if (c == '+') return 62;
|
|
96
|
-
if (c == '/') return 63;
|
|
473
|
+
if (c == '+' || c == '-') return 62;
|
|
474
|
+
if (c == '/' || c == '_') return 63;
|
|
97
475
|
return -1;
|
|
98
476
|
}
|
|
99
477
|
|
|
@@ -111,7 +489,7 @@ static inline int xt_fs_hex_value(char c) {
|
|
|
111
489
|
*/
|
|
112
490
|
static inline unsigned char *xt_fs_decode_text(const char *text, size_t length, const char *encoding, size_t *outLength) {
|
|
113
491
|
unsigned char *bytes = NULL;
|
|
114
|
-
if (xt_fs_is_base64(encoding)) {
|
|
492
|
+
if (xt_fs_is_base64(encoding) || xt_fs_is_base64url(encoding)) {
|
|
115
493
|
size_t capacity = (length / 4 + 1) * 3;
|
|
116
494
|
bytes = (unsigned char *)malloc(capacity + 1);
|
|
117
495
|
if (!bytes) return NULL;
|
|
@@ -159,8 +537,13 @@ static inline unsigned char *xt_fs_decode_text(const char *text, size_t length,
|
|
|
159
537
|
return bytes;
|
|
160
538
|
}
|
|
161
539
|
|
|
540
|
+
/*
|
|
541
|
+
* Report a failed syscall. The fs module follows Node and *throws* a shaped
|
|
542
|
+
* Error (the runtime now has catchable exceptions), so callers must not rely
|
|
543
|
+
* on a return value after a failure.
|
|
544
|
+
*/
|
|
162
545
|
static inline void xt_fs_error(const char *action, const char *path) {
|
|
163
|
-
|
|
546
|
+
xt_fs_raise_errno(errno, action, path);
|
|
164
547
|
}
|
|
165
548
|
|
|
166
549
|
#endif /* XT_NODE_FS_COMMON_H */
|