xbintsc 0.5.20 → 0.5.21
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/AGENTS.md +5 -3
- package/dist/src/driver/compiler.js +1 -1
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/runtime-objects.d.ts +1 -1
- package/dist/src/driver/runtime-objects.js +1 -0
- package/dist/src/driver/runtime-objects.js.map +1 -1
- package/dist/src/driver/version.d.ts +1 -1
- package/dist/src/driver/version.js +1 -1
- package/dist/src/extensions/node/fs/index.d.ts +4 -3
- package/dist/src/extensions/node/fs/index.js +12 -3
- package/dist/src/extensions/node/fs/index.js.map +1 -1
- package/dist/src/extensions/node/fs-promises/index.d.ts +5 -5
- package/dist/src/extensions/node/fs-promises/index.js +15 -6
- package/dist/src/extensions/node/fs-promises/index.js.map +1 -1
- package/dist/tests/e2e/async-await.test.js +1 -1
- package/dist/tests/e2e/async-fs.test.d.ts +9 -0
- package/dist/tests/e2e/async-fs.test.js +119 -0
- package/dist/tests/e2e/async-fs.test.js.map +1 -0
- package/dist/tests/e2e/fetch.test.js +24 -0
- package/dist/tests/e2e/fetch.test.js.map +1 -1
- package/dist/tests/e2e/gui-inline-svg.test.d.ts +11 -0
- package/dist/tests/e2e/gui-inline-svg.test.js +160 -0
- package/dist/tests/e2e/gui-inline-svg.test.js.map +1 -0
- package/doc/ai/contributing.md +2 -1
- package/doc/ai/extensions.md +4 -3
- package/doc/ai/language-support.md +2 -1
- package/doc/ai/zh-CN/contributing.md +1 -1
- package/doc/ai/zh-CN/extensions.md +4 -3
- package/doc/ai/zh-CN/language-support.md +2 -1
- package/doc/gui/api.md +8 -0
- package/doc/gui/known-issues.md +10 -9
- package/doc/gui/media.md +32 -3
- package/doc/gui.md +24 -2
- package/doc/implemented/async.md +16 -3
- package/doc/implemented/fetch.md +38 -6
- package/doc/implemented/node/fs-promises.md +19 -8
- package/doc/implemented/node.md +1 -1
- package/doc/implemented.md +1 -1
- package/doc/unimplemented/deviations.md +1 -1
- package/doc/unimplemented/node/async.md +6 -3
- package/doc/unimplemented/node/fs-promises.md +10 -6
- package/doc/unimplemented/node/fs.md +7 -8
- package/doc/unimplemented/node.md +2 -2
- package/doc/unimplemented/toolchain.md +1 -1
- package/doc/zh-CN/gui/api.md +7 -0
- package/doc/zh-CN/gui/known-issues.md +8 -7
- package/doc/zh-CN/gui/media.md +26 -2
- package/doc/zh-CN/gui.md +18 -1
- package/doc/zh-CN/implemented/async.md +13 -2
- package/doc/zh-CN/implemented/fetch.md +23 -4
- package/doc/zh-CN/implemented/node/fs-promises.md +6 -3
- package/doc/zh-CN/implemented/node.md +1 -1
- package/doc/zh-CN/implemented.md +1 -1
- package/doc/zh-CN/unimplemented/deviations.md +1 -1
- package/doc/zh-CN/unimplemented/node/async.md +6 -3
- package/doc/zh-CN/unimplemented/node/fs-promises.md +4 -4
- package/doc/zh-CN/unimplemented/node/fs.md +2 -2
- package/doc/zh-CN/unimplemented/node.md +2 -2
- package/doc/zh-CN/unimplemented/toolchain.md +1 -1
- package/package.json +1 -1
- package/runtime/ext_gui/inline_svg.cpp +219 -0
- package/runtime/ext_gui/inline_svg.h +41 -0
- package/runtime/ext_gui/layout.cpp +18 -0
- package/runtime/ext_gui/layout.h +7 -0
- package/runtime/ext_gui/layout_flow.cpp +4 -3
- package/runtime/ext_gui/paint.cpp +14 -0
- package/runtime/ext_gui/paint.h +5 -1
- package/runtime/ext_gui/renderer_image.cpp +53 -25
- package/runtime/ext_gui/style_ua.cpp +3 -0
- package/runtime/ext_gui/svg.cpp +122 -39
- package/runtime/ext_gui/svg.h +14 -3
- package/runtime/ext_gui/window.cpp +28 -0
- package/runtime/ext_node/fs/async_api.c +314 -0
- package/runtime/ext_node/fs/async_complete.c +99 -0
- package/runtime/ext_node/fs/async_fh.c +206 -0
- package/runtime/ext_node/fs/async_job.c +81 -0
- package/runtime/ext_node/fs/async_job.h +132 -0
- package/runtime/ext_node/fs/async_worker.c +534 -0
- package/runtime/ext_node/fs/async_worker_dir.c +439 -0
- package/runtime/ext_node/fs/async_worker_dir.h +33 -0
- package/runtime/ext_node/fs/async_worker_fd.c +74 -0
- package/runtime/ext_node/fs/dir.c +60 -15
- package/runtime/ext_node/fs/fs_common.h +9 -0
- package/runtime/ext_node/fs/fs_ops.c +18 -29
- package/runtime/ext_node/fs/parts/builtins.inc +34 -0
- package/runtime/ext_node/fs/parts/platform.inc +66 -0
- package/runtime/ext_node/fs/promises.c +44 -234
- package/runtime/rt_internal.h +2 -0
- package/runtime/xt_async_io.c +333 -0
- package/runtime/xt_async_io.h +47 -0
- package/runtime/xt_fetch/async.inc +295 -0
- package/runtime/xt_fetch/request.inc +6 -183
- package/runtime/xt_fetch/socket.inc +5 -4
- package/runtime/xt_fetch.c +6 -4
- package/runtime/xt_loop.c +44 -3
- package/src/driver/compiler.ts +1 -1
- package/src/driver/runtime-objects.ts +1 -0
- package/src/driver/version.ts +1 -1
- package/src/extensions/node/fs/index.ts +12 -3
- package/src/extensions/node/fs-promises/index.ts +15 -6
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Worker half of `fs/promises`: the blocking syscalls.
|
|
3
|
+
*
|
|
4
|
+
* Everything in this file runs on an async I/O worker thread. It may only touch
|
|
5
|
+
* plain C memory — no `xt_value`, no collector, no exceptions. Results are
|
|
6
|
+
* stored on the job and interpreted by async_complete.c on the main thread.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include "async_job.h"
|
|
10
|
+
#include "async_worker_dir.h"
|
|
11
|
+
|
|
12
|
+
#include <errno.h>
|
|
13
|
+
#include <stdio.h>
|
|
14
|
+
#include <time.h>
|
|
15
|
+
|
|
16
|
+
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
|
17
|
+
#include <sys/mount.h>
|
|
18
|
+
#elif defined(__linux__)
|
|
19
|
+
#include <sys/vfs.h>
|
|
20
|
+
#endif
|
|
21
|
+
|
|
22
|
+
#if defined(_WIN32)
|
|
23
|
+
#include <io.h>
|
|
24
|
+
#include <windows.h>
|
|
25
|
+
#define xt_fs_fstat_fn xt_fs_win_fstat
|
|
26
|
+
#else
|
|
27
|
+
#include <fcntl.h>
|
|
28
|
+
#include <sys/time.h>
|
|
29
|
+
#include <unistd.h>
|
|
30
|
+
#define xt_fs_fstat_fn fstat
|
|
31
|
+
#endif
|
|
32
|
+
|
|
33
|
+
/* -- small file helpers ---------------------------------------------------- */
|
|
34
|
+
|
|
35
|
+
int xt_fs_worker_read_fd(int fd, unsigned char **out, size_t *out_length) {
|
|
36
|
+
size_t capacity = 8192;
|
|
37
|
+
size_t length = 0;
|
|
38
|
+
unsigned char *bytes = (unsigned char *)malloc(capacity);
|
|
39
|
+
if (!bytes) return -1;
|
|
40
|
+
for (;;) {
|
|
41
|
+
if (length == capacity) {
|
|
42
|
+
capacity *= 2;
|
|
43
|
+
unsigned char *grown = (unsigned char *)realloc(bytes, capacity);
|
|
44
|
+
if (!grown) {
|
|
45
|
+
free(bytes);
|
|
46
|
+
return -1;
|
|
47
|
+
}
|
|
48
|
+
bytes = grown;
|
|
49
|
+
}
|
|
50
|
+
ssize_t count = XT_FS_READ(fd, bytes + length, capacity - length);
|
|
51
|
+
if (count < 0) {
|
|
52
|
+
int saved = errno;
|
|
53
|
+
free(bytes);
|
|
54
|
+
errno = saved;
|
|
55
|
+
return -1;
|
|
56
|
+
}
|
|
57
|
+
if (count == 0) break;
|
|
58
|
+
length += (size_t)count;
|
|
59
|
+
}
|
|
60
|
+
*out = bytes;
|
|
61
|
+
*out_length = length;
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
int xt_fs_worker_read_file(const char *path, unsigned char **out, size_t *out_length) {
|
|
66
|
+
int fd = XT_FS_OPEN(path, XT_FS_RDONLY | XT_FS_BINARY_FLAG, 0);
|
|
67
|
+
if (fd < 0) return -1;
|
|
68
|
+
int status = xt_fs_worker_read_fd(fd, out, out_length);
|
|
69
|
+
int saved = errno;
|
|
70
|
+
XT_FS_CLOSE(fd);
|
|
71
|
+
errno = saved;
|
|
72
|
+
return status;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
int xt_fs_worker_write_fd(int fd, const unsigned char *data, size_t length) {
|
|
76
|
+
size_t written = 0;
|
|
77
|
+
while (written < length) {
|
|
78
|
+
ssize_t count = XT_FS_WRITE(fd, data + written, length - written);
|
|
79
|
+
if (count <= 0) return -1;
|
|
80
|
+
written += (size_t)count;
|
|
81
|
+
}
|
|
82
|
+
return 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
int xt_fs_worker_write_file(const char *path, const unsigned char *data, size_t length, int append) {
|
|
86
|
+
int flags = XT_FS_WRONLY | XT_FS_CREAT | XT_FS_BINARY_FLAG | (append ? XT_FS_APPEND : XT_FS_TRUNC);
|
|
87
|
+
int fd = XT_FS_OPEN(path, flags, 0666);
|
|
88
|
+
if (fd < 0) return -1;
|
|
89
|
+
int status = xt_fs_worker_write_fd(fd, data, length);
|
|
90
|
+
int saved = errno;
|
|
91
|
+
if (XT_FS_CLOSE(fd) != 0 && status == 0) {
|
|
92
|
+
status = -1;
|
|
93
|
+
saved = errno;
|
|
94
|
+
}
|
|
95
|
+
errno = saved;
|
|
96
|
+
return status;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
int xt_fs_entry_push(xt_fs_job *job, const char *name, const char *bare, unsigned int mode) {
|
|
100
|
+
xt_fs_entry *grown = (xt_fs_entry *)realloc(job->entries, sizeof(xt_fs_entry) * (job->entry_count + 1));
|
|
101
|
+
if (!grown) return -1;
|
|
102
|
+
job->entries = grown;
|
|
103
|
+
xt_fs_entry *entry = &job->entries[job->entry_count];
|
|
104
|
+
entry->name = xt_fs_copy_cstr(name);
|
|
105
|
+
entry->bare = bare && strcmp(bare, name) != 0 ? xt_fs_copy_cstr(bare) : entry->name;
|
|
106
|
+
entry->mode = mode;
|
|
107
|
+
if (!entry->name || !entry->bare) return -1;
|
|
108
|
+
job->entry_count++;
|
|
109
|
+
return 0;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
char *xt_fs_worker_join(const char *dir, const char *name) {
|
|
113
|
+
size_t dirLength = strlen(dir);
|
|
114
|
+
int needsSlash = dirLength > 0 && dir[dirLength - 1] != '/' && dir[dirLength - 1] != '\\';
|
|
115
|
+
size_t size = dirLength + (needsSlash ? 1 : 0) + strlen(name) + 1;
|
|
116
|
+
char *path = (char *)malloc(size);
|
|
117
|
+
if (!path) return NULL;
|
|
118
|
+
snprintf(path, size, "%s%s%s", dir, needsSlash ? "/" : "", name);
|
|
119
|
+
return path;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* -- path operations ------------------------------------------------------- */
|
|
123
|
+
|
|
124
|
+
static void xt_fs_worker_mkdir(xt_fs_job *job) {
|
|
125
|
+
if (!job->path) {
|
|
126
|
+
xt_fs_job_fail(job, EINVAL, "mkdir", NULL);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (!job->recursive) {
|
|
130
|
+
if (xt_fs_mkdir_mode(job->path, job->mode) != 0 && errno != EEXIST) {
|
|
131
|
+
xt_fs_job_fail(job, errno, "mkdir", job->path);
|
|
132
|
+
}
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (xt_fs_mkdir_parents(job->path, job->mode) != 0) {
|
|
136
|
+
xt_fs_job_fail(job, errno, "mkdir", job->path);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
static void xt_fs_worker_realpath(xt_fs_job *job) {
|
|
141
|
+
if (!job->path) {
|
|
142
|
+
xt_fs_job_fail(job, EINVAL, "resolve", NULL);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
#if defined(_WIN32)
|
|
146
|
+
char *resolved = _fullpath(NULL, job->path, 0);
|
|
147
|
+
#else
|
|
148
|
+
char *resolved = realpath(job->path, NULL);
|
|
149
|
+
#endif
|
|
150
|
+
if (!resolved) {
|
|
151
|
+
xt_fs_job_fail(job, errno, "resolve", job->path);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
job->string = resolved;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
static void xt_fs_worker_statfs(xt_fs_job *job) {
|
|
158
|
+
#if defined(_WIN32) || defined(_AIX) || defined(__sun)
|
|
159
|
+
(void)job;
|
|
160
|
+
for (int i = 0; i < 7; i++) job->numbers[i] = 0;
|
|
161
|
+
#else
|
|
162
|
+
if (!job->path) {
|
|
163
|
+
xt_fs_job_fail(job, EINVAL, "statfs", NULL);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
struct statfs info;
|
|
167
|
+
if (statfs(job->path, &info) != 0) {
|
|
168
|
+
xt_fs_job_fail(job, errno, "statfs", job->path);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
job->numbers[0] = (long long)info.f_type;
|
|
172
|
+
job->numbers[1] = (long long)info.f_bsize;
|
|
173
|
+
job->numbers[2] = (long long)info.f_blocks;
|
|
174
|
+
job->numbers[3] = (long long)info.f_bfree;
|
|
175
|
+
job->numbers[4] = (long long)info.f_bavail;
|
|
176
|
+
job->numbers[5] = (long long)info.f_files;
|
|
177
|
+
job->numbers[6] = (long long)info.f_ffree;
|
|
178
|
+
#endif
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
static void xt_fs_worker_mkdtemp(xt_fs_job *job) {
|
|
182
|
+
if (!job->path) {
|
|
183
|
+
xt_fs_job_fail(job, EINVAL, "mkdtemp", NULL);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
size_t length = strlen(job->path);
|
|
187
|
+
char *dir = (char *)malloc(length + 7);
|
|
188
|
+
if (!dir) {
|
|
189
|
+
xt_fs_job_fail(job, ENOMEM, "mkdtemp", job->path);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
memcpy(dir, job->path, length);
|
|
193
|
+
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
194
|
+
/* Concurrent mkdtemp jobs must not walk the same candidate sequence; mix in
|
|
195
|
+
* this job's allocation address, which differs per thread. */
|
|
196
|
+
unsigned int noise = (unsigned int)(uintptr_t)dir;
|
|
197
|
+
for (int attempt = 0; attempt < 100; attempt++) {
|
|
198
|
+
unsigned int seed = (unsigned int)time(NULL) ^ noise ^ (unsigned int)(attempt * 2654435761u);
|
|
199
|
+
for (int i = 0; i < 6; i++) {
|
|
200
|
+
dir[length + (size_t)i] = alphabet[seed % 36u];
|
|
201
|
+
seed = seed * 1103515245u + 12345u;
|
|
202
|
+
}
|
|
203
|
+
dir[length + 6] = '\0';
|
|
204
|
+
if (xt_fs_mkdir_one(dir) == 0) {
|
|
205
|
+
job->string = dir;
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (errno != EEXIST) break;
|
|
209
|
+
}
|
|
210
|
+
int saved = errno;
|
|
211
|
+
free(dir);
|
|
212
|
+
xt_fs_job_fail(job, saved, "mkdtemp", job->path);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
#if defined(_WIN32)
|
|
216
|
+
static void xt_fs_worker_filetime(double seconds, FILETIME *out) {
|
|
217
|
+
long long ticks = (long long)(seconds * 10000000.0) + 116444736000000000LL;
|
|
218
|
+
unsigned long long value = (unsigned long long)ticks;
|
|
219
|
+
out->dwLowDateTime = (DWORD)value;
|
|
220
|
+
out->dwHighDateTime = (DWORD)(value >> 32);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
static int xt_fs_worker_set_handle_times(HANDLE handle, double atime, double mtime) {
|
|
224
|
+
FILETIME accessTime;
|
|
225
|
+
FILETIME modifyTime;
|
|
226
|
+
FILETIME *accessPtr = NULL;
|
|
227
|
+
FILETIME *modifyPtr = NULL;
|
|
228
|
+
if (atime == atime) {
|
|
229
|
+
xt_fs_worker_filetime(atime, &accessTime);
|
|
230
|
+
accessPtr = &accessTime;
|
|
231
|
+
}
|
|
232
|
+
if (mtime == mtime) {
|
|
233
|
+
xt_fs_worker_filetime(mtime, &modifyTime);
|
|
234
|
+
modifyPtr = &modifyTime;
|
|
235
|
+
}
|
|
236
|
+
return SetFileTime(handle, NULL, accessPtr, modifyPtr) ? 0 : -1;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
static int xt_fs_worker_set_path_times(const char *path, double atime, double mtime) {
|
|
240
|
+
HANDLE handle = CreateFileA(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
241
|
+
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
|
242
|
+
if (handle == INVALID_HANDLE_VALUE) return -1;
|
|
243
|
+
int status = xt_fs_worker_set_handle_times(handle, atime, mtime);
|
|
244
|
+
int saved = errno;
|
|
245
|
+
CloseHandle(handle);
|
|
246
|
+
errno = saved;
|
|
247
|
+
return status;
|
|
248
|
+
}
|
|
249
|
+
#endif
|
|
250
|
+
|
|
251
|
+
static void xt_fs_worker_utimes(xt_fs_job *job, int follow) {
|
|
252
|
+
if (!job->path) {
|
|
253
|
+
xt_fs_job_fail(job, EINVAL, "utime", NULL);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
#if defined(_WIN32)
|
|
257
|
+
(void)follow;
|
|
258
|
+
if (xt_fs_worker_set_path_times(job->path, job->atime, job->mtime) != 0) {
|
|
259
|
+
xt_fs_job_fail(job, errno ? errno : EPERM, "utime", job->path);
|
|
260
|
+
}
|
|
261
|
+
#else
|
|
262
|
+
struct timeval times[2];
|
|
263
|
+
times[0].tv_sec = (time_t)job->atime;
|
|
264
|
+
times[0].tv_usec = (suseconds_t)((job->atime - (double)times[0].tv_sec) * 1000000.0);
|
|
265
|
+
times[1].tv_sec = (time_t)job->mtime;
|
|
266
|
+
times[1].tv_usec = (suseconds_t)((job->mtime - (double)times[1].tv_sec) * 1000000.0);
|
|
267
|
+
#if defined(__linux__)
|
|
268
|
+
int status = follow ? utimes(job->path, times) : lutimes(job->path, times);
|
|
269
|
+
#else
|
|
270
|
+
(void)follow;
|
|
271
|
+
int status = utimes(job->path, times);
|
|
272
|
+
#endif
|
|
273
|
+
if (status != 0) xt_fs_job_fail(job, errno, "utime", job->path);
|
|
274
|
+
#endif
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/* -- FileHandle operations ------------------------------------------------- */
|
|
278
|
+
|
|
279
|
+
static void xt_fs_worker_fd_utimes(xt_fs_job *job) {
|
|
280
|
+
#if defined(_WIN32)
|
|
281
|
+
intptr_t osHandle = _get_osfhandle(job->fd);
|
|
282
|
+
if (osHandle == -1 || xt_fs_worker_set_handle_times((HANDLE)osHandle, job->atime, job->mtime) != 0) {
|
|
283
|
+
xt_fs_job_fail(job, errno ? errno : EPERM, "futime", NULL);
|
|
284
|
+
}
|
|
285
|
+
#else
|
|
286
|
+
struct timeval times[2];
|
|
287
|
+
times[0].tv_sec = (time_t)job->atime;
|
|
288
|
+
times[0].tv_usec = (suseconds_t)((job->atime - (double)times[0].tv_sec) * 1000000.0);
|
|
289
|
+
times[1].tv_sec = (time_t)job->mtime;
|
|
290
|
+
times[1].tv_usec = (suseconds_t)((job->mtime - (double)times[1].tv_sec) * 1000000.0);
|
|
291
|
+
if (futimes(job->fd, times) != 0) xt_fs_job_fail(job, errno, "futime", NULL);
|
|
292
|
+
#endif
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/* -- dispatch -------------------------------------------------------------- */
|
|
296
|
+
|
|
297
|
+
void xt_fs_job_run(xt_async_job *base) {
|
|
298
|
+
xt_fs_job *job = (xt_fs_job *)base;
|
|
299
|
+
switch (job->kind) {
|
|
300
|
+
case XT_FS_JOB_READ_FILE:
|
|
301
|
+
if (!job->path) {
|
|
302
|
+
xt_fs_job_fail(job, EINVAL, "open", NULL);
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
if (xt_fs_worker_read_file(job->path, &job->bytes, &job->bytes_length) != 0) {
|
|
306
|
+
xt_fs_job_fail(job, errno, "open", job->path);
|
|
307
|
+
}
|
|
308
|
+
break;
|
|
309
|
+
case XT_FS_JOB_WRITE_FILE:
|
|
310
|
+
if (!job->path) {
|
|
311
|
+
xt_fs_job_fail(job, EINVAL, "open", NULL);
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
if (xt_fs_worker_write_file(job->path, job->data, job->data_length, job->flags != 0) != 0) {
|
|
315
|
+
xt_fs_job_fail(job, errno, "open", job->path);
|
|
316
|
+
}
|
|
317
|
+
break;
|
|
318
|
+
case XT_FS_JOB_MKDIR: xt_fs_worker_mkdir(job); break;
|
|
319
|
+
case XT_FS_JOB_READDIR: xt_fs_worker_readdir(job); break;
|
|
320
|
+
case XT_FS_JOB_RM: xt_fs_worker_remove_tree(job); break;
|
|
321
|
+
case XT_FS_JOB_UNLINK:
|
|
322
|
+
if (!job->path) {
|
|
323
|
+
xt_fs_job_fail(job, EINVAL, "unlink", NULL);
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
#if defined(_WIN32)
|
|
327
|
+
if (_unlink(job->path) != 0) xt_fs_job_fail(job, errno, "unlink", job->path);
|
|
328
|
+
#else
|
|
329
|
+
if (unlink(job->path) != 0) xt_fs_job_fail(job, errno, "unlink", job->path);
|
|
330
|
+
#endif
|
|
331
|
+
break;
|
|
332
|
+
case XT_FS_JOB_RMDIR:
|
|
333
|
+
if (!job->path || xt_fs_rmdir_one(job->path) != 0) xt_fs_job_fail(job, errno, "rmdir", job->path);
|
|
334
|
+
break;
|
|
335
|
+
case XT_FS_JOB_RENAME:
|
|
336
|
+
if (!job->path || !job->path2 || rename(job->path, job->path2) != 0) {
|
|
337
|
+
xt_fs_job_fail(job, errno, "rename", job->path);
|
|
338
|
+
}
|
|
339
|
+
break;
|
|
340
|
+
case XT_FS_JOB_COPY_FILE: xt_fs_worker_copy_file(job); break;
|
|
341
|
+
case XT_FS_JOB_CP: xt_fs_worker_copy_tree(job); break;
|
|
342
|
+
case XT_FS_JOB_REALPATH: xt_fs_worker_realpath(job); break;
|
|
343
|
+
case XT_FS_JOB_STAT:
|
|
344
|
+
case XT_FS_JOB_LSTAT:
|
|
345
|
+
if (!job->path) {
|
|
346
|
+
xt_fs_job_fail(job, EINVAL, "stat", NULL);
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
if ((job->kind == XT_FS_JOB_STAT ? xt_fs_stat_fn(job->path, &job->stat)
|
|
350
|
+
: xt_fs_lstat_fn(job->path, &job->stat)) != 0) {
|
|
351
|
+
xt_fs_job_fail(job, errno, "stat", job->path);
|
|
352
|
+
}
|
|
353
|
+
break;
|
|
354
|
+
case XT_FS_JOB_STATFS: xt_fs_worker_statfs(job); break;
|
|
355
|
+
case XT_FS_JOB_ACCESS:
|
|
356
|
+
if (!job->path || xt_fs_access(job->path, job->mode) != 0) xt_fs_job_fail(job, errno, "access", job->path);
|
|
357
|
+
break;
|
|
358
|
+
case XT_FS_JOB_OPEN:
|
|
359
|
+
if (!job->path) {
|
|
360
|
+
xt_fs_job_fail(job, EINVAL, "open", NULL);
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
#if defined(_WIN32)
|
|
364
|
+
job->result_fd = _open(job->path, job->flags, job->mode);
|
|
365
|
+
#else
|
|
366
|
+
job->result_fd = open(job->path, job->flags, (mode_t)job->mode);
|
|
367
|
+
#endif
|
|
368
|
+
if (job->result_fd < 0) xt_fs_job_fail(job, errno, "open", job->path);
|
|
369
|
+
break;
|
|
370
|
+
case XT_FS_JOB_CHMOD:
|
|
371
|
+
case XT_FS_JOB_LCHMOD:
|
|
372
|
+
#if defined(_WIN32)
|
|
373
|
+
if (job->kind == XT_FS_JOB_LCHMOD) break;
|
|
374
|
+
if (!job->path || _chmod(job->path, job->mode) != 0) xt_fs_job_fail(job, errno, "chmod", job->path);
|
|
375
|
+
#else
|
|
376
|
+
if (!job->path || chmod(job->path, (mode_t)job->mode) != 0) xt_fs_job_fail(job, errno, "chmod", job->path);
|
|
377
|
+
#endif
|
|
378
|
+
break;
|
|
379
|
+
case XT_FS_JOB_CHOWN:
|
|
380
|
+
case XT_FS_JOB_LCHOWN:
|
|
381
|
+
#if defined(_WIN32)
|
|
382
|
+
break;
|
|
383
|
+
#else
|
|
384
|
+
if (!job->path ||
|
|
385
|
+
(job->kind == XT_FS_JOB_CHOWN ? chown(job->path, (uid_t)job->uid, (gid_t)job->gid)
|
|
386
|
+
: lchown(job->path, (uid_t)job->uid, (gid_t)job->gid)) != 0) {
|
|
387
|
+
xt_fs_job_fail(job, errno, "chown", job->path);
|
|
388
|
+
}
|
|
389
|
+
break;
|
|
390
|
+
#endif
|
|
391
|
+
case XT_FS_JOB_TRUNCATE:
|
|
392
|
+
if (!job->path) {
|
|
393
|
+
xt_fs_job_fail(job, EINVAL, "truncate", NULL);
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
396
|
+
#if defined(_WIN32)
|
|
397
|
+
{
|
|
398
|
+
int fd = _open(job->path, _O_RDWR | _O_BINARY);
|
|
399
|
+
int status = fd < 0 ? -1 : _chsize_s(fd, job->length);
|
|
400
|
+
int saved = errno;
|
|
401
|
+
if (fd >= 0) _close(fd);
|
|
402
|
+
if (status != 0) xt_fs_job_fail(job, saved, "truncate", job->path);
|
|
403
|
+
}
|
|
404
|
+
#else
|
|
405
|
+
if (truncate(job->path, (off_t)job->length) != 0) xt_fs_job_fail(job, errno, "truncate", job->path);
|
|
406
|
+
#endif
|
|
407
|
+
break;
|
|
408
|
+
case XT_FS_JOB_UTIMES: xt_fs_worker_utimes(job, 1); break;
|
|
409
|
+
case XT_FS_JOB_LUTIMES: xt_fs_worker_utimes(job, 0); break;
|
|
410
|
+
case XT_FS_JOB_LINK:
|
|
411
|
+
#if defined(_WIN32)
|
|
412
|
+
if (!job->path || !job->path2 || !CreateHardLinkA(job->path2, job->path, NULL)) {
|
|
413
|
+
xt_fs_job_fail(job, errno ? errno : EPERM, "link", job->path2);
|
|
414
|
+
}
|
|
415
|
+
#else
|
|
416
|
+
if (!job->path || !job->path2 || link(job->path, job->path2) != 0) {
|
|
417
|
+
xt_fs_job_fail(job, errno, "link", job->path2);
|
|
418
|
+
}
|
|
419
|
+
#endif
|
|
420
|
+
break;
|
|
421
|
+
case XT_FS_JOB_SYMLINK:
|
|
422
|
+
#if defined(_WIN32)
|
|
423
|
+
{
|
|
424
|
+
DWORD flags = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
|
|
425
|
+
if (job->text && (strcmp(job->text, "dir") == 0 || strcmp(job->text, "junction") == 0)) {
|
|
426
|
+
flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
|
|
427
|
+
}
|
|
428
|
+
if (!job->path || !job->path2 || !CreateSymbolicLinkA(job->path2, job->path, flags)) {
|
|
429
|
+
xt_fs_job_fail(job, errno ? errno : EPERM, "symlink", job->path2);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
#else
|
|
433
|
+
if (!job->path || !job->path2 || symlink(job->path, job->path2) != 0) {
|
|
434
|
+
xt_fs_job_fail(job, errno, "symlink", job->path2);
|
|
435
|
+
}
|
|
436
|
+
#endif
|
|
437
|
+
break;
|
|
438
|
+
case XT_FS_JOB_READLINK:
|
|
439
|
+
#if defined(_WIN32)
|
|
440
|
+
xt_fs_job_fail(job, ENOSYS, "readlink", job->path);
|
|
441
|
+
#else
|
|
442
|
+
if (!job->path) {
|
|
443
|
+
xt_fs_job_fail(job, ENOENT, "readlink", NULL);
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
{
|
|
447
|
+
size_t capacity = 256;
|
|
448
|
+
for (;;) {
|
|
449
|
+
char *buffer = (char *)malloc(capacity);
|
|
450
|
+
if (!buffer) {
|
|
451
|
+
xt_fs_job_fail(job, ENOMEM, "readlink", job->path);
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
ssize_t length = readlink(job->path, buffer, capacity);
|
|
455
|
+
if (length < 0) {
|
|
456
|
+
int saved = errno;
|
|
457
|
+
free(buffer);
|
|
458
|
+
xt_fs_job_fail(job, saved, "readlink", job->path);
|
|
459
|
+
break;
|
|
460
|
+
}
|
|
461
|
+
if ((size_t)length < capacity) {
|
|
462
|
+
buffer[length] = '\0';
|
|
463
|
+
job->string = buffer;
|
|
464
|
+
break;
|
|
465
|
+
}
|
|
466
|
+
free(buffer);
|
|
467
|
+
capacity *= 2;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
#endif
|
|
471
|
+
break;
|
|
472
|
+
case XT_FS_JOB_MKDTEMP: xt_fs_worker_mkdtemp(job); break;
|
|
473
|
+
case XT_FS_JOB_OPENDIR: xt_fs_worker_opendir(job); break;
|
|
474
|
+
case XT_FS_JOB_GLOB: xt_fs_worker_glob(job); break;
|
|
475
|
+
case XT_FS_JOB_FD_READ: xt_fs_worker_fd_read(job); break;
|
|
476
|
+
case XT_FS_JOB_FD_WRITE: xt_fs_worker_fd_write(job); break;
|
|
477
|
+
case XT_FS_JOB_FD_READ_FILE:
|
|
478
|
+
if (xt_fs_worker_read_fd(job->fd, &job->bytes, &job->bytes_length) != 0) {
|
|
479
|
+
xt_fs_job_fail(job, errno, "read", NULL);
|
|
480
|
+
}
|
|
481
|
+
break;
|
|
482
|
+
case XT_FS_JOB_FD_WRITE_FILE:
|
|
483
|
+
if (xt_fs_worker_write_fd(job->fd, job->data, job->data_length) != 0) {
|
|
484
|
+
xt_fs_job_fail(job, errno, "write", NULL);
|
|
485
|
+
}
|
|
486
|
+
break;
|
|
487
|
+
case XT_FS_JOB_FD_CLOSE:
|
|
488
|
+
if (XT_FS_CLOSE(job->fd) != 0) xt_fs_job_fail(job, errno, "close", NULL);
|
|
489
|
+
break;
|
|
490
|
+
case XT_FS_JOB_FD_STAT:
|
|
491
|
+
if (xt_fs_fstat_fn(job->fd, &job->stat) != 0) xt_fs_job_fail(job, errno, "fstat", NULL);
|
|
492
|
+
break;
|
|
493
|
+
case XT_FS_JOB_FD_TRUNCATE:
|
|
494
|
+
#if defined(_WIN32)
|
|
495
|
+
if (_chsize_s(job->fd, job->length) != 0) xt_fs_job_fail(job, errno, "ftruncate", NULL);
|
|
496
|
+
#else
|
|
497
|
+
if (ftruncate(job->fd, (off_t)job->length) != 0) xt_fs_job_fail(job, errno, "ftruncate", NULL);
|
|
498
|
+
#endif
|
|
499
|
+
break;
|
|
500
|
+
case XT_FS_JOB_FD_CHMOD:
|
|
501
|
+
#if defined(_WIN32)
|
|
502
|
+
break;
|
|
503
|
+
#else
|
|
504
|
+
if (fchmod(job->fd, (mode_t)job->mode) != 0) xt_fs_job_fail(job, errno, "fchmod", NULL);
|
|
505
|
+
#endif
|
|
506
|
+
break;
|
|
507
|
+
case XT_FS_JOB_FD_CHOWN:
|
|
508
|
+
#if defined(_WIN32)
|
|
509
|
+
break;
|
|
510
|
+
#else
|
|
511
|
+
if (fchown(job->fd, (uid_t)job->uid, (gid_t)job->gid) != 0) xt_fs_job_fail(job, errno, "fchown", NULL);
|
|
512
|
+
#endif
|
|
513
|
+
break;
|
|
514
|
+
case XT_FS_JOB_FD_UTIMES: xt_fs_worker_fd_utimes(job); break;
|
|
515
|
+
case XT_FS_JOB_FD_SYNC:
|
|
516
|
+
#if defined(_WIN32)
|
|
517
|
+
if (_commit(job->fd) != 0) xt_fs_job_fail(job, errno, "fsync", NULL);
|
|
518
|
+
#else
|
|
519
|
+
if (fsync(job->fd) != 0) xt_fs_job_fail(job, errno, "fsync", NULL);
|
|
520
|
+
#endif
|
|
521
|
+
break;
|
|
522
|
+
case XT_FS_JOB_FD_DATASYNC:
|
|
523
|
+
#if defined(_WIN32)
|
|
524
|
+
if (_commit(job->fd) != 0) xt_fs_job_fail(job, errno, "fdatasync", NULL);
|
|
525
|
+
#else
|
|
526
|
+
#if defined(__APPLE__)
|
|
527
|
+
if (fsync(job->fd) != 0) xt_fs_job_fail(job, errno, "fdatasync", NULL);
|
|
528
|
+
#else
|
|
529
|
+
if (fdatasync(job->fd) != 0) xt_fs_job_fail(job, errno, "fdatasync", NULL);
|
|
530
|
+
#endif
|
|
531
|
+
#endif
|
|
532
|
+
break;
|
|
533
|
+
}
|
|
534
|
+
}
|