@scriptc/cli-darwin-x64 0.2.2 → 0.2.3
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/dist/THIRD_PARTY_NOTICES +1 -1
- package/dist/bin/scriptc +0 -0
- package/dist/bin/scriptc.json +1 -1
- package/dist/lib/declarations/scriptc-node-fallback.d.ts +99 -27
- package/dist/lib/llvm/bin/scriptc-llvm-codegen +0 -0
- package/dist/lib/llvm/package.json +1 -1
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_async.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_events.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_file_handle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_util_style.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_async.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_events.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_file_handle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_island.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_util_style.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_web.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_async.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_events.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_file_handle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_util_style.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_async.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_events.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_file_handle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_island.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_util_style.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_web.o +0 -0
- package/dist/lib/runtime-darwin-x64/package.json +1 -1
- package/dist/lib/runtime-darwin-x64/runtime-pack.json +351 -225
- package/dist/lib/runtime-sources/package.json +1 -1
- package/dist/lib/runtime-sources/src/scr_array.c +5 -0
- package/dist/lib/runtime-sources/src/scr_assert.c +26 -0
- package/dist/lib/runtime-sources/src/scr_async.c +44 -0
- package/dist/lib/runtime-sources/src/scr_bytes_io.c +305 -48
- package/dist/lib/runtime-sources/src/scr_events.c +9 -0
- package/dist/lib/runtime-sources/src/scr_exception.c +1 -0
- package/dist/lib/runtime-sources/src/scr_file_handle.c +11 -0
- package/dist/lib/runtime-sources/src/scr_island.c +1001 -417
- package/dist/lib/runtime-sources/src/scr_island_manifest.h +11 -7
- package/dist/lib/runtime-sources/src/scr_json.c +135 -2
- package/dist/lib/runtime-sources/src/scr_lib.c +379 -12
- package/dist/lib/runtime-sources/src/scr_map.c +8 -0
- package/dist/lib/runtime-sources/src/scr_node_builtin.c +78 -0
- package/dist/lib/runtime-sources/src/scr_regex.c +65 -0
- package/dist/lib/runtime-sources/src/scr_runtime.h +69 -1
- package/dist/lib/runtime-sources/src/scr_symbol.c +5 -0
- package/dist/lib/runtime-sources/src/scr_system_errors.h +573 -0
- package/dist/lib/runtime-sources/src/scr_url.c +515 -59
- package/dist/lib/runtime-sources/src/scr_url_internal.h +6 -0
- package/dist/lib/runtime-sources/src/scr_url_params.c +10 -0
- package/dist/lib/runtime-sources/src/scr_util_compare.c +222 -0
- package/dist/lib/runtime-sources/src/scr_util_style.c +337 -0
- package/dist/lib/runtime-sources/src/scr_web.c +720 -238
- package/package.json +1 -1
|
@@ -27,6 +27,13 @@
|
|
|
27
27
|
#include <stdlib.h>
|
|
28
28
|
#include <string.h>
|
|
29
29
|
#include <sys/stat.h>
|
|
30
|
+
#if defined(__linux__)
|
|
31
|
+
#include <sys/vfs.h>
|
|
32
|
+
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
|
33
|
+
#include <sys/mount.h>
|
|
34
|
+
#elif !defined(_WIN32) && !defined(__wasi__)
|
|
35
|
+
#include <sys/statvfs.h>
|
|
36
|
+
#endif
|
|
30
37
|
#include <time.h>
|
|
31
38
|
|
|
32
39
|
#ifdef _WIN32
|
|
@@ -55,6 +62,8 @@
|
|
|
55
62
|
|
|
56
63
|
static WCHAR *scr_fs_win_wide(const ScrStr *path);
|
|
57
64
|
static int scr_fs_win_errno(DWORD error);
|
|
65
|
+
static bool scr_stats_is_link_tag(DWORD tag);
|
|
66
|
+
static bool scr_stats_link_target(HANDLE h, DWORD tag, double *size_out, ScrStr **text_out);
|
|
58
67
|
|
|
59
68
|
static ScrStr *scr_fs_win_utf8(const WCHAR *text, size_t length) {
|
|
60
69
|
if (length > INT_MAX) { SetLastError(ERROR_FILENAME_EXCED_RANGE); return NULL; }
|
|
@@ -869,10 +878,12 @@ ScrDyn *scr_util_parse_env(const ScrDyn *content) {
|
|
|
869
878
|
return scr_env_parse_content(content->v.str, true);
|
|
870
879
|
}
|
|
871
880
|
|
|
872
|
-
|
|
881
|
+
void scr_fs_invalid_named_path(const ScrDyn *value, const ScrStr *path, const char *name) {
|
|
873
882
|
ScrJsonBuf b;
|
|
874
883
|
scr_jb_init(&b);
|
|
875
|
-
scr_jb_puts(&b, "The argument '
|
|
884
|
+
scr_jb_puts(&b, "The argument '");
|
|
885
|
+
scr_jb_puts(&b, name);
|
|
886
|
+
scr_jb_puts(&b, "' must be a string, Uint8Array, or URL without null bytes. Received ");
|
|
876
887
|
if (value->kind == SCR_DYN_BYTES) {
|
|
877
888
|
const ScrBytes *bytes = value->v.bytes;
|
|
878
889
|
if (value->buffer) {
|
|
@@ -916,6 +927,10 @@ static void scr_env_invalid_path(const ScrDyn *value, const ScrStr *path) {
|
|
|
916
927
|
scr_str_release(message);
|
|
917
928
|
}
|
|
918
929
|
|
|
930
|
+
void scr_fs_invalid_path(const ScrDyn *value, const ScrStr *path) {
|
|
931
|
+
scr_fs_invalid_named_path(value, path, "path");
|
|
932
|
+
}
|
|
933
|
+
|
|
919
934
|
void scr_process_load_env_file(const ScrDyn *value) {
|
|
920
935
|
ScrStr *path;
|
|
921
936
|
if (value->kind == SCR_DYN_UNDEF || value->kind == SCR_DYN_NULL) path = scr_str_new("./.env", 6);
|
|
@@ -928,7 +943,7 @@ void scr_process_load_env_file(const ScrDyn *value) {
|
|
|
928
943
|
}
|
|
929
944
|
if (!path) return;
|
|
930
945
|
if (memchr(path->data, 0, path->len)) {
|
|
931
|
-
|
|
946
|
+
scr_fs_invalid_path(value, path);
|
|
932
947
|
scr_str_release(path);
|
|
933
948
|
return;
|
|
934
949
|
}
|
|
@@ -2501,7 +2516,45 @@ void scr_fs_mkdir_mode(ScrStr *path, double mode) {
|
|
|
2501
2516
|
if (scr_sys_mkdir(path->data, (mode_t)mode) != 0) scr_fs_throw(errno, "mkdir", path);
|
|
2502
2517
|
}
|
|
2503
2518
|
|
|
2519
|
+
#ifdef _WIN32
|
|
2520
|
+
/* The CRT's stat follows junctions. Recognize real link reparse records
|
|
2521
|
+
* before unlink/rm dispatch so a tree walk never descends into their targets.
|
|
2522
|
+
* Return 1 for a removed link, 0 for an ordinary entry, -1 on failure. */
|
|
2523
|
+
static int scr_fs_win_remove_link(const char *path, size_t len) {
|
|
2524
|
+
ScrStr *text = scr_str_new(path, len);
|
|
2525
|
+
WCHAR *wide = scr_fs_win_wide(text);
|
|
2526
|
+
scr_str_release(text);
|
|
2527
|
+
if (!wide) { errno = scr_fs_win_errno(GetLastError()); return -1; }
|
|
2528
|
+
DWORD attributes = GetFileAttributesW(wide);
|
|
2529
|
+
if (attributes == INVALID_FILE_ATTRIBUTES || !(attributes & FILE_ATTRIBUTE_REPARSE_POINT)) { free(wide); return 0; }
|
|
2530
|
+
HANDLE h = CreateFileW(wide, FILE_READ_ATTRIBUTES,
|
|
2531
|
+
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING,
|
|
2532
|
+
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
|
|
2533
|
+
if (h == INVALID_HANDLE_VALUE) { DWORD error = GetLastError(); free(wide); errno = scr_fs_win_errno(error); return -1; }
|
|
2534
|
+
FILE_ATTRIBUTE_TAG_INFO tagged;
|
|
2535
|
+
if (!GetFileInformationByHandleEx(h, FileAttributeTagInfo, &tagged, sizeof tagged)) {
|
|
2536
|
+
DWORD error = GetLastError(); CloseHandle(h); free(wide); errno = scr_fs_win_errno(error); return -1;
|
|
2537
|
+
}
|
|
2538
|
+
double size;
|
|
2539
|
+
bool link = scr_stats_is_link_tag(tagged.ReparseTag);
|
|
2540
|
+
// Mount-point tags also represent mounted volumes. Only junction payloads
|
|
2541
|
+
// are links; keep the existing ordinary-directory behavior for volumes.
|
|
2542
|
+
if (link && tagged.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) link = scr_stats_link_target(h, tagged.ReparseTag, &size, NULL);
|
|
2543
|
+
CloseHandle(h);
|
|
2544
|
+
if (!link) { free(wide); return 0; }
|
|
2545
|
+
BOOL ok = attributes & FILE_ATTRIBUTE_DIRECTORY ? RemoveDirectoryW(wide) : DeleteFileW(wide);
|
|
2546
|
+
DWORD error = ok ? 0 : GetLastError();
|
|
2547
|
+
free(wide);
|
|
2548
|
+
if (!ok) { errno = scr_fs_win_errno(error); return -1; }
|
|
2549
|
+
return 1;
|
|
2550
|
+
}
|
|
2551
|
+
#endif
|
|
2552
|
+
|
|
2504
2553
|
void scr_fs_unlink(ScrStr *path) {
|
|
2554
|
+
#ifdef _WIN32
|
|
2555
|
+
int link = scr_fs_win_remove_link(path->data, path->len);
|
|
2556
|
+
if (link != 0) { if (link < 0) scr_fs_throw(errno, "unlink", path); return; }
|
|
2557
|
+
#endif
|
|
2505
2558
|
if (unlink(path->data) != 0) scr_fs_throw(errno, "unlink", path);
|
|
2506
2559
|
}
|
|
2507
2560
|
|
|
@@ -2665,6 +2718,80 @@ void scr_fs_ftruncate(double fd, double length) {
|
|
|
2665
2718
|
#endif
|
|
2666
2719
|
}
|
|
2667
2720
|
|
|
2721
|
+
#ifdef _WIN32
|
|
2722
|
+
static bool scr_fs_set_times(HANDLE handle, double access, double modified) {
|
|
2723
|
+
FILETIME atime, mtime, now;
|
|
2724
|
+
if (isinf(access) || isinf(modified)) GetSystemTimeAsFileTime(&now);
|
|
2725
|
+
double values[2] = { access, modified };
|
|
2726
|
+
FILETIME *files[2] = { &atime, &mtime };
|
|
2727
|
+
for (size_t i = 0; i < 2; i++) {
|
|
2728
|
+
if (isnan(values[i])) { files[i] = NULL; continue; }
|
|
2729
|
+
if (isinf(values[i])) { *files[i] = now; continue; }
|
|
2730
|
+
double ticks = values[i] * 10000000.0 + 116444736000000000.0;
|
|
2731
|
+
if (ticks < -9223372036854775808.0 || ticks >= 9223372036854775808.0) {
|
|
2732
|
+
SetLastError(ERROR_INVALID_PARAMETER);
|
|
2733
|
+
return false;
|
|
2734
|
+
}
|
|
2735
|
+
int64_t time = (int64_t)ticks;
|
|
2736
|
+
files[i]->dwLowDateTime = (DWORD)(uint64_t)time;
|
|
2737
|
+
files[i]->dwHighDateTime = (DWORD)((uint64_t)time >> 32);
|
|
2738
|
+
}
|
|
2739
|
+
return SetFileTime(handle, NULL, files[0], files[1]) != 0;
|
|
2740
|
+
}
|
|
2741
|
+
|
|
2742
|
+
static DWORD scr_fs_set_path_times(WCHAR *path, double atime, double mtime, bool nofollow) {
|
|
2743
|
+
DWORD flags = FILE_FLAG_BACKUP_SEMANTICS | (nofollow ? FILE_FLAG_OPEN_REPARSE_POINT : 0);
|
|
2744
|
+
HANDLE handle = CreateFileW(path, FILE_WRITE_ATTRIBUTES,
|
|
2745
|
+
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, flags, NULL);
|
|
2746
|
+
if (handle == INVALID_HANDLE_VALUE) return GetLastError();
|
|
2747
|
+
DWORD error = scr_fs_set_times(handle, atime, mtime) ? 0 : GetLastError();
|
|
2748
|
+
CloseHandle(handle);
|
|
2749
|
+
return error;
|
|
2750
|
+
}
|
|
2751
|
+
#else
|
|
2752
|
+
/* Match the pinned libuv conversion: microsecond truncation, normalized
|
|
2753
|
+
* negative fractions, and the special current/unchanged time sentinels. */
|
|
2754
|
+
static bool scr_fs_timespec(double time, struct timespec *out) {
|
|
2755
|
+
if (isinf(time)) { *out = (struct timespec){ 0, UTIME_NOW }; return true; }
|
|
2756
|
+
if (isnan(time)) { *out = (struct timespec){ 0, UTIME_OMIT }; return true; }
|
|
2757
|
+
if (time < -9223372036854775808.0 || time >= 9223372036854775808.0) return false;
|
|
2758
|
+
out->tv_sec = (time_t)time;
|
|
2759
|
+
out->tv_nsec = (long)((time - (double)out->tv_sec) * 1000000000.0);
|
|
2760
|
+
out->tv_nsec -= out->tv_nsec % 1000;
|
|
2761
|
+
if (out->tv_nsec < 0) { out->tv_nsec += 1000000000; out->tv_sec--; }
|
|
2762
|
+
return true;
|
|
2763
|
+
}
|
|
2764
|
+
#endif
|
|
2765
|
+
|
|
2766
|
+
void scr_fs_utimes(ScrStr *path, double atime, double mtime, bool nofollow) {
|
|
2767
|
+
const char *op = nofollow ? "lutime" : "utime";
|
|
2768
|
+
#ifdef _WIN32
|
|
2769
|
+
WCHAR *wide = scr_fs_win_wide(path);
|
|
2770
|
+
if (!wide) { scr_fs_throw(scr_fs_win_errno(GetLastError()), op, path); return; }
|
|
2771
|
+
DWORD error = scr_fs_set_path_times(wide, atime, mtime, nofollow);
|
|
2772
|
+
if (nofollow && (error == ERROR_SYMLINK_NOT_SUPPORTED || error == ERROR_NOT_A_REPARSE_POINT))
|
|
2773
|
+
error = scr_fs_set_path_times(wide, atime, mtime, false);
|
|
2774
|
+
free(wide);
|
|
2775
|
+
if (error) scr_fs_throw(scr_fs_win_errno(error), op, path);
|
|
2776
|
+
#else
|
|
2777
|
+
struct timespec times[2];
|
|
2778
|
+
if (!scr_fs_timespec(atime, ×[0]) || !scr_fs_timespec(mtime, ×[1])) { scr_fs_throw(EINVAL, op, path); return; }
|
|
2779
|
+
if (utimensat(AT_FDCWD, path->data, times, nofollow ? AT_SYMLINK_NOFOLLOW : 0) != 0) scr_fs_throw(errno, op, path);
|
|
2780
|
+
#endif
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2783
|
+
void scr_fs_futimes(double fd, double atime, double mtime) {
|
|
2784
|
+
#ifdef _WIN32
|
|
2785
|
+
HANDLE handle = (HANDLE)_get_osfhandle((int)fd);
|
|
2786
|
+
if (handle == INVALID_HANDLE_VALUE) { scr_fs_throw_nopath(EBADF, "futime"); return; }
|
|
2787
|
+
if (!scr_fs_set_times(handle, atime, mtime)) scr_fs_throw_nopath(scr_fs_win_errno(GetLastError()), "futime");
|
|
2788
|
+
#else
|
|
2789
|
+
struct timespec times[2];
|
|
2790
|
+
if (!scr_fs_timespec(atime, ×[0]) || !scr_fs_timespec(mtime, ×[1])) { scr_fs_throw_nopath(EINVAL, "futime"); return; }
|
|
2791
|
+
if (futimens((int)fd, times) != 0) scr_fs_throw_nopath(errno, "futime");
|
|
2792
|
+
#endif
|
|
2793
|
+
}
|
|
2794
|
+
|
|
2668
2795
|
/* fs.closeSync(fd) — close(2); failure throws Node's path-less fs error
|
|
2669
2796
|
* shape ("EBADF: bad file descriptor, close"). */
|
|
2670
2797
|
|
|
@@ -3165,18 +3292,15 @@ void scr_fs_link(ScrStr *source, ScrStr *dest) {
|
|
|
3165
3292
|
WCHAR *from = scr_fs_win_wide(source);
|
|
3166
3293
|
WCHAR *to = scr_fs_win_wide(dest);
|
|
3167
3294
|
if (!from || !to) {
|
|
3295
|
+
DWORD error = GetLastError();
|
|
3168
3296
|
free(from); free(to);
|
|
3169
|
-
scr_fs_throw2(
|
|
3297
|
+
scr_fs_throw2(scr_fs_win_errno(error), "link", source, dest);
|
|
3170
3298
|
return;
|
|
3171
3299
|
}
|
|
3172
3300
|
BOOL ok = CreateHardLinkW(to, from, NULL);
|
|
3173
3301
|
DWORD error = ok ? 0 : GetLastError();
|
|
3174
3302
|
free(from); free(to);
|
|
3175
|
-
if (!ok)
|
|
3176
|
-
int code = error == ERROR_ALREADY_EXISTS || error == ERROR_FILE_EXISTS ? EEXIST :
|
|
3177
|
-
error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND ? ENOENT : EACCES;
|
|
3178
|
-
scr_fs_throw2(code, "link", source, dest);
|
|
3179
|
-
}
|
|
3303
|
+
if (!ok) scr_fs_throw2(scr_fs_win_errno(error), "link", source, dest);
|
|
3180
3304
|
#else
|
|
3181
3305
|
if (link(source->data, dest->data) != 0) scr_fs_throw2(errno, "link", source, dest);
|
|
3182
3306
|
#endif
|
|
@@ -3347,6 +3471,10 @@ void scr_fs_rename(ScrStr *oldpath, ScrStr *newpath) {
|
|
|
3347
3471
|
static int scr_rm_unlink(const char *path, size_t len);
|
|
3348
3472
|
|
|
3349
3473
|
void scr_fs_rm(ScrStr *path) {
|
|
3474
|
+
#ifdef _WIN32
|
|
3475
|
+
int link = scr_fs_win_remove_link(path->data, path->len);
|
|
3476
|
+
if (link != 0) { if (link < 0) scr_fs_throw(errno, "unlink", path); return; }
|
|
3477
|
+
#endif
|
|
3350
3478
|
/* Node's rmSync: lstat first (a missing path reports the lstat syscall),
|
|
3351
3479
|
* refuse directories (Node requires `recursive`, which the scriptc
|
|
3352
3480
|
* surface doesn't declare — the message wording diverges from Node's
|
|
@@ -3501,6 +3629,10 @@ static int scr_rm_unlink(const char *path, size_t len) {
|
|
|
3501
3629
|
/* Post-order tree removal for rmSync's recursive form. Stops at (and
|
|
3502
3630
|
* records) the first failure, with the failing path and syscall name. */
|
|
3503
3631
|
static void scr_rm_tree_e(const char *path, size_t len, ScrRmFail *f) {
|
|
3632
|
+
#ifdef _WIN32
|
|
3633
|
+
int link = scr_fs_win_remove_link(path, len);
|
|
3634
|
+
if (link != 0) { if (link < 0) scr_rm_fail_set(f, errno, "unlink", path, len); return; }
|
|
3635
|
+
#endif
|
|
3504
3636
|
struct stat st;
|
|
3505
3637
|
if (lstat(path, &st) != 0) {
|
|
3506
3638
|
scr_rm_fail_set(f, errno, "lstat", path, len);
|
|
@@ -3541,6 +3673,10 @@ static void scr_rm_tree_e(const char *path, size_t len, ScrRmFail *f) {
|
|
|
3541
3673
|
* force's ENOENT swallow, the non-recursive directory rejection, and the
|
|
3542
3674
|
* tree walk — failures recorded in `f`, never thrown. */
|
|
3543
3675
|
static void scr_fs_rm_attempt(ScrStr *path, bool recursive, bool force, ScrRmFail *f) {
|
|
3676
|
+
#ifdef _WIN32
|
|
3677
|
+
int link = scr_fs_win_remove_link(path->data, path->len);
|
|
3678
|
+
if (link != 0) { if (link < 0) scr_rm_fail_set(f, errno, "unlink", path->data, path->len); return; }
|
|
3679
|
+
#endif
|
|
3544
3680
|
struct stat st;
|
|
3545
3681
|
if (lstat(path->data, &st) != 0) {
|
|
3546
3682
|
if (force && errno == ENOENT) return; /* Node: force swallows ENOENT */
|
|
@@ -3994,7 +4130,7 @@ typedef struct {
|
|
|
3994
4130
|
/* Node/libuv reports a Windows link's target-text length as st_size. The
|
|
3995
4131
|
* ordinary handle information does not carry that value, so read the reparse
|
|
3996
4132
|
* payload while the no-follow handle is live. */
|
|
3997
|
-
static bool
|
|
4133
|
+
static bool scr_stats_link_target(HANDLE h, DWORD tag, double *size_out, ScrStr **text_out) {
|
|
3998
4134
|
union {
|
|
3999
4135
|
ScrStatsReparseData align;
|
|
4000
4136
|
unsigned char bytes[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
|
|
@@ -4039,6 +4175,7 @@ static bool scr_stats_link_size(HANDLE h, DWORD tag, double *size_out) {
|
|
|
4039
4175
|
/* WSL's LX symlink payload is a version word followed by UTF-8 bytes. */
|
|
4040
4176
|
if (data->data_len < sizeof(ULONG)) return false;
|
|
4041
4177
|
*size_out = (double)(data->data_len - sizeof(ULONG));
|
|
4178
|
+
if (text_out) *text_out = scr_str_new((const char *)data->body.generic.bytes + sizeof(ULONG), data->data_len - sizeof(ULONG));
|
|
4042
4179
|
return true;
|
|
4043
4180
|
} else {
|
|
4044
4181
|
/* App execution links carry a counted UTF-16 string list; the third
|
|
@@ -4067,6 +4204,10 @@ static bool scr_stats_link_size(HANDLE h, DWORD tag, double *size_out) {
|
|
|
4067
4204
|
double size = scr_stats_utf16_len(target, len);
|
|
4068
4205
|
if (size < 0) return false;
|
|
4069
4206
|
*size_out = size;
|
|
4207
|
+
if (text_out) {
|
|
4208
|
+
*text_out = scr_fs_win_utf8(target, len);
|
|
4209
|
+
if (!*text_out) return false;
|
|
4210
|
+
}
|
|
4070
4211
|
return true;
|
|
4071
4212
|
}
|
|
4072
4213
|
|
|
@@ -4092,6 +4233,10 @@ static bool scr_stats_link_size(HANDLE h, DWORD tag, double *size_out) {
|
|
|
4092
4233
|
double size = scr_stats_utf16_len(target, len);
|
|
4093
4234
|
if (size < 0) return false;
|
|
4094
4235
|
*size_out = size;
|
|
4236
|
+
if (text_out) {
|
|
4237
|
+
*text_out = scr_fs_win_utf8(target, len);
|
|
4238
|
+
if (!*text_out) return false;
|
|
4239
|
+
}
|
|
4095
4240
|
return true;
|
|
4096
4241
|
}
|
|
4097
4242
|
|
|
@@ -4105,8 +4250,21 @@ static ScrStats *scr_stats_of_path(const ScrStr *path, const char *op,
|
|
|
4105
4250
|
HANDLE h = CreateFileW(wide, FILE_READ_ATTRIBUTES,
|
|
4106
4251
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
4107
4252
|
NULL, OPEN_EXISTING, flags, NULL);
|
|
4253
|
+
if (h == INVALID_HANDLE_VALUE) {
|
|
4254
|
+
DWORD error = GetLastError();
|
|
4255
|
+
DWORD attributes = GetFileAttributesW(wide);
|
|
4256
|
+
free(wide);
|
|
4257
|
+
/* CRT stat can report the link entry when its target cannot be opened,
|
|
4258
|
+
* hiding dangling links and Windows file/directory type mismatches.
|
|
4259
|
+
* libuv preserves the failed follow operation for reparse points. */
|
|
4260
|
+
if (!no_follow && attributes != INVALID_FILE_ATTRIBUTES &&
|
|
4261
|
+
(attributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
|
|
4262
|
+
scr_fs_throw(scr_fs_win_errno(error), op, path);
|
|
4263
|
+
return NULL;
|
|
4264
|
+
}
|
|
4265
|
+
return scr_stats_crt_fallback(path, op);
|
|
4266
|
+
}
|
|
4108
4267
|
free(wide);
|
|
4109
|
-
if (h == INVALID_HANDLE_VALUE) return scr_stats_crt_fallback(path, op);
|
|
4110
4268
|
|
|
4111
4269
|
DWORD file_type = GetFileType(h);
|
|
4112
4270
|
if (file_type != FILE_TYPE_DISK) {
|
|
@@ -4130,7 +4288,7 @@ static ScrStats *scr_stats_of_path(const ScrStr *path, const char *op,
|
|
|
4130
4288
|
CloseHandle(h);
|
|
4131
4289
|
return scr_stats_of_path(path, op, false);
|
|
4132
4290
|
}
|
|
4133
|
-
if (!
|
|
4291
|
+
if (!scr_stats_link_target(h, tagged.ReparseTag, &link_size, NULL)) {
|
|
4134
4292
|
/* A mount-point tag may name a mounted volume rather than a junction.
|
|
4135
4293
|
* libuv treats those (and malformed/unsupported link payloads) as
|
|
4136
4294
|
* ordinary reparse points and retries with the final component
|
|
@@ -4207,6 +4365,215 @@ static ScrStats *scr_stats_of(const struct stat *st) {
|
|
|
4207
4365
|
}
|
|
4208
4366
|
#endif
|
|
4209
4367
|
|
|
4368
|
+
/* Symbolic link targets are stored verbatim on POSIX. Windows junctions
|
|
4369
|
+
* instead carry an absolute NT path in a bounded mount-point reparse record. */
|
|
4370
|
+
#ifdef _WIN32
|
|
4371
|
+
static DWORD scr_fs_win_junction(const WCHAR *target, const WCHAR *destination) {
|
|
4372
|
+
size_t len = wcslen(target);
|
|
4373
|
+
/* libuv permits drive-absolute junctions, not UNC mount targets. */
|
|
4374
|
+
size_t skip = len >= 4 && !wcsncmp(target, L"\\\\?\\", 4) ? 4 : 0;
|
|
4375
|
+
const WCHAR *plain = target + skip;
|
|
4376
|
+
size_t chars = len - skip;
|
|
4377
|
+
if (chars < 3 || !((plain[0] >= L'A' && plain[0] <= L'Z') || (plain[0] >= L'a' && plain[0] <= L'z')) || plain[1] != L':' || plain[2] != L'\\') return ERROR_INVALID_PARAMETER;
|
|
4378
|
+
size_t fixed = offsetof(ScrStatsReparseData, body.mount.path);
|
|
4379
|
+
size_t total = fixed + (4 + chars + 1 + chars + 1) * sizeof(WCHAR);
|
|
4380
|
+
if (total > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) return ERROR_FILENAME_EXCED_RANGE;
|
|
4381
|
+
ScrStatsReparseData *data = calloc(1, total);
|
|
4382
|
+
if (!data) return ERROR_NOT_ENOUGH_MEMORY;
|
|
4383
|
+
data->tag = IO_REPARSE_TAG_MOUNT_POINT;
|
|
4384
|
+
data->data_len = (USHORT)(total - offsetof(ScrStatsReparseData, body));
|
|
4385
|
+
data->body.mount.substitute_offset = 0;
|
|
4386
|
+
data->body.mount.substitute_len = (USHORT)((4 + chars) * sizeof(WCHAR));
|
|
4387
|
+
data->body.mount.print_offset = (USHORT)((4 + chars + 1) * sizeof(WCHAR));
|
|
4388
|
+
data->body.mount.print_len = (USHORT)(chars * sizeof(WCHAR));
|
|
4389
|
+
memcpy(data->body.mount.path, L"\\??\\", 4 * sizeof(WCHAR));
|
|
4390
|
+
memcpy(data->body.mount.path + 4, plain, chars * sizeof(WCHAR));
|
|
4391
|
+
memcpy(data->body.mount.path + 4 + chars + 1, plain, chars * sizeof(WCHAR));
|
|
4392
|
+
DWORD error = 0, used;
|
|
4393
|
+
bool created = CreateDirectoryW(destination, NULL) != 0;
|
|
4394
|
+
HANDLE h = INVALID_HANDLE_VALUE;
|
|
4395
|
+
if (!created) error = GetLastError();
|
|
4396
|
+
else {
|
|
4397
|
+
h = CreateFileW(destination, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
|
|
4398
|
+
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
|
|
4399
|
+
if (h == INVALID_HANDLE_VALUE) error = GetLastError();
|
|
4400
|
+
else if (!DeviceIoControl(h, FSCTL_SET_REPARSE_POINT, data, (DWORD)total, NULL, 0, &used, NULL)) error = GetLastError();
|
|
4401
|
+
}
|
|
4402
|
+
if (h != INVALID_HANDLE_VALUE) CloseHandle(h);
|
|
4403
|
+
if (error && created) RemoveDirectoryW(destination);
|
|
4404
|
+
free(data);
|
|
4405
|
+
return error;
|
|
4406
|
+
}
|
|
4407
|
+
#endif
|
|
4408
|
+
|
|
4409
|
+
#ifdef _WIN32
|
|
4410
|
+
/* libuv keeps this fallback for later calls once Windows rejects the flag. */
|
|
4411
|
+
static DWORD scr_fs_symlink_usermode_flag = 0x2; /* ALLOW_UNPRIVILEGED_CREATE */
|
|
4412
|
+
#endif
|
|
4413
|
+
|
|
4414
|
+
int scr_fs_symlink_infer(ScrStr *absolute) {
|
|
4415
|
+
#ifdef _WIN32
|
|
4416
|
+
WCHAR *probe = scr_fs_win_wide(absolute);
|
|
4417
|
+
DWORD attributes = probe ? GetFileAttributesW(probe) : INVALID_FILE_ATTRIBUTES;
|
|
4418
|
+
free(probe);
|
|
4419
|
+
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
|
|
4420
|
+
#else
|
|
4421
|
+
(void)absolute;
|
|
4422
|
+
return 0;
|
|
4423
|
+
#endif
|
|
4424
|
+
}
|
|
4425
|
+
|
|
4426
|
+
void scr_fs_symlink(ScrStr *target, ScrStr *destination, int kind) {
|
|
4427
|
+
#ifdef _WIN32
|
|
4428
|
+
ScrArr *parts = scr_arr_new_ref(scr_str_retain_v, scr_str_release_v, NULL, 3);
|
|
4429
|
+
scr_arr_push_ref(parts, scr_str_retain(destination));
|
|
4430
|
+
scr_arr_push_ref(parts, scr_str_new("..", 2));
|
|
4431
|
+
scr_arr_push_ref(parts, scr_str_retain(target));
|
|
4432
|
+
ScrStr *absolute = scr_path_win32_resolve(parts);
|
|
4433
|
+
scr_arr_release(parts);
|
|
4434
|
+
if (kind == -1) kind = scr_fs_symlink_infer(absolute);
|
|
4435
|
+
ScrStr *stored;
|
|
4436
|
+
if (kind == 2) stored = scr_path_win32_to_namespaced_path(absolute);
|
|
4437
|
+
else if (scr_path_win32_is_absolute(target)) stored = scr_path_win32_to_namespaced_path(target);
|
|
4438
|
+
else {
|
|
4439
|
+
char *text = malloc(target->len ? target->len : 1);
|
|
4440
|
+
if (!text) scr_trap("scriptc: out of memory\n");
|
|
4441
|
+
for (size_t i = 0; i < target->len; i++) text[i] = target->data[i] == '/' ? '\\' : target->data[i];
|
|
4442
|
+
stored = scr_str_new(text, target->len);
|
|
4443
|
+
free(text);
|
|
4444
|
+
}
|
|
4445
|
+
scr_str_release(absolute);
|
|
4446
|
+
/* Node's binding namespaces the link path before passing it to libuv. */
|
|
4447
|
+
ScrStr *link_path = scr_path_win32_to_namespaced_path(destination);
|
|
4448
|
+
WCHAR *from = scr_fs_win_wide(stored), *to = scr_fs_win_wide(link_path);
|
|
4449
|
+
DWORD error = !from || !to ? GetLastError() : 0;
|
|
4450
|
+
if (!error && kind == 2) error = scr_fs_win_junction(from, to);
|
|
4451
|
+
else if (!error) {
|
|
4452
|
+
DWORD flags = (kind == 1 ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) | scr_fs_symlink_usermode_flag;
|
|
4453
|
+
if (!CreateSymbolicLinkW(to, from, flags)) {
|
|
4454
|
+
error = GetLastError();
|
|
4455
|
+
if (error == ERROR_INVALID_PARAMETER && scr_fs_symlink_usermode_flag) {
|
|
4456
|
+
scr_fs_symlink_usermode_flag = 0;
|
|
4457
|
+
error = CreateSymbolicLinkW(to, from, flags & ~0x2u) ? 0 : GetLastError();
|
|
4458
|
+
}
|
|
4459
|
+
}
|
|
4460
|
+
}
|
|
4461
|
+
free(from); free(to); scr_str_release(stored); scr_str_release(link_path);
|
|
4462
|
+
if (error) scr_fs_throw2(scr_fs_win_errno(error), "symlink", target, destination);
|
|
4463
|
+
#else
|
|
4464
|
+
(void)kind;
|
|
4465
|
+
if (symlink(target->data, destination->data) != 0) scr_fs_throw2(errno, "symlink", target, destination);
|
|
4466
|
+
#endif
|
|
4467
|
+
}
|
|
4468
|
+
|
|
4469
|
+
/* Keep the unsigned libuv statfs representation before selecting Number or
|
|
4470
|
+
* BigInt. Free-space counts are live snapshots, not cached volume metadata. */
|
|
4471
|
+
ScrDyn *scr_fs_statfs(ScrStr *path, bool bigint) {
|
|
4472
|
+
uint64_t fields[7];
|
|
4473
|
+
#if defined(_WIN32)
|
|
4474
|
+
ScrStr *syscall_path = scr_path_win32_to_namespaced_path(path);
|
|
4475
|
+
WCHAR *wide = scr_fs_win_wide(syscall_path);
|
|
4476
|
+
scr_str_release(syscall_path);
|
|
4477
|
+
if (!wide) { scr_fs_throw(scr_fs_win_errno(GetLastError()), "statfs", path); return NULL; }
|
|
4478
|
+
DWORD sectors, bytes, free_clusters, total_clusters;
|
|
4479
|
+
BOOL ok = GetDiskFreeSpaceW(wide, §ors, &bytes, &free_clusters, &total_clusters);
|
|
4480
|
+
DWORD error = ok ? 0 : GetLastError();
|
|
4481
|
+
if (!ok && error == ERROR_DIRECTORY) {
|
|
4482
|
+
/* libuv retries a file path's parent once, preserving the original path
|
|
4483
|
+
* in errors. GetFullPathName also expands relative and drive paths. */
|
|
4484
|
+
DWORD size = GetFullPathNameW(wide, 0, NULL, NULL);
|
|
4485
|
+
WCHAR *absolute = size ? malloc((size_t)size * sizeof *absolute) : NULL;
|
|
4486
|
+
if (size && !absolute) scr_trap("scriptc: out of memory\n");
|
|
4487
|
+
WCHAR *part = NULL;
|
|
4488
|
+
DWORD length = absolute ? GetFullPathNameW(wide, size, absolute, &part) : 0;
|
|
4489
|
+
if (length && length < size) {
|
|
4490
|
+
if (part) *part = L'\0';
|
|
4491
|
+
ok = GetDiskFreeSpaceW(absolute, §ors, &bytes, &free_clusters, &total_clusters);
|
|
4492
|
+
if (!ok) error = GetLastError();
|
|
4493
|
+
}
|
|
4494
|
+
free(absolute);
|
|
4495
|
+
}
|
|
4496
|
+
free(wide);
|
|
4497
|
+
if (!ok) { scr_fs_throw(scr_fs_win_errno(error), "statfs", path); return NULL; }
|
|
4498
|
+
fields[0] = 0;
|
|
4499
|
+
fields[1] = (DWORD)(bytes * sectors);
|
|
4500
|
+
fields[2] = total_clusters;
|
|
4501
|
+
fields[3] = fields[4] = free_clusters;
|
|
4502
|
+
fields[5] = fields[6] = 0;
|
|
4503
|
+
#elif defined(__wasi__)
|
|
4504
|
+
(void)path; (void)bigint;
|
|
4505
|
+
static const char message[] = "Filesystem capacity queries have no native WASI syscall";
|
|
4506
|
+
scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "SC2020");
|
|
4507
|
+
return NULL;
|
|
4508
|
+
#else
|
|
4509
|
+
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
|
4510
|
+
struct statfs snapshot;
|
|
4511
|
+
if (statfs(path->data, &snapshot) != 0) { scr_fs_throw(errno, "statfs", path); return NULL; }
|
|
4512
|
+
fields[0] = (uint64_t)snapshot.f_type;
|
|
4513
|
+
#else
|
|
4514
|
+
struct statvfs snapshot;
|
|
4515
|
+
if (statvfs(path->data, &snapshot) != 0) { scr_fs_throw(errno, "statfs", path); return NULL; }
|
|
4516
|
+
fields[0] = 0;
|
|
4517
|
+
#endif
|
|
4518
|
+
fields[1] = (uint64_t)snapshot.f_bsize;
|
|
4519
|
+
fields[2] = (uint64_t)snapshot.f_blocks;
|
|
4520
|
+
fields[3] = (uint64_t)snapshot.f_bfree;
|
|
4521
|
+
fields[4] = (uint64_t)snapshot.f_bavail;
|
|
4522
|
+
fields[5] = (uint64_t)snapshot.f_files;
|
|
4523
|
+
fields[6] = (uint64_t)snapshot.f_ffree;
|
|
4524
|
+
#endif
|
|
4525
|
+
static const char *names[] = { "type", "bsize", "blocks", "bfree", "bavail", "files", "ffree" };
|
|
4526
|
+
ScrDyn *result = scr_dyn_new_obj();
|
|
4527
|
+
for (size_t i = 0; i < 7; i++) {
|
|
4528
|
+
ScrDyn *value;
|
|
4529
|
+
if (bigint) {
|
|
4530
|
+
ScrBigInt *number = scr_bigint_from_u64(fields[i]);
|
|
4531
|
+
value = scr_dyn_new_bigint(number);
|
|
4532
|
+
scr_bigint_release(number);
|
|
4533
|
+
} else value = scr_dyn_new_num((double)fields[i]);
|
|
4534
|
+
scr_dyn_obj_set(result, names[i], strlen(names[i]), value);
|
|
4535
|
+
}
|
|
4536
|
+
return result;
|
|
4537
|
+
}
|
|
4538
|
+
|
|
4539
|
+
ScrBytes *scr_fs_readlink_bytes(ScrStr *path) {
|
|
4540
|
+
#ifdef _WIN32
|
|
4541
|
+
WCHAR *wide = scr_fs_win_wide(path);
|
|
4542
|
+
if (!wide) { scr_fs_throw(scr_fs_win_errno(GetLastError()), "readlink", path); return NULL; }
|
|
4543
|
+
HANDLE h = CreateFileW(wide, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING,
|
|
4544
|
+
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
|
4545
|
+
free(wide);
|
|
4546
|
+
if (h == INVALID_HANDLE_VALUE) { scr_fs_throw(scr_fs_win_errno(GetLastError()), "readlink", path); return NULL; }
|
|
4547
|
+
FILE_ATTRIBUTE_TAG_INFO tagged;
|
|
4548
|
+
ScrStr *text = NULL;
|
|
4549
|
+
double size;
|
|
4550
|
+
bool ok = GetFileInformationByHandleEx(h, FileAttributeTagInfo, &tagged, sizeof tagged) &&
|
|
4551
|
+
scr_stats_link_target(h, tagged.ReparseTag, &size, &text);
|
|
4552
|
+
CloseHandle(h);
|
|
4553
|
+
if (!ok || !text) { scr_str_release(text); scr_fs_throw(EINVAL, "readlink", path); return NULL; }
|
|
4554
|
+
ScrBytes *bytes = scr_bytes_from_data((const uint8_t *)text->data, text->len);
|
|
4555
|
+
scr_str_release(text);
|
|
4556
|
+
return bytes;
|
|
4557
|
+
#else
|
|
4558
|
+
size_t capacity = 256;
|
|
4559
|
+
uint8_t *text = NULL;
|
|
4560
|
+
for (;;) {
|
|
4561
|
+
uint8_t *grown = realloc(text, capacity);
|
|
4562
|
+
if (!grown) { free(text); scr_trap("scriptc: out of memory\n"); }
|
|
4563
|
+
text = grown;
|
|
4564
|
+
ssize_t size = readlink(path->data, (char *)text, capacity);
|
|
4565
|
+
if (size < 0) { int error = errno; free(text); scr_fs_throw(error, "readlink", path); return NULL; }
|
|
4566
|
+
if ((size_t)size < capacity) {
|
|
4567
|
+
ScrBytes *bytes = scr_bytes_from_data(text, (size_t)size);
|
|
4568
|
+
free(text);
|
|
4569
|
+
return bytes;
|
|
4570
|
+
}
|
|
4571
|
+
if (capacity > SIZE_MAX / 2) { free(text); scr_fs_throw(ENAMETOOLONG, "readlink", path); return NULL; }
|
|
4572
|
+
capacity *= 2;
|
|
4573
|
+
}
|
|
4574
|
+
#endif
|
|
4575
|
+
}
|
|
4576
|
+
|
|
4210
4577
|
ScrStats *scr_fs_stat(ScrStr *path) {
|
|
4211
4578
|
#ifdef _WIN32
|
|
4212
4579
|
return scr_stats_of_path(path, "stat", false);
|
|
@@ -649,6 +649,14 @@ void scr_map_dyn_set(ScrMap *map, const ScrDyn *key, const ScrDyn *value, bool s
|
|
|
649
649
|
scr_map_release_key(map, key_slot);
|
|
650
650
|
}
|
|
651
651
|
|
|
652
|
+
ScrArr *scr_set_to_arr_dyn(const ScrMap *map) {
|
|
653
|
+
ScrArr *out = scr_arr_new_ref(scr_dyn_retain_v, scr_dyn_release_v, scr_dyn_trace_v, map->nlive);
|
|
654
|
+
for (size_t i = 0; i < map->nentries; i++) {
|
|
655
|
+
if (scr_map_iter_live(map, (double)i)) scr_arr_push_ref(out, scr_map_dyn_key(map, (double)i));
|
|
656
|
+
}
|
|
657
|
+
return out;
|
|
658
|
+
}
|
|
659
|
+
|
|
652
660
|
void *scr_map_iter_val_ref(const ScrMap *m, double i) {
|
|
653
661
|
return m->val_retain(scr_map_slot_to_ptr(scr_map_iter_at(m, i)->val)); /* +1 */
|
|
654
662
|
}
|
|
@@ -1,11 +1,89 @@
|
|
|
1
1
|
/* Native builtin export objects. The compiler supplies the existing static
|
|
2
2
|
* callable implementations; this unit owns lookup, identity, and mutations. */
|
|
3
3
|
#include "scr_runtime.h"
|
|
4
|
+
#include "scr_system_errors.h"
|
|
4
5
|
|
|
5
6
|
#include <stdlib.h>
|
|
6
7
|
#include <string.h>
|
|
7
8
|
#include <math.h>
|
|
8
9
|
|
|
10
|
+
typedef struct { int value; const char *name; const char *message; } ScrSystemError;
|
|
11
|
+
#define SCR_SYSTEM_ERROR(name, message) { SCR_NODE_UV__##name, #name, message },
|
|
12
|
+
static const ScrSystemError scr_system_errors[] = {
|
|
13
|
+
SCR_NODE_UV_ERRNO_MAP(SCR_SYSTEM_ERROR)
|
|
14
|
+
};
|
|
15
|
+
#undef SCR_SYSTEM_ERROR
|
|
16
|
+
|
|
17
|
+
static bool scr_system_error_number(const ScrDyn *error, double *number) {
|
|
18
|
+
if (!error || error->kind != SCR_DYN_NUM) {
|
|
19
|
+
scr_dyn_arg_type_fail("err", "of type number", error ? error : scr_dyn_undefined());
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
double n = error->v.num;
|
|
23
|
+
if (!(isfinite(n) && n < 0 && trunc(n) == n && n >= -9007199254740991.0)) {
|
|
24
|
+
char received[48];
|
|
25
|
+
scr_num_received(n, received);
|
|
26
|
+
if (n == 0 && signbit(n)) strcpy(received, "-0");
|
|
27
|
+
ScrJsonBuf buffer;
|
|
28
|
+
scr_jb_init(&buffer);
|
|
29
|
+
scr_jb_puts(&buffer, "The value of \"err\" is out of range. It must be a negative integer. Received ");
|
|
30
|
+
scr_jb_puts(&buffer, received);
|
|
31
|
+
ScrStr *message = scr_jb_finish(&buffer);
|
|
32
|
+
scr_throw_error_msg_code(SCR_ERR_RANGE, message->data, message->len, "ERR_OUT_OF_RANGE");
|
|
33
|
+
scr_str_release(message);
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
*number = n;
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static ScrStr *scr_system_error_lookup(double number, bool message) {
|
|
41
|
+
/* Node's name helper looks up the original safe integer. Its message
|
|
42
|
+
* binding uses V8's saturating Int32 extraction instead. */
|
|
43
|
+
double lookup = message && number < -2147483648.0 ? -2147483648.0 : number;
|
|
44
|
+
for (size_t i = 0; i < sizeof scr_system_errors / sizeof scr_system_errors[0]; i++) {
|
|
45
|
+
if (lookup == scr_system_errors[i].value) {
|
|
46
|
+
const char *text = message ? scr_system_errors[i].message : scr_system_errors[i].name;
|
|
47
|
+
return scr_str_new(text, strlen(text));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
ScrJsonBuf buffer;
|
|
51
|
+
scr_jb_init(&buffer);
|
|
52
|
+
scr_jb_puts(&buffer, "Unknown system error ");
|
|
53
|
+
ScrStr *rendered = scr_f64_to_scrstr(lookup);
|
|
54
|
+
scr_jb_put_str(&buffer, rendered);
|
|
55
|
+
scr_str_release(rendered);
|
|
56
|
+
return scr_jb_finish(&buffer);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
ScrStr *scr_util_system_error_name(const ScrDyn *error) {
|
|
60
|
+
double number;
|
|
61
|
+
return scr_system_error_number(error, &number) ? scr_system_error_lookup(number, false) : NULL;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
ScrStr *scr_util_system_error_message(const ScrDyn *error) {
|
|
65
|
+
double number;
|
|
66
|
+
return scr_system_error_number(error, &number) ? scr_system_error_lookup(number, true) : NULL;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
ScrDyn *scr_util_system_error_entries(void) {
|
|
70
|
+
ScrDyn *entries = scr_dyn_new_arr();
|
|
71
|
+
for (size_t i = 0; i < sizeof scr_system_errors / sizeof scr_system_errors[0]; i++) {
|
|
72
|
+
const ScrSystemError *error = &scr_system_errors[i];
|
|
73
|
+
ScrDyn *entry = scr_dyn_new_arr(), *pair = scr_dyn_new_arr();
|
|
74
|
+
ScrStr *name = scr_str_new(error->name, strlen(error->name));
|
|
75
|
+
ScrStr *message = scr_str_new(error->message, strlen(error->message));
|
|
76
|
+
scr_dyn_arr_push(pair, scr_dyn_new_str(name));
|
|
77
|
+
scr_dyn_arr_push(pair, scr_dyn_new_str(message));
|
|
78
|
+
scr_str_release(name);
|
|
79
|
+
scr_str_release(message);
|
|
80
|
+
scr_dyn_arr_push(entry, scr_dyn_new_num(error->value));
|
|
81
|
+
scr_dyn_arr_push(entry, pair);
|
|
82
|
+
scr_dyn_arr_push(entries, entry);
|
|
83
|
+
}
|
|
84
|
+
return entries;
|
|
85
|
+
}
|
|
86
|
+
|
|
9
87
|
static SCR_TL ScrDyn *scr_global_known;
|
|
10
88
|
static SCR_TL ScrDyn *scr_global_own;
|
|
11
89
|
static SCR_TL bool scr_global_cleanup_registered;
|