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
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Node.js `fs` metadata / temporary-directory operations for xbintsc.
|
|
3
|
+
*
|
|
4
|
+
* accessSync, chmodSync, chownSync, truncateSync, utimesSync, lutimesSync,
|
|
5
|
+
* statfsSync, mkdtempSync
|
|
6
|
+
*
|
|
7
|
+
* Errors throw Node-shaped `Error` objects (see `fs_common.h`).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include "../node_common.h"
|
|
11
|
+
#include "fs_common.h"
|
|
12
|
+
|
|
13
|
+
#include <sys/stat.h>
|
|
14
|
+
#include <sys/types.h>
|
|
15
|
+
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
|
16
|
+
#include <sys/mount.h>
|
|
17
|
+
#elif defined(__linux__)
|
|
18
|
+
#include <sys/vfs.h>
|
|
19
|
+
#endif
|
|
20
|
+
|
|
21
|
+
#if defined(_WIN32)
|
|
22
|
+
#include <io.h>
|
|
23
|
+
#include <windows.h>
|
|
24
|
+
#define xt_fs_chmod_fn _chmod
|
|
25
|
+
#define xt_fs_truncate_path(path, length) xt_fs_win_truncate(path, length)
|
|
26
|
+
#else
|
|
27
|
+
#include <sys/time.h>
|
|
28
|
+
#include <unistd.h>
|
|
29
|
+
#define xt_fs_chmod_fn chmod
|
|
30
|
+
#define xt_fs_truncate_path(path, length) truncate((path), (off_t)(length))
|
|
31
|
+
#endif
|
|
32
|
+
|
|
33
|
+
#if defined(_WIN32)
|
|
34
|
+
static int xt_fs_errno_from_win32(DWORD error) {
|
|
35
|
+
switch (error) {
|
|
36
|
+
case ERROR_FILE_NOT_FOUND:
|
|
37
|
+
case ERROR_PATH_NOT_FOUND:
|
|
38
|
+
case ERROR_INVALID_NAME:
|
|
39
|
+
case ERROR_BAD_PATHNAME:
|
|
40
|
+
case ERROR_BAD_NETPATH:
|
|
41
|
+
case ERROR_INVALID_DRIVE:
|
|
42
|
+
return ENOENT;
|
|
43
|
+
case ERROR_ACCESS_DENIED:
|
|
44
|
+
case ERROR_SHARING_VIOLATION:
|
|
45
|
+
case ERROR_LOCK_VIOLATION:
|
|
46
|
+
return EACCES;
|
|
47
|
+
case ERROR_DIRECTORY:
|
|
48
|
+
return ENOTDIR;
|
|
49
|
+
#ifdef ENAMETOOLONG
|
|
50
|
+
case ERROR_FILENAME_EXCED_RANGE:
|
|
51
|
+
return ENAMETOOLONG;
|
|
52
|
+
#endif
|
|
53
|
+
case ERROR_NOT_ENOUGH_MEMORY:
|
|
54
|
+
case ERROR_OUTOFMEMORY:
|
|
55
|
+
return ENOMEM;
|
|
56
|
+
default:
|
|
57
|
+
return EINVAL;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* FILETIME (100 ns ticks since 1601-01-01 UTC) -> Unix seconds, in UTC.
|
|
62
|
+
* Unlike the CRT's `_stat` this never round-trips through the local time zone,
|
|
63
|
+
* so epoch-relative times stay representable regardless of the machine's
|
|
64
|
+
* timezone (matching libuv/Node). */
|
|
65
|
+
static long long xt_fs_filetime_to_seconds(const FILETIME *time) {
|
|
66
|
+
unsigned long long value = ((unsigned long long)time->dwHighDateTime << 32) | time->dwLowDateTime;
|
|
67
|
+
if (value == 0) return 0;
|
|
68
|
+
return ((long long)value - 116444736000000000LL) / 10000000LL;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
static void xt_fs_win_fill_stat(xt_fs_stat_t *out, DWORD attributes, DWORD volume,
|
|
72
|
+
unsigned long long index, unsigned int links, long long size,
|
|
73
|
+
const FILETIME *creation, const FILETIME *access,
|
|
74
|
+
const FILETIME *write) {
|
|
75
|
+
memset(out, 0, sizeof(*out));
|
|
76
|
+
if (attributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
77
|
+
out->st_mode = _S_IFDIR;
|
|
78
|
+
size = 0;
|
|
79
|
+
} else {
|
|
80
|
+
out->st_mode = _S_IFREG;
|
|
81
|
+
}
|
|
82
|
+
if (attributes & FILE_ATTRIBUTE_READONLY) {
|
|
83
|
+
out->st_mode |= _S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6);
|
|
84
|
+
} else {
|
|
85
|
+
out->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) |
|
|
86
|
+
((_S_IREAD | _S_IWRITE) >> 6);
|
|
87
|
+
}
|
|
88
|
+
out->st_size = size;
|
|
89
|
+
out->st_dev = volume;
|
|
90
|
+
out->st_ino = index;
|
|
91
|
+
out->st_nlink = links ? links : 1;
|
|
92
|
+
out->st_ctime = xt_fs_filetime_to_seconds(creation);
|
|
93
|
+
out->st_atime = xt_fs_filetime_to_seconds(access);
|
|
94
|
+
out->st_mtime = xt_fs_filetime_to_seconds(write);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
int xt_fs_win_stat(const char *path, xt_fs_stat_t *out) {
|
|
98
|
+
WIN32_FILE_ATTRIBUTE_DATA data;
|
|
99
|
+
if (!path || !GetFileAttributesExA(path, GetFileExInfoStandard, &data)) {
|
|
100
|
+
errno = xt_fs_errno_from_win32(GetLastError());
|
|
101
|
+
return -1;
|
|
102
|
+
}
|
|
103
|
+
long long size = ((long long)data.nFileSizeHigh << 32) | data.nFileSizeLow;
|
|
104
|
+
xt_fs_win_fill_stat(out, data.dwFileAttributes, 0, 0, 1, size, &data.ftCreationTime,
|
|
105
|
+
&data.ftLastAccessTime, &data.ftLastWriteTime);
|
|
106
|
+
/* Best effort: fill the volume serial, file index and link count like Node. */
|
|
107
|
+
HANDLE handle = CreateFileA(path, FILE_READ_ATTRIBUTES,
|
|
108
|
+
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
|
109
|
+
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
|
110
|
+
if (handle != INVALID_HANDLE_VALUE) {
|
|
111
|
+
BY_HANDLE_FILE_INFORMATION info;
|
|
112
|
+
if (GetFileInformationByHandle(handle, &info)) {
|
|
113
|
+
out->st_dev = info.dwVolumeSerialNumber;
|
|
114
|
+
out->st_ino = ((unsigned long long)info.nFileIndexHigh << 32) | info.nFileIndexLow;
|
|
115
|
+
out->st_nlink = info.nNumberOfLinks ? info.nNumberOfLinks : 1;
|
|
116
|
+
}
|
|
117
|
+
CloseHandle(handle);
|
|
118
|
+
}
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
int xt_fs_win_lstat(const char *path, xt_fs_stat_t *out) { return xt_fs_win_stat(path, out); }
|
|
123
|
+
|
|
124
|
+
int xt_fs_win_fstat(int fd, xt_fs_stat_t *out) {
|
|
125
|
+
intptr_t os_handle = _get_osfhandle(fd);
|
|
126
|
+
if (os_handle == -1) {
|
|
127
|
+
errno = EBADF;
|
|
128
|
+
return -1;
|
|
129
|
+
}
|
|
130
|
+
BY_HANDLE_FILE_INFORMATION info;
|
|
131
|
+
if (GetFileInformationByHandle((HANDLE)os_handle, &info)) {
|
|
132
|
+
long long size = ((long long)info.nFileSizeHigh << 32) | info.nFileSizeLow;
|
|
133
|
+
xt_fs_win_fill_stat(out, info.dwFileAttributes, info.dwVolumeSerialNumber,
|
|
134
|
+
((unsigned long long)info.nFileIndexHigh << 32) | info.nFileIndexLow,
|
|
135
|
+
info.nNumberOfLinks, size, &info.ftCreationTime, &info.ftLastAccessTime,
|
|
136
|
+
&info.ftLastWriteTime);
|
|
137
|
+
return 0;
|
|
138
|
+
}
|
|
139
|
+
DWORD type = GetFileType((HANDLE)os_handle);
|
|
140
|
+
if (type == FILE_TYPE_CHAR || type == FILE_TYPE_PIPE) {
|
|
141
|
+
memset(out, 0, sizeof(*out));
|
|
142
|
+
out->st_mode = (type == FILE_TYPE_PIPE ? _S_IFIFO : _S_IFCHR) | _S_IREAD | _S_IWRITE |
|
|
143
|
+
(_S_IREAD >> 3) | (_S_IWRITE >> 3) | (_S_IREAD >> 6) | (_S_IWRITE >> 6);
|
|
144
|
+
out->st_nlink = 1;
|
|
145
|
+
out->st_ino = (unsigned long long)(uintptr_t)os_handle;
|
|
146
|
+
return 0;
|
|
147
|
+
}
|
|
148
|
+
errno = xt_fs_errno_from_win32(GetLastError());
|
|
149
|
+
return -1;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
static int xt_fs_win_truncate(const char *path, long long length) {
|
|
153
|
+
int fd = _open(path, _O_RDWR | _O_BINARY);
|
|
154
|
+
if (fd < 0) return -1;
|
|
155
|
+
int result = _chsize_s(fd, length);
|
|
156
|
+
_close(fd);
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* Unix seconds -> Windows FILETIME (100 ns ticks since 1601-01-01 UTC). The CRT
|
|
161
|
+
* `_utime`/`_utimbuf` path goes through local time, which is both lossy around
|
|
162
|
+
* DST boundaries and ABI-fragile across MSVC/MinGW; matching libuv's direct
|
|
163
|
+
* conversion keeps the result exact and identical to Node. */
|
|
164
|
+
static void xt_fs_unix_to_filetime(double seconds, FILETIME *out) {
|
|
165
|
+
long long ticks = (long long)(seconds * 10000000.0) + 116444736000000000LL;
|
|
166
|
+
unsigned long long value = (unsigned long long)ticks;
|
|
167
|
+
out->dwLowDateTime = (DWORD)value;
|
|
168
|
+
out->dwHighDateTime = (DWORD)(value >> 32);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static int xt_fs_set_file_times(HANDLE handle, double atime, double mtime) {
|
|
172
|
+
FILETIME access_time;
|
|
173
|
+
FILETIME modify_time;
|
|
174
|
+
FILETIME *access_ptr = NULL;
|
|
175
|
+
FILETIME *modify_ptr = NULL;
|
|
176
|
+
if (atime == atime) {
|
|
177
|
+
xt_fs_unix_to_filetime(atime, &access_time);
|
|
178
|
+
access_ptr = &access_time;
|
|
179
|
+
}
|
|
180
|
+
if (mtime == mtime) {
|
|
181
|
+
xt_fs_unix_to_filetime(mtime, &modify_time);
|
|
182
|
+
modify_ptr = &modify_time;
|
|
183
|
+
}
|
|
184
|
+
return SetFileTime(handle, NULL, access_ptr, modify_ptr) ? 0 : -1;
|
|
185
|
+
}
|
|
186
|
+
#endif
|
|
187
|
+
|
|
188
|
+
/* ------------------------------------------------------------------------- */
|
|
189
|
+
/* accessSync */
|
|
190
|
+
/* ------------------------------------------------------------------------- */
|
|
191
|
+
|
|
192
|
+
xt_value xt_node_access(int32_t argc, xt_value *argv) {
|
|
193
|
+
if (argc < 1) return xt_undefined();
|
|
194
|
+
const char *path = xt_node_cstr(argv[0]);
|
|
195
|
+
int mode = argc > 1 ? (int)xt_to_number(argv[1]) : F_OK;
|
|
196
|
+
if (!path || xt_fs_access(path, mode) != 0) {
|
|
197
|
+
xt_fs_raise_path("access", path);
|
|
198
|
+
return xt_undefined();
|
|
199
|
+
}
|
|
200
|
+
return xt_undefined();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/* ------------------------------------------------------------------------- */
|
|
204
|
+
/* chmodSync / chownSync */
|
|
205
|
+
/* ------------------------------------------------------------------------- */
|
|
206
|
+
|
|
207
|
+
xt_value xt_node_chmod(int32_t argc, xt_value *argv) {
|
|
208
|
+
if (argc < 2) return xt_undefined();
|
|
209
|
+
const char *path = xt_node_cstr(argv[0]);
|
|
210
|
+
int mode = (int)xt_to_number(argv[1]);
|
|
211
|
+
if (!path || xt_fs_chmod_fn(path, mode) != 0) {
|
|
212
|
+
xt_fs_raise_path("chmod", path);
|
|
213
|
+
return xt_undefined();
|
|
214
|
+
}
|
|
215
|
+
return xt_undefined();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
xt_value xt_node_chown(int32_t argc, xt_value *argv) {
|
|
219
|
+
if (argc < 3) return xt_undefined();
|
|
220
|
+
const char *path = xt_node_cstr(argv[0]);
|
|
221
|
+
int uid = (int)xt_to_number(argv[1]);
|
|
222
|
+
int gid = (int)xt_to_number(argv[2]);
|
|
223
|
+
#if defined(_WIN32)
|
|
224
|
+
(void)path;
|
|
225
|
+
(void)uid;
|
|
226
|
+
(void)gid;
|
|
227
|
+
return xt_undefined();
|
|
228
|
+
#else
|
|
229
|
+
if (!path || chown(path, (uid_t)uid, (gid_t)gid) != 0) {
|
|
230
|
+
xt_fs_raise_path("chown", path);
|
|
231
|
+
return xt_undefined();
|
|
232
|
+
}
|
|
233
|
+
return xt_undefined();
|
|
234
|
+
#endif
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
xt_value xt_node_lchown(int32_t argc, xt_value *argv) {
|
|
238
|
+
if (argc < 3) return xt_undefined();
|
|
239
|
+
const char *path = xt_node_cstr(argv[0]);
|
|
240
|
+
int uid = (int)xt_to_number(argv[1]);
|
|
241
|
+
int gid = (int)xt_to_number(argv[2]);
|
|
242
|
+
#if defined(_WIN32)
|
|
243
|
+
(void)path;
|
|
244
|
+
(void)uid;
|
|
245
|
+
(void)gid;
|
|
246
|
+
return xt_undefined();
|
|
247
|
+
#else
|
|
248
|
+
if (!path || lchown(path, (uid_t)uid, (gid_t)gid) != 0) {
|
|
249
|
+
xt_fs_raise_path("lchown", path);
|
|
250
|
+
return xt_undefined();
|
|
251
|
+
}
|
|
252
|
+
return xt_undefined();
|
|
253
|
+
#endif
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/* Windows has no `lchmod`; Node ignores the call there. */
|
|
257
|
+
xt_value xt_node_lchmod(int32_t argc, xt_value *argv) {
|
|
258
|
+
#if defined(_WIN32)
|
|
259
|
+
(void)argc;
|
|
260
|
+
(void)argv;
|
|
261
|
+
return xt_undefined();
|
|
262
|
+
#else
|
|
263
|
+
return xt_node_chmod(argc, argv);
|
|
264
|
+
#endif
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/* ------------------------------------------------------------------------- */
|
|
268
|
+
/* truncateSync */
|
|
269
|
+
/* ------------------------------------------------------------------------- */
|
|
270
|
+
|
|
271
|
+
xt_value xt_node_truncate(int32_t argc, xt_value *argv) {
|
|
272
|
+
if (argc < 1) return xt_undefined();
|
|
273
|
+
const char *path = xt_node_cstr(argv[0]);
|
|
274
|
+
long long length = argc > 1 ? (long long)xt_to_number(argv[1]) : 0;
|
|
275
|
+
if (!path || xt_fs_truncate_path(path, length) != 0) {
|
|
276
|
+
xt_fs_raise_path("truncate", path);
|
|
277
|
+
return xt_undefined();
|
|
278
|
+
}
|
|
279
|
+
return xt_undefined();
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* ------------------------------------------------------------------------- */
|
|
283
|
+
/* utimesSync / lutimesSync */
|
|
284
|
+
/* ------------------------------------------------------------------------- */
|
|
285
|
+
|
|
286
|
+
xt_value xt_node_utimes(int32_t argc, xt_value *argv) {
|
|
287
|
+
if (argc < 3) return xt_undefined();
|
|
288
|
+
const char *path = xt_node_cstr(argv[0]);
|
|
289
|
+
double atime = xt_fs_time_seconds(argv[1]);
|
|
290
|
+
double mtime = xt_fs_time_seconds(argv[2]);
|
|
291
|
+
#if defined(_WIN32)
|
|
292
|
+
HANDLE handle = path ? CreateFileA(path, FILE_WRITE_ATTRIBUTES,
|
|
293
|
+
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
|
294
|
+
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL)
|
|
295
|
+
: INVALID_HANDLE_VALUE;
|
|
296
|
+
if (handle == INVALID_HANDLE_VALUE || xt_fs_set_file_times(handle, atime, mtime) != 0) {
|
|
297
|
+
if (handle != INVALID_HANDLE_VALUE) CloseHandle(handle);
|
|
298
|
+
xt_fs_raise_path("utime", path);
|
|
299
|
+
return xt_undefined();
|
|
300
|
+
}
|
|
301
|
+
CloseHandle(handle);
|
|
302
|
+
return xt_undefined();
|
|
303
|
+
#else
|
|
304
|
+
struct timeval times[2];
|
|
305
|
+
times[0].tv_sec = (time_t)atime;
|
|
306
|
+
times[0].tv_usec = (suseconds_t)((atime - (double)times[0].tv_sec) * 1000000.0);
|
|
307
|
+
times[1].tv_sec = (time_t)mtime;
|
|
308
|
+
times[1].tv_usec = (suseconds_t)((mtime - (double)times[1].tv_sec) * 1000000.0);
|
|
309
|
+
if (!path || utimes(path, times) != 0) {
|
|
310
|
+
xt_fs_raise_path("utimes", path);
|
|
311
|
+
return xt_undefined();
|
|
312
|
+
}
|
|
313
|
+
return xt_undefined();
|
|
314
|
+
#endif
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
xt_value xt_node_lutimes(int32_t argc, xt_value *argv) {
|
|
318
|
+
#if defined(__linux__)
|
|
319
|
+
if (argc < 3) return xt_undefined();
|
|
320
|
+
const char *path = xt_node_cstr(argv[0]);
|
|
321
|
+
double atime = xt_fs_time_seconds(argv[1]);
|
|
322
|
+
double mtime = xt_fs_time_seconds(argv[2]);
|
|
323
|
+
struct timeval times[2];
|
|
324
|
+
times[0].tv_sec = (time_t)atime;
|
|
325
|
+
times[0].tv_usec = (suseconds_t)((atime - (double)times[0].tv_sec) * 1000000.0);
|
|
326
|
+
times[1].tv_sec = (time_t)mtime;
|
|
327
|
+
times[1].tv_usec = (suseconds_t)((mtime - (double)times[1].tv_sec) * 1000000.0);
|
|
328
|
+
if (!path || lutimes(path, times) != 0) {
|
|
329
|
+
xt_fs_raise_path("lutimes", path);
|
|
330
|
+
return xt_undefined();
|
|
331
|
+
}
|
|
332
|
+
return xt_undefined();
|
|
333
|
+
#else
|
|
334
|
+
/* macOS and Windows have no `lutimes`; fall back to `utimes`. */
|
|
335
|
+
return xt_node_utimes(argc, argv);
|
|
336
|
+
#endif
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/* ------------------------------------------------------------------------- */
|
|
340
|
+
/* statfsSync */
|
|
341
|
+
/* ------------------------------------------------------------------------- */
|
|
342
|
+
|
|
343
|
+
xt_value xt_node_statfs(int32_t argc, xt_value *argv) {
|
|
344
|
+
xt_value object = xt_object_new();
|
|
345
|
+
#if defined(_WIN32) || defined(_AIX) || defined(__sun)
|
|
346
|
+
(void)argc;
|
|
347
|
+
(void)argv;
|
|
348
|
+
xt_object_set(object, xt_string_from_cstr("type"), xt_number(0));
|
|
349
|
+
xt_object_set(object, xt_string_from_cstr("bsize"), xt_number(0));
|
|
350
|
+
xt_object_set(object, xt_string_from_cstr("blocks"), xt_number(0));
|
|
351
|
+
xt_object_set(object, xt_string_from_cstr("bfree"), xt_number(0));
|
|
352
|
+
xt_object_set(object, xt_string_from_cstr("bavail"), xt_number(0));
|
|
353
|
+
xt_object_set(object, xt_string_from_cstr("files"), xt_number(0));
|
|
354
|
+
xt_object_set(object, xt_string_from_cstr("ffree"), xt_number(0));
|
|
355
|
+
#else
|
|
356
|
+
const char *path = argc > 0 ? xt_node_cstr(argv[0]) : NULL;
|
|
357
|
+
struct statfs info;
|
|
358
|
+
if (!path || statfs(path, &info) != 0) {
|
|
359
|
+
xt_fs_raise_path("statfs", path);
|
|
360
|
+
return xt_undefined();
|
|
361
|
+
}
|
|
362
|
+
xt_object_set(object, xt_string_from_cstr("type"), xt_number((double)info.f_type));
|
|
363
|
+
xt_object_set(object, xt_string_from_cstr("bsize"), xt_number((double)info.f_bsize));
|
|
364
|
+
xt_object_set(object, xt_string_from_cstr("blocks"), xt_number((double)info.f_blocks));
|
|
365
|
+
xt_object_set(object, xt_string_from_cstr("bfree"), xt_number((double)info.f_bfree));
|
|
366
|
+
xt_object_set(object, xt_string_from_cstr("bavail"), xt_number((double)info.f_bavail));
|
|
367
|
+
xt_object_set(object, xt_string_from_cstr("files"), xt_number((double)info.f_files));
|
|
368
|
+
xt_object_set(object, xt_string_from_cstr("ffree"), xt_number((double)info.f_ffree));
|
|
369
|
+
#endif
|
|
370
|
+
return object;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/* ------------------------------------------------------------------------- */
|
|
374
|
+
/* mkdtempSync */
|
|
375
|
+
/* ------------------------------------------------------------------------- */
|
|
376
|
+
|
|
377
|
+
xt_value xt_node_mkdtemp(int32_t argc, xt_value *argv) {
|
|
378
|
+
if (argc < 1) return xt_undefined();
|
|
379
|
+
const char *prefix = xt_node_cstr(argv[0]);
|
|
380
|
+
if (!prefix) {
|
|
381
|
+
xt_fs_raise_errno(EINVAL, "mkdtemp", NULL);
|
|
382
|
+
return xt_undefined();
|
|
383
|
+
}
|
|
384
|
+
size_t length = strlen(prefix);
|
|
385
|
+
char *dir = (char *)malloc(length + 7);
|
|
386
|
+
if (!dir) return xt_undefined();
|
|
387
|
+
memcpy(dir, prefix, length);
|
|
388
|
+
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
389
|
+
for (int attempt = 0; attempt < 100; attempt++) {
|
|
390
|
+
unsigned int seed = (unsigned int)(time(NULL) ^ (attempt * 2654435761u));
|
|
391
|
+
for (int i = 0; i < 6; i++) dir[length + i] = alphabet[seed % 36u], seed = seed * 1103515245u + 12345u;
|
|
392
|
+
dir[length + 6] = '\0';
|
|
393
|
+
if (xt_fs_mkdir_one(dir) == 0) {
|
|
394
|
+
xt_value result = xt_string_from_cstr(dir);
|
|
395
|
+
free(dir);
|
|
396
|
+
return result;
|
|
397
|
+
}
|
|
398
|
+
if (errno != EEXIST) break;
|
|
399
|
+
}
|
|
400
|
+
free(dir);
|
|
401
|
+
xt_fs_raise_path("mkdtemp", prefix);
|
|
402
|
+
return xt_undefined();
|
|
403
|
+
}
|