diff options
author | 2023-08-28 04:39:16 -0700 | |
---|---|---|
committer | 2023-08-28 04:39:16 -0700 | |
commit | e2a17344dc543c9c652cfe2b14cd2709dd6cfd22 (patch) | |
tree | fe93965d39886494aee12dca71bdcf2a991d806f /src | |
parent | efe987e8d12e824dde840b56cbb704feabe26ed1 (diff) | |
download | bun-e2a17344dc543c9c652cfe2b14cd2709dd6cfd22.tar.gz bun-e2a17344dc543c9c652cfe2b14cd2709dd6cfd22.tar.zst bun-e2a17344dc543c9c652cfe2b14cd2709dd6cfd22.zip |
just kernel32 things (#4354)
* just kernel32 things
* more
* Update linux_c.zig
* Update windows_c.zig
* Add workaround
Workaround https://github.com/ziglang/zig/issues/16980
* Rename http.zig to bun_dev_http_server.zig
* Rename usages
* more
* more
* more
* thanks tigerbeetle
* Rename `JSC.Node.Syscall` -> `bun.sys`
* more
* woops
* more!
* hmm
* it says there are only 37 errors, but that's not true
* populate argv
* it says 32 errors!
* 24 errors
* fix regular build
* 12 left!
* Still 12 left!
* more
* 2 errors left...
* 1 more error
* Add link to Tigerbeetle
* Fix the remainign error
* Fix test timeout
* Update syscall.zig
---------
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Diffstat (limited to 'src')
90 files changed, 9325 insertions, 1344 deletions
diff --git a/src/analytics/analytics_thread.zig b/src/analytics/analytics_thread.zig index e4de58d96..b0ee2cdbc 100644 --- a/src/analytics/analytics_thread.zig +++ b/src/analytics/analytics_thread.zig @@ -281,9 +281,16 @@ pub const GenerateHeader = struct { if (comptime Environment.isMac) { platform_ = forMac(); return platform_.?; + } else if (comptime Environment.isPosix) { + platform_ = forLinux(); + } else { + platform_ = Platform{ + .os = Analytics.OperatingSystem.windows, + .version = &[_]u8{}, + .arch = platform_arch, + }; } - platform_ = forLinux(); return platform_.?; } diff --git a/src/bun.js/api/JSBundler.zig b/src/bun.js/api/JSBundler.zig index f5c3793ed..4a4d10f0f 100644 --- a/src/bun.js/api/JSBundler.zig +++ b/src/bun.js/api/JSBundler.zig @@ -1,6 +1,6 @@ const std = @import("std"); const Api = @import("../../api/schema.zig").Api; -const http = @import("../../http.zig"); +const http = @import("../../bun_dev_http_server.zig"); const JavaScript = @import("../javascript.zig"); const QueryStringMap = @import("../../url.zig").QueryStringMap; const CombinedScanner = @import("../../url.zig").CombinedScanner; @@ -287,7 +287,7 @@ pub const JSBundler = struct { defer dir.close(); var rootdir_buf: [bun.MAX_PATH_BYTES]u8 = undefined; - this.rootdir.appendSliceExact(try bun.getFdPath(dir.fd, &rootdir_buf)) catch unreachable; + this.rootdir.appendSliceExact(try bun.getFdPath(bun.toFD(dir.fd), &rootdir_buf)) catch unreachable; } if (try config.getArray(globalThis, "external")) |externals| { diff --git a/src/bun.js/api/JSTranspiler.zig b/src/bun.js/api/JSTranspiler.zig index c31354712..8cec025eb 100644 --- a/src/bun.js/api/JSTranspiler.zig +++ b/src/bun.js/api/JSTranspiler.zig @@ -1,6 +1,6 @@ const std = @import("std"); const Api = @import("../../api/schema.zig").Api; -const http = @import("../../http.zig"); +const http = @import("../../bun_dev_http_server.zig"); const JavaScript = @import("../javascript.zig"); const QueryStringMap = @import("../../url.zig").QueryStringMap; const CombinedScanner = @import("../../url.zig").CombinedScanner; diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig index 71b065993..cf984c81a 100644 --- a/src/bun.js/api/bun.zig +++ b/src/bun.js/api/bun.zig @@ -179,7 +179,7 @@ const ServerEntryPoint = bun.bundler.ServerEntryPoint; const js_printer = bun.js_printer; const js_parser = bun.js_parser; const js_ast = bun.JSAst; -const http = @import("../../http.zig"); +const http = @import("../../bun_dev_http_server.zig"); const NodeFallbackModules = @import("../../node_fallbacks.zig"); const ImportKind = ast.ImportKind; const Analytics = @import("../../analytics/analytics_thread.zig"); @@ -2738,6 +2738,11 @@ pub fn mmapFile( globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame, ) callconv(.C) JSC.JSValue { + if (comptime Environment.isWindows) { + globalThis.throwTODO("mmapFile is not supported on Windows"); + return JSC.JSValue.zero; + } + const arguments_ = callframe.arguments(2); var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments_.slice()); defer args.deinit(); @@ -2789,7 +2794,7 @@ pub fn mmapFile( flags |= std.os.MAP.SHARED; } - const map = switch (JSC.Node.Syscall.mmapFile(buf_z, flags, map_size, offset)) { + const map = switch (bun.sys.mmapFile(buf_z, flags, map_size, offset)) { .result => |map| map, .err => |err| { @@ -2800,7 +2805,7 @@ pub fn mmapFile( return JSC.C.JSObjectMakeTypedArrayWithBytesNoCopy(globalThis, JSC.C.JSTypedArrayType.kJSTypedArrayTypeUint8Array, @as(?*anyopaque, @ptrCast(map.ptr)), map.len, struct { pub fn x(ptr: ?*anyopaque, size: ?*anyopaque) callconv(.C) void { - _ = JSC.Node.Syscall.munmap(@as([*]align(std.mem.page_size) u8, @ptrCast(@alignCast(ptr)))[0..@intFromPtr(size)]); + _ = bun.sys.munmap(@as([*]align(std.mem.page_size) u8, @ptrCast(@alignCast(ptr)))[0..@intFromPtr(size)]); } }.x, @as(?*anyopaque, @ptrFromInt(map.len)), null).?.value(); } diff --git a/src/bun.js/api/bun/dns_resolver.zig b/src/bun.js/api/bun/dns_resolver.zig index 5c9be467f..1a370cd60 100644 --- a/src/bun.js/api/bun/dns_resolver.zig +++ b/src/bun.js/api/bun/dns_resolver.zig @@ -225,6 +225,11 @@ pub fn addressToJS( address: std.net.Address, globalThis: *JSC.JSGlobalObject, ) JSC.JSValue { + if (comptime Environment.isWindows) { + globalThis.throwTODO("TODO: windows"); + return .zero; + } + return addressToString(allocator, address).toValueGC(globalThis); } @@ -823,6 +828,10 @@ pub const GetAddrInfoRequest = struct { query: GetAddrInfo, pub fn run(this: *@This()) void { + if (comptime Environment.isWindows) { + bun.todo(@src(), {}); + return; + } const query = this.query; defer bun.default_allocator.free(bun.constStrToU8(query.name)); var hints = query.options.toLibC(); @@ -842,7 +851,7 @@ pub const GetAddrInfoRequest = struct { if (hints) |*hint| hint else null, &addrinfo, ); - JSC.Node.Syscall.syslog("getaddrinfo({s}, {d}) = {d} ({any})", .{ + bun.sys.syslog("getaddrinfo({s}, {d}) = {d} ({any})", .{ query.name, port, err, @@ -1043,7 +1052,7 @@ pub const DNSLookup = struct { const error_value = brk: { if (err == .ESERVFAIL) { - break :brk JSC.Node.Syscall.Error.fromCode(std.c.getErrno(-1), .getaddrinfo).toJSC(globalThis); + break :brk bun.sys.Error.fromCode(bun.C.getErrno(-1), .getaddrinfo).toJSC(globalThis); } const error_value = globalThis.createErrorInstance("DNS lookup failed: {s}", .{err.label()}); error_value.put( @@ -1435,7 +1444,7 @@ pub const DNSResolver = struct { var poll_entry = this.polls.getOrPut(fd) catch unreachable; if (!poll_entry.found_existing) { - poll_entry.value_ptr.* = JSC.FilePoll.init(vm, fd, .{}, DNSResolver, this); + poll_entry.value_ptr.* = JSC.FilePoll.init(vm, bun.toFD(fd), .{}, DNSResolver, this); } var poll = poll_entry.value_ptr.*.?; diff --git a/src/bun.js/api/bun/spawn.zig b/src/bun.js/api/bun/spawn.zig index be354c7f0..e5678ec44 100644 --- a/src/bun.js/api/bun/spawn.zig +++ b/src/bun.js/api/bun/spawn.zig @@ -206,7 +206,7 @@ pub const PosixSpawn = struct { envp, ); if (comptime bun.Environment.allow_assert) - JSC.Node.Syscall.syslog("posix_spawn({s}) = {d} ({d})", .{ + bun.sys.syslog("posix_spawn({s}) = {d} ({d})", .{ path, rc, pid, diff --git a/src/bun.js/api/bun/subprocess.zig b/src/bun.js/api/bun/subprocess.zig index f2e33cf78..77cf3886e 100644 --- a/src/bun.js/api/bun/subprocess.zig +++ b/src/bun.js/api/bun/subprocess.zig @@ -23,7 +23,7 @@ pub const Subprocess = struct { pid: std.os.pid_t, // on macOS, this is nothing // on linux, it's a pidfd - pidfd: std.os.fd_t = std.math.maxInt(std.os.fd_t), + pidfd: if (Environment.isLinux) bun.FileDescriptor else u0 = std.math.maxInt(if (Environment.isLinux) bun.FileDescriptor else u0), stdin: Writable, stdout: Readable, @@ -36,7 +36,7 @@ pub const Subprocess = struct { exit_code: ?u8 = null, signal_code: ?SignalCode = null, - waitpid_err: ?JSC.Node.Syscall.Error = null, + waitpid_err: ?bun.sys.Error = null, has_waitpid_task: bool = false, notification_task: JSC.AnyTask = undefined, @@ -210,7 +210,7 @@ pub const Subprocess = struct { }; } - pub fn onClose(this: *Readable, _: ?JSC.Node.Syscall.Error) void { + pub fn onClose(this: *Readable, _: ?bun.sys.Error) void { this.* = .closed; } @@ -221,7 +221,7 @@ pub const Subprocess = struct { pub fn close(this: *Readable) void { switch (this.*) { .fd => |fd| { - _ = JSC.Node.Syscall.close(fd); + _ = bun.sys.close(fd); }, .pipe => { this.pipe.done(); @@ -233,7 +233,7 @@ pub const Subprocess = struct { pub fn finalize(this: *Readable) void { switch (this.*) { .fd => |fd| { - _ = JSC.Node.Syscall.close(fd); + _ = bun.sys.close(fd); }, .pipe => { if (this.pipe == .stream and this.pipe.stream.ptr == .File) { @@ -355,7 +355,7 @@ pub const Subprocess = struct { if (comptime Environment.isLinux) { // should this be handled differently? // this effectively shouldn't happen - if (this.pidfd == std.math.maxInt(std.os.fd_t)) { + if (this.pidfd == bun.invalid_fd) { return .{ .result = {} }; } @@ -366,16 +366,16 @@ pub const Subprocess = struct { const errno = std.os.linux.getErrno(rc); // if the process was already killed don't throw if (errno != .SRCH) - return .{ .err = JSC.Node.Syscall.Error.fromCode(errno, .kill) }; + return .{ .err = bun.sys.Error.fromCode(errno, .kill) }; } } else { const err = std.c.kill(this.pid, sig); if (err != 0) { - const errno = std.c.getErrno(err); + const errno = bun.C.getErrno(err); // if the process was already killed don't throw if (errno != .SRCH) - return .{ .err = JSC.Node.Syscall.Error.fromCode(errno, .kill) }; + return .{ .err = bun.sys.Error.fromCode(errno, .kill) }; } } @@ -394,9 +394,9 @@ pub const Subprocess = struct { const pidfd = this.pidfd; - this.pidfd = std.math.maxInt(std.os.fd_t); + this.pidfd = bun.invalid_fd; - if (pidfd != std.math.maxInt(std.os.fd_t)) { + if (pidfd != bun.invalid_fd) { _ = std.os.close(pidfd); } } @@ -492,7 +492,7 @@ pub const Subprocess = struct { } while (to_write.len > 0) { - switch (JSC.Node.Syscall.write(this.fd, to_write)) { + switch (bun.sys.write(this.fd, to_write)) { .err => |e| { if (e.isRetry()) { log("write({d}) retry", .{ @@ -546,7 +546,7 @@ pub const Subprocess = struct { } if (this.fd != bun.invalid_fd) { - _ = JSC.Node.Syscall.close(this.fd); + _ = bun.sys.close(this.fd); this.fd = bun.invalid_fd; } } @@ -576,7 +576,7 @@ pub const Subprocess = struct { pub const Status = union(enum) { pending: void, done: void, - err: JSC.Node.Syscall.Error, + err: bun.sys.Error, }; pub fn init(fd: bun.FileDescriptor) BufferedOutput { @@ -619,7 +619,7 @@ pub const Subprocess = struct { if (err == .Error) { this.status = .{ .err = err.Error }; } else { - this.status = .{ .err = JSC.Node.Syscall.Error.fromCode(.CANCELED, .read) }; + this.status = .{ .err = bun.sys.Error.fromCode(.CANCELED, .read) }; } this.fifo.close(); @@ -838,7 +838,7 @@ pub const Subprocess = struct { // When the stream has closed we need to be notified to prevent a use-after-free // We can test for this use-after-free by enabling hot module reloading on a file and then saving it twice - pub fn onClose(this: *Writable, _: ?JSC.Node.Syscall.Error) void { + pub fn onClose(this: *Writable, _: ?bun.sys.Error) void { this.* = .{ .ignore = {}, }; @@ -916,7 +916,7 @@ pub const Subprocess = struct { _ = pipe_to_readable_stream.pipe.end(null); }, .fd => |fd| { - _ = JSC.Node.Syscall.close(fd); + _ = bun.sys.close(fd); this.* = .{ .ignore = {} }; }, .buffered_input => { @@ -934,7 +934,7 @@ pub const Subprocess = struct { _ = pipe_to_readable_stream.pipe.end(null); }, .fd => |fd| { - _ = JSC.Node.Syscall.close(fd); + _ = bun.sys.close(fd); this.* = .{ .ignore = {} }; }, .buffered_input => { @@ -1035,6 +1035,11 @@ pub const Subprocess = struct { secondaryArgsValue: ?JSValue, comptime is_sync: bool, ) JSValue { + if (comptime Environment.isWindows) { + globalThis.throwTODO("spawn() is not yet implemented on Windows"); + return .zero; + } + var arena = @import("root").bun.ArenaAllocator.init(bun.default_allocator); defer arena.deinit(); var allocator = arena.allocator(); @@ -1204,7 +1209,7 @@ pub const Subprocess = struct { if (stdio_val.jsType().isArray()) { var stdio_iter = stdio_val.arrayIterator(globalThis); stdio_iter.len = @min(stdio_iter.len, 3); - var i: usize = 0; + var i: u32 = 0; while (stdio_iter.next()) |value| : (i += 1) { if (!extractStdio(globalThis, i, value, &stdio)) return JSC.JSValue.jsUndefined(); @@ -1216,17 +1221,17 @@ pub const Subprocess = struct { } } else { if (args.get(globalThis, "stdin")) |value| { - if (!extractStdio(globalThis, std.os.STDIN_FILENO, value, &stdio)) + if (!extractStdio(globalThis, bun.STDIN_FD, value, &stdio)) return .zero; } if (args.get(globalThis, "stderr")) |value| { - if (!extractStdio(globalThis, std.os.STDERR_FILENO, value, &stdio)) + if (!extractStdio(globalThis, bun.STDERR_FD, value, &stdio)) return .zero; } if (args.get(globalThis, "stdout")) |value| { - if (!extractStdio(globalThis, std.os.STDOUT_FILENO, value, &stdio)) + if (!extractStdio(globalThis, bun.STDOUT_FD, value, &stdio)) return .zero; } } @@ -1282,19 +1287,19 @@ pub const Subprocess = struct { stdio[0].setUpChildIoPosixSpawn( &actions, stdin_pipe, - std.os.STDIN_FILENO, + bun.STDIN_FD, ) catch |err| return globalThis.handleError(err, "in configuring child stdin"); stdio[1].setUpChildIoPosixSpawn( &actions, stdout_pipe, - std.os.STDOUT_FILENO, + bun.STDOUT_FD, ) catch |err| return globalThis.handleError(err, "in configuring child stdout"); stdio[2].setUpChildIoPosixSpawn( &actions, stderr_pipe, - std.os.STDERR_FILENO, + bun.STDERR_FD, ) catch |err| return globalThis.handleError(err, "in configuring child stderr"); actions.chdir(cwd) catch |err| return globalThis.handleError(err, "in chdir()"); @@ -1313,15 +1318,15 @@ pub const Subprocess = struct { const pid = brk: { defer { if (stdio[0].isPiped()) { - _ = JSC.Node.Syscall.close(stdin_pipe[0]); + _ = bun.sys.close(stdin_pipe[0]); } if (stdio[1].isPiped()) { - _ = JSC.Node.Syscall.close(stdout_pipe[1]); + _ = bun.sys.close(stdout_pipe[1]); } if (stdio[2].isPiped()) { - _ = JSC.Node.Syscall.close(stderr_pipe[1]); + _ = bun.sys.close(stderr_pipe[1]); } } @@ -1332,8 +1337,8 @@ pub const Subprocess = struct { }; const pidfd: std.os.fd_t = brk: { - if (Environment.isMac) { - break :brk @as(std.os.fd_t, @intCast(pid)); + if (!Environment.isLinux) { + break :brk pid; } const kernel = @import("../../../analytics.zig").GenerateHeader.GeneratePlatform.kernelVersion(); @@ -1352,7 +1357,7 @@ pub const Subprocess = struct { switch (std.os.linux.getErrno(fd)) { .SUCCESS => break :brk @as(std.os.fd_t, @intCast(fd)), else => |err| { - globalThis.throwValue(JSC.Node.Syscall.Error.fromCode(err, .open).toJSC(globalThis)); + globalThis.throwValue(bun.sys.Error.fromCode(err, .open).toJSC(globalThis)); var status: u32 = 0; // ensure we don't leak the child process on error _ = std.os.linux.waitpid(pid, &status, 0); @@ -1370,14 +1375,14 @@ pub const Subprocess = struct { subprocess.* = Subprocess{ .globalThis = globalThis, .pid = pid, - .pidfd = pidfd, - .stdin = Writable.init(stdio[std.os.STDIN_FILENO], stdin_pipe[1], globalThis) catch { + .pidfd = @truncate(pidfd), + .stdin = Writable.init(stdio[bun.STDIN_FD], stdin_pipe[1], globalThis) catch { globalThis.throw("out of memory", .{}); return .zero; }, // stdout and stderr only uses allocator and default_max_buffer_size if they are pipes and not a array buffer - .stdout = Readable.init(stdio[std.os.STDOUT_FILENO], stdout_pipe[0], jsc_vm.allocator, default_max_buffer_size), - .stderr = Readable.init(stdio[std.os.STDERR_FILENO], stderr_pipe[0], jsc_vm.allocator, default_max_buffer_size), + .stdout = Readable.init(stdio[bun.STDOUT_FD], stdout_pipe[0], jsc_vm.allocator, default_max_buffer_size), + .stderr = Readable.init(stdio[bun.STDERR_FD], stderr_pipe[0], jsc_vm.allocator, default_max_buffer_size), .on_exit_callback = if (on_exit_callback != .zero) JSC.Strong.create(on_exit_callback, globalThis) else .{}, .is_sync = is_sync, }; @@ -1393,9 +1398,10 @@ pub const Subprocess = struct { subprocess.this_jsvalue = out; var send_exit_notification = false; + const watchfd = if (comptime Environment.isLinux) pidfd else pid; if (comptime !is_sync) { - var poll = JSC.FilePoll.init(jsc_vm, pidfd, .{}, Subprocess, subprocess); + var poll = JSC.FilePoll.init(jsc_vm, watchfd, .{}, Subprocess, subprocess); subprocess.poll_ref = poll; switch (subprocess.poll_ref.?.register( jsc_vm.uws_event_loop.?, @@ -1458,7 +1464,7 @@ pub const Subprocess = struct { subprocess.closeIO(.stdin); { - var poll = JSC.FilePoll.init(jsc_vm, pidfd, .{}, Subprocess, subprocess); + var poll = JSC.FilePoll.init(jsc_vm, watchfd, .{}, Subprocess, subprocess); subprocess.poll_ref = poll; switch (subprocess.poll_ref.?.register( jsc_vm.uws_event_loop.?, @@ -1680,7 +1686,7 @@ pub const Subprocess = struct { try actions.dup2(fd, std_fileno); }, .path => |pathlike| { - const flag = if (std_fileno == std.os.STDIN_FILENO) @as(u32, os.O.RDONLY) else @as(u32, std.os.O.WRONLY); + const flag = if (std_fileno == bun.STDIN_FD) @as(u32, os.O.RDONLY) else @as(u32, std.os.O.WRONLY); try actions.open(std_fileno, pathlike.slice(), flag | std.os.O.CREAT, 0o664); }, .inherit => { @@ -1692,7 +1698,7 @@ pub const Subprocess = struct { }, .ignore => { - const flag = if (std_fileno == std.os.STDIN_FILENO) @as(u32, os.O.RDONLY) else @as(u32, std.os.O.WRONLY); + const flag = if (std_fileno == bun.STDIN_FD) @as(u32, os.O.RDONLY) else @as(u32, std.os.O.WRONLY); try actions.openZ(std_fileno, "/dev/null", flag, 0o664); }, } @@ -1702,25 +1708,27 @@ pub const Subprocess = struct { fn extractStdioBlob( globalThis: *JSC.JSGlobalObject, blob: JSC.WebCore.AnyBlob, - i: usize, + i: u32, stdio_array: []Stdio, ) bool { + const fd = bun.stdio(i); + if (blob.needsToReadFile()) { if (blob.store()) |store| { if (store.data.file.pathlike == .fd) { - if (store.data.file.pathlike.fd == @as(bun.FileDescriptor, @intCast(i))) { + if (store.data.file.pathlike.fd == fd) { stdio_array[i] = Stdio{ .inherit = {} }; } else { - switch (@as(std.os.fd_t, @intCast(i))) { - std.os.STDIN_FILENO => { - if (i == std.os.STDERR_FILENO or i == std.os.STDOUT_FILENO) { + switch (bun.FDTag.get(i)) { + .stdin => { + if (i == 1 or i == 2) { globalThis.throwInvalidArguments("stdin cannot be used for stdout or stderr", .{}); return false; } }, - std.os.STDOUT_FILENO, std.os.STDERR_FILENO => { - if (i == std.os.STDIN_FILENO) { + .stdout, .stderr => { + if (i == 0) { globalThis.throwInvalidArguments("stdout and stderr cannot be used for stdin", .{}); return false; } @@ -1745,7 +1753,7 @@ pub const Subprocess = struct { fn extractStdio( globalThis: *JSC.JSGlobalObject, - i: usize, + i: u32, value: JSValue, stdio_array: []Stdio, ) bool { @@ -1776,16 +1784,16 @@ pub const Subprocess = struct { const fd = @as(bun.FileDescriptor, @intCast(fd_)); - switch (@as(std.os.fd_t, @intCast(i))) { - std.os.STDIN_FILENO => { - if (i == std.os.STDERR_FILENO or i == std.os.STDOUT_FILENO) { + switch (bun.FDTag.get(fd)) { + .stdin => { + if (i == bun.STDERR_FD or i == bun.STDOUT_FD) { globalThis.throwInvalidArguments("stdin cannot be used for stdout or stderr", .{}); return false; } }, - std.os.STDOUT_FILENO, std.os.STDERR_FILENO => { - if (i == std.os.STDIN_FILENO) { + .stdout, .stderr => { + if (i == bun.STDIN_FD) { globalThis.throwInvalidArguments("stdout and stderr cannot be used for stdin", .{}); return false; } @@ -1806,7 +1814,7 @@ pub const Subprocess = struct { return extractStdioBlob(globalThis, req.getBodyValue().useAsAnyBlob(), i, stdio_array); } else if (JSC.WebCore.ReadableStream.fromJS(value, globalThis)) |req_const| { var req = req_const; - if (i == std.os.STDIN_FILENO) { + if (i == bun.STDIN_FD) { if (req.toAnyBlob(globalThis)) |blob| { return extractStdioBlob(globalThis, blob, i, stdio_array); } diff --git a/src/bun.js/api/ffi.zig b/src/bun.js/api/ffi.zig index 1b265af11..097b66d35 100644 --- a/src/bun.js/api/ffi.zig +++ b/src/bun.js/api/ffi.zig @@ -25,7 +25,7 @@ const ServerEntryPoint = bun.bundler.ServerEntryPoint; const js_printer = bun.js_printer; const js_parser = bun.js_parser; const js_ast = bun.JSAst; -const http = @import("../../http.zig"); +const http = @import("../../bun_dev_http_server.zig"); const NodeFallbackModules = @import("../../node_fallbacks.zig"); const ImportKind = ast.ImportKind; const Analytics = @import("../../analytics/analytics_thread.zig"); @@ -722,7 +722,7 @@ pub const FFI = struct { var runtime_path = std.fs.path.join(default_allocator, &[_]string{ dir, "FFI.h" }) catch unreachable; const file = std.fs.openFileAbsolute(runtime_path, .{}) catch @panic("Missing bun/src/bun.js/api/FFI.h."); defer file.close(); - return file.readToEndAlloc(default_allocator, (file.stat() catch unreachable).size) catch unreachable; + return file.readToEndAlloc(default_allocator, file.getEndPos() catch unreachable) catch unreachable; } else { return FFI_HEADER; } @@ -937,7 +937,7 @@ pub const FFI = struct { var ffi_wrapper = Bun__createFFICallbackFunction(js_context, js_function); try this.printCallbackSourceCode(js_context, ffi_wrapper, &source_code_writer); - if (comptime Environment.allow_assert) { + if (comptime Environment.allow_assert and Environment.isPosix) { debug_write: { const fd = std.os.open("/tmp/bun-ffi-callback-source.c", std.os.O.WRONLY | std.os.O.CREAT, 0o644) catch break :debug_write; _ = std.os.write(fd, source_code.items) catch break :debug_write; diff --git a/src/bun.js/api/filesystem_router.zig b/src/bun.js/api/filesystem_router.zig index c15826c31..f33066298 100644 --- a/src/bun.js/api/filesystem_router.zig +++ b/src/bun.js/api/filesystem_router.zig @@ -1,6 +1,6 @@ const std = @import("std"); const Api = @import("../../api/schema.zig").Api; -const http = @import("../../http.zig"); +const http = @import("../../bun_dev_http_server.zig"); const JavaScript = @import("../javascript.zig"); const QueryStringMap = @import("../../url.zig").QueryStringMap; const CombinedScanner = @import("../../url.zig").CombinedScanner; diff --git a/src/bun.js/api/html_rewriter.zig b/src/bun.js/api/html_rewriter.zig index fd0b5dd9e..86c2c4b53 100644 --- a/src/bun.js/api/html_rewriter.zig +++ b/src/bun.js/api/html_rewriter.zig @@ -199,7 +199,7 @@ pub const HTMLRewriter = struct { this.finalized = true; } - pub fn fail(this: *HTMLRewriterLoader, err: JSC.Node.Syscall.Error) void { + pub fn fail(this: *HTMLRewriterLoader, err: bun.sys.Error) void { this.signal.close(err); this.output.end(err); this.failed = true; @@ -213,7 +213,7 @@ pub const HTMLRewriter = struct { pub fn writeToDestination(this: *HTMLRewriterLoader, bytes: []const u8) void { if (this.backpressure.count > 0) { this.backpressure.write(bytes) catch { - this.fail(JSC.Node.Syscall.Error.oom); + this.fail(bun.sys.Error.oom); this.finalize(); }; return; @@ -287,9 +287,9 @@ pub const HTMLRewriter = struct { return JSC.WebCore.Sink.init(this); } - fn writeBytes(this: *HTMLRewriterLoader, bytes: bun.ByteList, comptime deinit_: bool) ?JSC.Node.Syscall.Error { + fn writeBytes(this: *HTMLRewriterLoader, bytes: bun.ByteList, comptime deinit_: bool) ?bun.sys.Error { this.rewriter.write(bytes.slice()) catch { - return JSC.Node.Syscall.Error{ + return bun.sys.Error{ .errno = 1, // TODO: make this a union .path = bun.default_allocator.dupe(u8, LOLHTML.HTMLString.lastError().slice()) catch unreachable, diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig index 01f06ebf2..ffe24f0f6 100644 --- a/src/bun.js/api/server.zig +++ b/src/bun.js/api/server.zig @@ -24,7 +24,7 @@ const ServerEntryPoint = bun.bundler.ServerEntryPoint; const js_printer = bun.js_printer; const js_parser = bun.js_parser; const js_ast = bun.JSAst; -const http = @import("../../http.zig"); +const http = @import("../../bun_dev_http_server.zig"); const NodeFallbackModules = @import("../../node_fallbacks.zig"); const ImportKind = ast.ImportKind; const Analytics = @import("../../analytics/analytics_thread.zig"); @@ -80,7 +80,7 @@ const Blob = JSC.WebCore.Blob; const BoringSSL = @import("root").bun.BoringSSL; const Arena = @import("../../mimalloc_arena.zig").Arena; const SendfileContext = struct { - fd: i32, + fd: bun.FileDescriptor, socket_fd: i32 = 0, remain: Blob.SizeType = 0, offset: Blob.SizeType = 0, @@ -1182,7 +1182,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp defer_deinit_until_callback_completes: ?*bool = null, // TODO: support builtin compression - const can_sendfile = !ssl_enabled; + // TODO: Use TransmitFile on Windows + const can_sendfile = !ssl_enabled and !bun.Environment.isWindows; pub inline fn isAsync(this: *const RequestContext) bool { return this.defer_deinit_until_callback_completes == null; @@ -1744,7 +1745,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp } // use node syscall so that we don't segfault on BADF if (this.sendfile.auto_close) - _ = JSC.Node.Syscall.close(this.sendfile.fd); + _ = bun.sys.close(this.sendfile.fd); this.sendfile = undefined; this.finalize(); } @@ -1837,8 +1838,9 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp return true; } - pub fn sendWritableBytesForBlob(this: *RequestContext, bytes_: []const u8, write_offset: c_ulong, resp: *App.Response) bool { + pub fn sendWritableBytesForBlob(this: *RequestContext, bytes_: []const u8, write_offset_: c_ulong, resp: *App.Response) bool { std.debug.assert(this.resp == resp); + const write_offset: usize = write_offset_; var bytes = bytes_[@min(bytes_.len, @as(usize, @truncate(write_offset)))..]; if (resp.tryEnd(bytes, bytes_.len, this.shouldCloseConnection())) { @@ -1851,7 +1853,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp } } - pub fn sendWritableBytesForCompleteResponseBuffer(this: *RequestContext, bytes_: []const u8, write_offset: c_ulong, resp: *App.Response) bool { + pub fn sendWritableBytesForCompleteResponseBuffer(this: *RequestContext, bytes_: []const u8, write_offset_: c_ulong, resp: *App.Response) bool { + const write_offset: usize = write_offset_; std.debug.assert(this.resp == resp); var bytes = bytes_[@min(bytes_.len, @as(usize, @truncate(write_offset)))..]; @@ -1882,7 +1885,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp const auto_close = file.pathlike != .fd; const fd = if (!auto_close) file.pathlike.fd - else switch (JSC.Node.Syscall.open(file.pathlike.path.sliceZ(&file_buf), std.os.O.RDONLY | std.os.O.NONBLOCK | std.os.O.CLOEXEC, 0)) { + else switch (bun.sys.open(file.pathlike.path.sliceZ(&file_buf), std.os.O.RDONLY | std.os.O.NONBLOCK | std.os.O.CLOEXEC, 0)) { .result => |_fd| _fd, .err => |err| return this.runErrorHandler(err.withPath(file.pathlike.path.slice()).toSystemError().toErrorInstance( this.server.globalThis, @@ -1890,27 +1893,27 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp }; // stat only blocks if the target is a file descriptor - const stat: std.os.Stat = switch (JSC.Node.Syscall.fstat(fd)) { + const stat: bun.Stat = switch (bun.sys.fstat(fd)) { .result => |result| result, .err => |err| { this.runErrorHandler(err.withPathLike(file.pathlike).toSystemError().toErrorInstance( this.server.globalThis, )); if (auto_close) { - _ = JSC.Node.Syscall.close(fd); + _ = bun.sys.close(fd); } return; }, }; if (Environment.isMac) { - if (!std.os.S.ISREG(stat.mode)) { + if (!bun.isRegularFile(stat.mode)) { if (auto_close) { - _ = JSC.Node.Syscall.close(fd); + _ = bun.sys.close(fd); } - var err = JSC.Node.Syscall.Error{ - .errno = @as(JSC.Node.Syscall.Error.Int, @intCast(@intFromEnum(std.os.E.INVAL))), + var err = bun.sys.Error{ + .errno = @as(bun.sys.Error.Int, @intCast(@intFromEnum(std.os.E.INVAL))), .syscall = .sendfile, }; var sys = err.withPathLike(file.pathlike).toSystemError(); @@ -1923,13 +1926,13 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp } if (Environment.isLinux) { - if (!(std.os.S.ISREG(stat.mode) or std.os.S.ISFIFO(stat.mode))) { + if (!(bun.isRegularFile(stat.mode) or std.os.S.ISFIFO(stat.mode))) { if (auto_close) { - _ = JSC.Node.Syscall.close(fd); + _ = bun.sys.close(fd); } - var err = JSC.Node.Syscall.Error{ - .errno = @as(JSC.Node.Syscall.Error.Int, @intCast(@intFromEnum(std.os.E.INVAL))), + var err = bun.sys.Error{ + .errno = @as(bun.sys.Error.Int, @intCast(@intFromEnum(std.os.E.INVAL))), .syscall = .sendfile, }; var sys = err.withPathLike(file.pathlike).toSystemError(); @@ -1943,7 +1946,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp const original_size = this.blob.Blob.size; const stat_size = @as(Blob.SizeType, @intCast(stat.size)); - this.blob.Blob.size = if (std.os.S.ISREG(stat.mode)) + this.blob.Blob.size = if (bun.isRegularFile(stat.mode)) stat_size else @min(original_size, stat_size); @@ -1961,12 +1964,12 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp // if we are sending only part of a file, include the content-range header // only include content-range automatically when using a file path instead of an fd // this is to better support manually controlling the behavior - if (std.os.S.ISREG(stat.mode) and auto_close) { + if (bun.isRegularFile(stat.mode) and auto_close) { this.flags.needs_content_range = (this.sendfile.remain -| this.sendfile.offset) != stat_size; } // we know the bounds when we are sending a regular file - if (std.os.S.ISREG(stat.mode)) { + if (bun.isRegularFile(stat.mode)) { this.sendfile.offset = @min(this.sendfile.offset, stat_size); this.sendfile.remain = @min(@max(this.sendfile.remain, this.sendfile.offset), stat_size) -| this.sendfile.offset; } @@ -2035,7 +2038,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp // this is used by content-range this.sendfile = .{ - .fd = @as(i32, @truncate(bun.invalid_fd)), + .fd = bun.invalid_fd, .remain = @as(Blob.SizeType, @truncate(result.result.buf.len)), .offset = this.blob.Blob.offset, .auto_close = false, diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig index 66cc50f5d..44f33d670 100644 --- a/src/bun.js/base.zig +++ b/src/bun.js/base.zig @@ -1696,7 +1696,7 @@ const KQueueGenerationNumber = if (Environment.isMac and Environment.allow_asser pub const FilePoll = struct { var max_generation_number: KQueueGenerationNumber = 0; - fd: u32 = invalid_fd, + fd: bun.UFileDescriptor = invalid_fd, flags: Flags.Set = Flags.Set{}, owner: Owner = undefined, @@ -2009,7 +2009,7 @@ pub const FilePoll = struct { pub fn initWithOwner(vm: *JSC.VirtualMachine, fd: bun.FileDescriptor, flags: Flags.Struct, owner: Owner) *FilePoll { var poll = vm.rareData().filePolls(vm).get(); - poll.fd = @as(u32, @intCast(fd)); + poll.fd = @intCast(fd); poll.flags = Flags.Set.init(flags); poll.owner = owner; if (KQueueGenerationNumber != u0) { @@ -2194,11 +2194,11 @@ pub const FilePoll = struct { if (errno != .SUCCESS) { return JSC.Maybe(void){ - .err = JSC.Node.Syscall.Error.fromCode(errno, .kqueue), + .err = bun.sys.Error.fromCode(errno, .kqueue), }; } } else { - @compileError("TODO: Pollable"); + bun.todo(@src(), {}); } if (this.canActivate()) this.activate(loop); @@ -2220,7 +2220,7 @@ pub const FilePoll = struct { return this.unregisterWithFd(loop, this.fd); } - pub fn unregisterWithFd(this: *FilePoll, loop: *uws.Loop, fd: u64) JSC.Maybe(void) { + pub fn unregisterWithFd(this: *FilePoll, loop: *uws.Loop, fd: bun.UFileDescriptor) JSC.Maybe(void) { if (!(this.flags.contains(.poll_readable) or this.flags.contains(.poll_writable) or this.flags.contains(.poll_process) or this.flags.contains(.poll_machport))) { // no-op return JSC.Maybe(void).success; @@ -2338,7 +2338,7 @@ pub const FilePoll = struct { else => {}, } } else { - @compileError("TODO: Pollable"); + bun.todo(@src(), {}); } this.flags.remove(.needs_rearm); diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index c8c87648a..870b78738 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -2499,6 +2499,12 @@ pub const JSGlobalObject = extern struct { this.throwValue(this.createErrorInstance("Out of memory", .{})); } + pub fn throwTODO(this: *JSGlobalObject, msg: []const u8) void { + const err = this.createErrorInstance("{s}", .{msg}); + err.put(this, ZigString.static("name"), bun.String.static("TODOError").toJSConst(this)); + this.throwValue(err); + } + extern fn JSGlobalObject__clearTerminationException(this: *JSGlobalObject) void; extern fn JSGlobalObject__throwTerminationException(this: *JSGlobalObject) void; pub const throwTerminationException = JSGlobalObject__throwTerminationException; @@ -3763,7 +3769,14 @@ pub const JSValue = enum(JSValueReprInt) { else => jsNumberFromInt64(@as(i64, @intCast(number))), }, // u0 => jsNumberFromInt32(0), - else => @compileError("Type transformation missing for number of type: " ++ @typeName(Number)), + else => { + // windows + if (comptime Number == std.os.fd_t) { + return jsNumber(bun.toFD(number)); + } + + @compileError("Type transformation missing for number of type: " ++ @typeName(Number)); + }, }; } diff --git a/src/bun.js/bindings/headers.zig b/src/bun.js/bindings/headers.zig index a696e86b1..6d8f0e774 100644 --- a/src/bun.js/bindings/headers.zig +++ b/src/bun.js/bindings/headers.zig @@ -81,303 +81,303 @@ pub const JSC__JSObject = bJSC__JSObject; pub const JSC__JSCell = bJSC__JSCell; pub const JSC__JSGlobalObject = bJSC__JSGlobalObject; pub const JSC__JSInternalPromise = bJSC__JSInternalPromise; -pub extern fn JSC__JSObject__create(arg0: *bindings.JSGlobalObject, arg1: usize, arg2: ?*anyopaque, ArgFn3: ?*const fn (?*anyopaque, [*c]bindings.JSObject, *bindings.JSGlobalObject) callconv(.C) void) JSC__JSValue; -pub extern fn JSC__JSObject__getArrayLength(arg0: [*c]bindings.JSObject) usize; -pub extern fn JSC__JSObject__getDirect(arg0: [*c]bindings.JSObject, arg1: *bindings.JSGlobalObject, arg2: [*c]const ZigString) JSC__JSValue; -pub extern fn JSC__JSObject__getIndex(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: u32) JSC__JSValue; -pub extern fn JSC__JSObject__putRecord(arg0: [*c]bindings.JSObject, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString, arg3: [*c]ZigString, arg4: usize) void; -pub extern fn ZigString__external(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (?*anyopaque, ?*anyopaque, usize) callconv(.C) void) JSC__JSValue; -pub extern fn ZigString__to16BitValue(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn ZigString__toAtomicValue(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn ZigString__toErrorInstance(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn ZigString__toExternalU16(arg0: [*c]const u16, arg1: usize, arg2: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn ZigString__toExternalValue(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn ZigString__toExternalValueWithCallback(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject, ArgFn2: ?*const fn (?*anyopaque, ?*anyopaque, usize) callconv(.C) void) JSC__JSValue; -pub extern fn ZigString__toRangeErrorInstance(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn ZigString__toSyntaxErrorInstance(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn ZigString__toTypeErrorInstance(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn ZigString__toValue(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn ZigString__toValueGC(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn WebCore__DOMURL__cast_(JSValue0: JSC__JSValue, arg1: *bindings.VM) ?*bindings.DOMURL; -pub extern fn WebCore__DOMURL__fileSystemPath(arg0: ?*bindings.DOMURL) BunString; -pub extern fn WebCore__DOMURL__href_(arg0: ?*bindings.DOMURL, arg1: [*c]ZigString) void; -pub extern fn WebCore__DOMURL__pathname_(arg0: ?*bindings.DOMURL, arg1: [*c]ZigString) void; -pub extern fn WebCore__DOMFormData__append(arg0: ?*bindings.DOMFormData, arg1: [*c]ZigString, arg2: [*c]ZigString) void; -pub extern fn WebCore__DOMFormData__appendBlob(arg0: ?*bindings.DOMFormData, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString, arg3: ?*anyopaque, arg4: [*c]ZigString) void; -pub extern fn WebCore__DOMFormData__count(arg0: ?*bindings.DOMFormData) usize; -pub extern fn WebCore__DOMFormData__create(arg0: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn WebCore__DOMFormData__createFromURLQuery(arg0: *bindings.JSGlobalObject, arg1: [*c]ZigString) JSC__JSValue; -pub extern fn WebCore__DOMFormData__fromJS(JSValue0: JSC__JSValue) ?*bindings.DOMFormData; -pub extern fn WebCore__FetchHeaders__append(arg0: ?*bindings.FetchHeaders, arg1: [*c]const ZigString, arg2: [*c]const ZigString, arg3: *bindings.JSGlobalObject) void; -pub extern fn WebCore__FetchHeaders__cast_(JSValue0: JSC__JSValue, arg1: *bindings.VM) ?*bindings.FetchHeaders; -pub extern fn WebCore__FetchHeaders__clone(arg0: ?*bindings.FetchHeaders, arg1: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn WebCore__FetchHeaders__cloneThis(arg0: ?*bindings.FetchHeaders, arg1: *bindings.JSGlobalObject) ?*bindings.FetchHeaders; -pub extern fn WebCore__FetchHeaders__copyTo(arg0: ?*bindings.FetchHeaders, arg1: [*c]StringPointer, arg2: [*c]StringPointer, arg3: [*c]u8) void; -pub extern fn WebCore__FetchHeaders__count(arg0: ?*bindings.FetchHeaders, arg1: [*c]u32, arg2: [*c]u32) void; -pub extern fn WebCore__FetchHeaders__createEmpty(...) ?*bindings.FetchHeaders; -pub extern fn WebCore__FetchHeaders__createFromJS(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) ?*bindings.FetchHeaders; -pub extern fn WebCore__FetchHeaders__createFromPicoHeaders_(arg0: ?*const anyopaque) ?*bindings.FetchHeaders; -pub extern fn WebCore__FetchHeaders__createFromUWS(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque) ?*bindings.FetchHeaders; -pub extern fn WebCore__FetchHeaders__createValue(arg0: *bindings.JSGlobalObject, arg1: [*c]StringPointer, arg2: [*c]StringPointer, arg3: [*c]const ZigString, arg4: u32) JSC__JSValue; -pub extern fn WebCore__FetchHeaders__deref(arg0: ?*bindings.FetchHeaders) void; -pub extern fn WebCore__FetchHeaders__fastGet_(arg0: ?*bindings.FetchHeaders, arg1: u8, arg2: [*c]ZigString) void; -pub extern fn WebCore__FetchHeaders__fastHas_(arg0: ?*bindings.FetchHeaders, arg1: u8) bool; -pub extern fn WebCore__FetchHeaders__fastRemove_(arg0: ?*bindings.FetchHeaders, arg1: u8) void; -pub extern fn WebCore__FetchHeaders__get_(arg0: ?*bindings.FetchHeaders, arg1: [*c]const ZigString, arg2: [*c]ZigString, arg3: *bindings.JSGlobalObject) void; -pub extern fn WebCore__FetchHeaders__has(arg0: ?*bindings.FetchHeaders, arg1: [*c]const ZigString, arg2: *bindings.JSGlobalObject) bool; -pub extern fn WebCore__FetchHeaders__isEmpty(arg0: ?*bindings.FetchHeaders) bool; -pub extern fn WebCore__FetchHeaders__put_(arg0: ?*bindings.FetchHeaders, arg1: [*c]const ZigString, arg2: [*c]const ZigString, arg3: *bindings.JSGlobalObject) void; -pub extern fn WebCore__FetchHeaders__remove(arg0: ?*bindings.FetchHeaders, arg1: [*c]const ZigString, arg2: *bindings.JSGlobalObject) void; -pub extern fn WebCore__FetchHeaders__toJS(arg0: ?*bindings.FetchHeaders, arg1: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn WebCore__FetchHeaders__toUWSResponse(arg0: ?*bindings.FetchHeaders, arg1: bool, arg2: ?*anyopaque) void; -pub extern fn SystemError__toErrorInstance(arg0: [*c]const SystemError, arg1: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn JSC__JSCell__getObject(arg0: [*c]bindings.JSCell) [*c]bindings.JSObject; -pub extern fn JSC__JSCell__getType(arg0: [*c]bindings.JSCell) u8; -pub extern fn JSC__JSString__eql(arg0: [*c]const JSC__JSString, arg1: *bindings.JSGlobalObject, arg2: [*c]bindings.JSString) bool; -pub extern fn JSC__JSString__is8Bit(arg0: [*c]const JSC__JSString) bool; -pub extern fn JSC__JSString__iterator(arg0: [*c]bindings.JSString, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque) void; -pub extern fn JSC__JSString__length(arg0: [*c]const JSC__JSString) usize; -pub extern fn JSC__JSString__toObject(arg0: [*c]bindings.JSString, arg1: *bindings.JSGlobalObject) [*c]bindings.JSObject; -pub extern fn JSC__JSString__toZigString(arg0: [*c]bindings.JSString, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString) void; -pub extern fn JSC__JSModuleLoader__evaluate(arg0: *bindings.JSGlobalObject, arg1: [*c]const u8, arg2: usize, arg3: [*c]const u8, arg4: usize, arg5: [*c]const u8, arg6: usize, JSValue7: JSC__JSValue, arg8: [*c]bindings.JSValue) JSC__JSValue; -pub extern fn JSC__JSModuleLoader__loadAndEvaluateModule(arg0: *bindings.JSGlobalObject, arg1: [*c]const BunString) [*c]bindings.JSInternalPromise; -pub extern fn WebCore__AbortSignal__aborted(arg0: ?*bindings.AbortSignal) bool; -pub extern fn WebCore__AbortSignal__abortReason(arg0: ?*bindings.AbortSignal) JSC__JSValue; -pub extern fn WebCore__AbortSignal__addListener(arg0: ?*bindings.AbortSignal, arg1: ?*anyopaque, ArgFn2: ?*const fn (?*anyopaque, JSC__JSValue) callconv(.C) void) ?*bindings.AbortSignal; -pub extern fn WebCore__AbortSignal__cleanNativeBindings(arg0: ?*bindings.AbortSignal, arg1: ?*anyopaque) void; -pub extern fn WebCore__AbortSignal__create(arg0: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn WebCore__AbortSignal__createAbortError(arg0: [*c]const ZigString, arg1: [*c]const ZigString, arg2: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn WebCore__AbortSignal__createTimeoutError(arg0: [*c]const ZigString, arg1: [*c]const ZigString, arg2: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn WebCore__AbortSignal__fromJS(JSValue0: JSC__JSValue) ?*bindings.AbortSignal; -pub extern fn WebCore__AbortSignal__ref(arg0: ?*bindings.AbortSignal) ?*bindings.AbortSignal; -pub extern fn WebCore__AbortSignal__signal(arg0: ?*bindings.AbortSignal, JSValue1: JSC__JSValue) ?*bindings.AbortSignal; -pub extern fn WebCore__AbortSignal__toJS(arg0: ?*bindings.AbortSignal, arg1: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn WebCore__AbortSignal__unref(arg0: ?*bindings.AbortSignal) ?*bindings.AbortSignal; -pub extern fn JSC__JSPromise__asValue(arg0: ?*bindings.JSPromise, arg1: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn JSC__JSPromise__create(arg0: *bindings.JSGlobalObject) ?*bindings.JSPromise; -pub extern fn JSC__JSPromise__isHandled(arg0: [*c]const JSC__JSPromise, arg1: *bindings.VM) bool; -pub extern fn JSC__JSPromise__reject(arg0: ?*bindings.JSPromise, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; -pub extern fn JSC__JSPromise__rejectAsHandled(arg0: ?*bindings.JSPromise, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; -pub extern fn JSC__JSPromise__rejectAsHandledException(arg0: ?*bindings.JSPromise, arg1: *bindings.JSGlobalObject, arg2: [*c]bindings.Exception) void; -pub extern fn JSC__JSPromise__rejectedPromise(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) ?*bindings.JSPromise; -pub extern fn JSC__JSPromise__rejectedPromiseValue(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) JSC__JSValue; -pub extern fn JSC__JSPromise__rejectOnNextTickWithHandled(arg0: ?*bindings.JSPromise, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue, arg3: bool) void; -pub extern fn JSC__JSPromise__rejectWithCaughtException(arg0: ?*bindings.JSPromise, arg1: *bindings.JSGlobalObject, arg2: bJSC__ThrowScope) void; -pub extern fn JSC__JSPromise__resolve(arg0: ?*bindings.JSPromise, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; -pub extern fn JSC__JSPromise__resolvedPromise(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) ?*bindings.JSPromise; -pub extern fn JSC__JSPromise__resolvedPromiseValue(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) JSC__JSValue; -pub extern fn JSC__JSPromise__resolveOnNextTick(arg0: ?*bindings.JSPromise, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; -pub extern fn JSC__JSPromise__result(arg0: ?*bindings.JSPromise, arg1: *bindings.VM) JSC__JSValue; -pub extern fn JSC__JSPromise__setHandled(arg0: ?*bindings.JSPromise, arg1: *bindings.VM) void; -pub extern fn JSC__JSPromise__status(arg0: [*c]const JSC__JSPromise, arg1: *bindings.VM) u32; -pub extern fn JSC__JSInternalPromise__create(arg0: *bindings.JSGlobalObject) [*c]bindings.JSInternalPromise; -pub extern fn JSC__JSInternalPromise__isHandled(arg0: [*c]const JSC__JSInternalPromise, arg1: *bindings.VM) bool; -pub extern fn JSC__JSInternalPromise__reject(arg0: [*c]bindings.JSInternalPromise, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; -pub extern fn JSC__JSInternalPromise__rejectAsHandled(arg0: [*c]bindings.JSInternalPromise, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; -pub extern fn JSC__JSInternalPromise__rejectAsHandledException(arg0: [*c]bindings.JSInternalPromise, arg1: *bindings.JSGlobalObject, arg2: [*c]bindings.Exception) void; -pub extern fn JSC__JSInternalPromise__rejectedPromise(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) [*c]bindings.JSInternalPromise; -pub extern fn JSC__JSInternalPromise__rejectWithCaughtException(arg0: [*c]bindings.JSInternalPromise, arg1: *bindings.JSGlobalObject, arg2: bJSC__ThrowScope) void; -pub extern fn JSC__JSInternalPromise__resolve(arg0: [*c]bindings.JSInternalPromise, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; -pub extern fn JSC__JSInternalPromise__resolvedPromise(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) [*c]bindings.JSInternalPromise; -pub extern fn JSC__JSInternalPromise__result(arg0: [*c]const JSC__JSInternalPromise, arg1: *bindings.VM) JSC__JSValue; -pub extern fn JSC__JSInternalPromise__setHandled(arg0: [*c]bindings.JSInternalPromise, arg1: *bindings.VM) void; -pub extern fn JSC__JSInternalPromise__status(arg0: [*c]const JSC__JSInternalPromise, arg1: *bindings.VM) u32; -pub extern fn JSC__JSFunction__optimizeSoon(JSValue0: JSC__JSValue) void; -pub extern fn JSC__JSGlobalObject__bunVM(arg0: *bindings.JSGlobalObject) ?*bindings.VirtualMachine; -pub extern fn JSC__JSGlobalObject__createAggregateError(arg0: *bindings.JSGlobalObject, arg1: [*c]*anyopaque, arg2: u16, arg3: [*c]const ZigString) JSC__JSValue; -pub extern fn JSC__JSGlobalObject__createSyntheticModule_(arg0: *bindings.JSGlobalObject, arg1: [*c]ZigString, arg2: usize, arg3: [*c]bindings.JSValue, arg4: usize) void; -pub extern fn JSC__JSGlobalObject__deleteModuleRegistryEntry(arg0: *bindings.JSGlobalObject, arg1: [*c]ZigString) void; -pub extern fn JSC__JSGlobalObject__generateHeapSnapshot(arg0: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn JSC__JSGlobalObject__getCachedObject(arg0: *bindings.JSGlobalObject, arg1: [*c]const ZigString) JSC__JSValue; -pub extern fn JSC__JSGlobalObject__handleRejectedPromises(arg0: *bindings.JSGlobalObject) void; -pub extern fn JSC__JSGlobalObject__putCachedObject(arg0: *bindings.JSGlobalObject, arg1: [*c]const ZigString, JSValue2: JSC__JSValue) JSC__JSValue; -pub extern fn JSC__JSGlobalObject__queueMicrotaskJob(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue, JSValue2: JSC__JSValue, JSValue3: JSC__JSValue) void; -pub extern fn JSC__JSGlobalObject__reload(arg0: *bindings.JSGlobalObject) void; -pub extern fn JSC__JSGlobalObject__startRemoteInspector(arg0: *bindings.JSGlobalObject, arg1: [*c]u8, arg2: u16) bool; -pub extern fn JSC__JSGlobalObject__vm(arg0: *bindings.JSGlobalObject) *bindings.VM; -pub extern fn JSC__JSMap__create(arg0: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn JSC__JSMap__get_(arg0: ?*bindings.JSMap, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) JSC__JSValue; -pub extern fn JSC__JSMap__has(arg0: ?*bindings.JSMap, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) bool; -pub extern fn JSC__JSMap__remove(arg0: ?*bindings.JSMap, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) bool; -pub extern fn JSC__JSMap__set(arg0: ?*bindings.JSMap, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue, JSValue3: JSC__JSValue) void; -pub extern fn JSC__JSValue___then(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue, ArgFn3: ?*const fn (*bindings.JSGlobalObject, *bindings.CallFrame) callconv(.C) JSC__JSValue, ArgFn4: ?*const fn (*bindings.JSGlobalObject, *bindings.CallFrame) callconv(.C) JSC__JSValue) void; -pub extern fn JSC__JSValue__asArrayBuffer_(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: ?*Bun__ArrayBuffer) bool; -pub extern fn JSC__JSValue__asBigIntCompare(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) u8; -pub extern fn JSC__JSValue__asCell(JSValue0: JSC__JSValue) [*c]bindings.JSCell; -pub extern fn JSC__JSValue__asInternalPromise(JSValue0: JSC__JSValue) [*c]bindings.JSInternalPromise; -pub extern fn JSC__JSValue__asNumber(JSValue0: JSC__JSValue) f64; -pub extern fn JSC__JSValue__asObject(JSValue0: JSC__JSValue) bJSC__JSObject; -pub extern fn JSC__JSValue__asPromise(JSValue0: JSC__JSValue) ?*bindings.JSPromise; -pub extern fn JSC__JSValue__asString(JSValue0: JSC__JSValue) [*c]bindings.JSString; -pub extern fn JSC__JSValue__coerceToDouble(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) f64; -pub extern fn JSC__JSValue__coerceToInt32(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) i32; -pub extern fn JSC__JSValue__coerceToInt64(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) i64; -pub extern fn JSC__JSValue__createEmptyArray(arg0: *bindings.JSGlobalObject, arg1: usize) JSC__JSValue; -pub extern fn JSC__JSValue__createEmptyObject(arg0: *bindings.JSGlobalObject, arg1: usize) JSC__JSValue; -pub extern fn JSC__JSValue__createInternalPromise(arg0: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn JSC__JSValue__createObject2(arg0: *bindings.JSGlobalObject, arg1: [*c]const ZigString, arg2: [*c]const ZigString, JSValue3: JSC__JSValue, JSValue4: JSC__JSValue) JSC__JSValue; -pub extern fn JSC__JSValue__createRangeError(arg0: [*c]const ZigString, arg1: [*c]const ZigString, arg2: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn JSC__JSValue__createRopeString(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn JSC__JSValue__createStringArray(arg0: *bindings.JSGlobalObject, arg1: [*c]const ZigString, arg2: usize, arg3: bool) JSC__JSValue; -pub extern fn JSC__JSValue__createTypeError(arg0: [*c]const ZigString, arg1: [*c]const ZigString, arg2: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn JSC__JSValue__createUninitializedUint8Array(arg0: *bindings.JSGlobalObject, arg1: usize) JSC__JSValue; -pub extern fn JSC__JSValue__deepEquals(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject) bool; -pub extern fn JSC__JSValue__deepMatch(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject, arg3: bool) bool; -pub extern fn JSC__JSValue__eqlCell(JSValue0: JSC__JSValue, arg1: [*c]bindings.JSCell) bool; -pub extern fn JSC__JSValue__eqlValue(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue) bool; -pub extern fn JSC__JSValue__fastGet_(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: u8) JSC__JSValue; -pub extern fn JSC__JSValue__fastGetDirect_(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: u8) JSC__JSValue; -pub extern fn JSC__JSValue__forEach(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (*bindings.VM, *bindings.JSGlobalObject, ?*anyopaque, JSC__JSValue) callconv(.C) void) void; -pub extern fn JSC__JSValue__forEachProperty(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (*bindings.JSGlobalObject, ?*anyopaque, [*c]ZigString, JSC__JSValue, bool) callconv(.C) void) void; -pub extern fn JSC__JSValue__forEachPropertyOrdered(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (*bindings.JSGlobalObject, ?*anyopaque, [*c]ZigString, JSC__JSValue, bool) callconv(.C) void) void; -pub extern fn JSC__JSValue__fromEntries(arg0: *bindings.JSGlobalObject, arg1: [*c]ZigString, arg2: [*c]ZigString, arg3: usize, arg4: bool) JSC__JSValue; -pub extern fn JSC__JSValue__fromInt64NoTruncate(arg0: *bindings.JSGlobalObject, arg1: i64) JSC__JSValue; -pub extern fn JSC__JSValue__fromUInt64NoTruncate(arg0: *bindings.JSGlobalObject, arg1: u64) JSC__JSValue; -pub extern fn JSC__JSValue__getClassName(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString) void; -pub extern fn JSC__JSValue__getErrorsProperty(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn JSC__JSValue__getIfPropertyExistsFromPath(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) JSC__JSValue; -pub extern fn JSC__JSValue__getIfPropertyExistsImpl(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]const u8, arg3: u32) JSC__JSValue; -pub extern fn JSC__JSValue__getLengthIfPropertyExistsInternal(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) f64; -pub extern fn JSC__JSValue__getNameProperty(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString) void; -pub extern fn JSC__JSValue__getPrototype(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn JSC__JSValue__getSymbolDescription(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString) void; -pub extern fn JSC__JSValue__getUnixTimestamp(JSValue0: JSC__JSValue) f64; -pub extern fn JSC__JSValue__isAggregateError(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) bool; -pub extern fn JSC__JSValue__isAnyError(JSValue0: JSC__JSValue) bool; -pub extern fn JSC__JSValue__isAnyInt(JSValue0: JSC__JSValue) bool; -pub extern fn JSC__JSValue__isBigInt(JSValue0: JSC__JSValue) bool; -pub extern fn JSC__JSValue__isBigInt32(JSValue0: JSC__JSValue) bool; -pub extern fn JSC__JSValue__isBoolean(JSValue0: JSC__JSValue) bool; -pub extern fn JSC__JSValue__isCallable(JSValue0: JSC__JSValue, arg1: *bindings.VM) bool; -pub extern fn JSC__JSValue__isClass(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) bool; -pub extern fn JSC__JSValue__isConstructor(JSValue0: JSC__JSValue) bool; -pub extern fn JSC__JSValue__isCustomGetterSetter(JSValue0: JSC__JSValue) bool; -pub extern fn JSC__JSValue__isError(JSValue0: JSC__JSValue) bool; -pub extern fn JSC__JSValue__isException(JSValue0: JSC__JSValue, arg1: *bindings.VM) bool; -pub extern fn JSC__JSValue__isGetterSetter(JSValue0: JSC__JSValue) bool; -pub extern fn JSC__JSValue__isHeapBigInt(JSValue0: JSC__JSValue) bool; -pub extern fn JSC__JSValue__isInstanceOf(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) bool; -pub extern fn JSC__JSValue__isInt32(JSValue0: JSC__JSValue) bool; -pub extern fn JSC__JSValue__isInt32AsAnyInt(JSValue0: JSC__JSValue) bool; -pub extern fn JSC__JSValue__isIterable(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) bool; -pub extern fn JSC__JSValue__isNumber(JSValue0: JSC__JSValue) bool; -pub extern fn JSC__JSValue__isObject(JSValue0: JSC__JSValue) bool; -pub extern fn JSC__JSValue__isPrimitive(JSValue0: JSC__JSValue) bool; -pub extern fn JSC__JSValue__isSameValue(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject) bool; -pub extern fn JSC__JSValue__isSymbol(JSValue0: JSC__JSValue) bool; -pub extern fn JSC__JSValue__isTerminationException(JSValue0: JSC__JSValue, arg1: *bindings.VM) bool; -pub extern fn JSC__JSValue__isUInt32AsAnyInt(JSValue0: JSC__JSValue) bool; -pub extern fn JSC__JSValue__jestDeepEquals(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject) bool; -pub extern fn JSC__JSValue__jestDeepMatch(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject, arg3: bool) bool; -pub extern fn JSC__JSValue__jestStrictDeepEquals(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject) bool; -pub extern fn JSC__JSValue__jsBoolean(arg0: bool) JSC__JSValue; -pub extern fn JSC__JSValue__jsDoubleNumber(arg0: f64) JSC__JSValue; -pub extern fn JSC__JSValue__jsNull(...) JSC__JSValue; -pub extern fn JSC__JSValue__jsNumberFromChar(arg0: u8) JSC__JSValue; -pub extern fn JSC__JSValue__jsNumberFromDouble(arg0: f64) JSC__JSValue; -pub extern fn JSC__JSValue__jsNumberFromInt64(arg0: i64) JSC__JSValue; -pub extern fn JSC__JSValue__jsNumberFromU16(arg0: u16) JSC__JSValue; -pub extern fn JSC__JSValue__jsonStringify(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: u32, arg3: [*c]BunString) void; -pub extern fn JSC__JSValue__jsTDZValue(...) JSC__JSValue; -pub extern fn JSC__JSValue__jsType(JSValue0: JSC__JSValue) u8; -pub extern fn JSC__JSValue__jsUndefined(...) JSC__JSValue; -pub extern fn JSC__JSValue__makeWithNameAndPrototype(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque, arg2: ?*anyopaque, arg3: [*c]const ZigString) JSC__JSValue; -pub extern fn JSC__JSValue__parseJSON(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn JSC__JSValue__push(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; -pub extern fn JSC__JSValue__put(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]const ZigString, JSValue3: JSC__JSValue) void; -pub extern fn JSC__JSValue__putIndex(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: u32, JSValue3: JSC__JSValue) void; -pub extern fn JSC__JSValue__putRecord(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString, arg3: [*c]ZigString, arg4: usize) void; -pub extern fn JSC__JSValue__strictDeepEquals(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject) bool; -pub extern fn JSC__JSValue__stringIncludes(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) bool; -pub extern fn JSC__JSValue__symbolFor(arg0: *bindings.JSGlobalObject, arg1: [*c]ZigString) JSC__JSValue; -pub extern fn JSC__JSValue__symbolKeyFor(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString) bool; -pub extern fn JSC__JSValue__toBoolean(JSValue0: JSC__JSValue) bool; -pub extern fn JSC__JSValue__toBooleanSlow(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) bool; -pub extern fn JSC__JSValue__toError_(JSValue0: JSC__JSValue) JSC__JSValue; -pub extern fn JSC__JSValue__toInt32(JSValue0: JSC__JSValue) i32; -pub extern fn JSC__JSValue__toInt64(JSValue0: JSC__JSValue) i64; -pub extern fn JSC__JSValue__toMatch(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) bool; -pub extern fn JSC__JSValue__toObject(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) [*c]bindings.JSObject; -pub extern fn JSC__JSValue__toString(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) [*c]bindings.JSString; -pub extern fn JSC__JSValue__toStringOrNull(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) [*c]bindings.JSString; -pub extern fn JSC__JSValue__toUInt64NoTruncate(JSValue0: JSC__JSValue) u64; -pub extern fn JSC__JSValue__toZigException(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigException) void; -pub extern fn JSC__JSValue__toZigString(JSValue0: JSC__JSValue, arg1: [*c]ZigString, arg2: *bindings.JSGlobalObject) void; -pub extern fn JSC__Exception__create(arg0: *bindings.JSGlobalObject, arg1: [*c]bindings.JSObject, StackCaptureAction2: u8) [*c]bindings.Exception; -pub extern fn JSC__Exception__getStackTrace(arg0: [*c]bindings.Exception, arg1: [*c]ZigStackTrace) void; -pub extern fn JSC__Exception__value(arg0: [*c]bindings.Exception) JSC__JSValue; -pub extern fn JSC__VM__blockBytesAllocated(arg0: *bindings.VM) usize; -pub extern fn JSC__VM__clearExecutionTimeLimit(arg0: *bindings.VM) void; -pub extern fn JSC__VM__collectAsync(arg0: *bindings.VM) void; -pub extern fn JSC__VM__create(HeapType0: u8) *bindings.VM; -pub extern fn JSC__VM__deferGC(arg0: *bindings.VM, arg1: ?*anyopaque, ArgFn2: ?*const fn (?*anyopaque) callconv(.C) void) void; -pub extern fn JSC__VM__deinit(arg0: *bindings.VM, arg1: *bindings.JSGlobalObject) void; -pub extern fn JSC__VM__deleteAllCode(arg0: *bindings.VM, arg1: *bindings.JSGlobalObject) void; -pub extern fn JSC__VM__drainMicrotasks(arg0: *bindings.VM) void; -pub extern fn JSC__VM__executionForbidden(arg0: *bindings.VM) bool; -pub extern fn JSC__VM__externalMemorySize(arg0: *bindings.VM) usize; -pub extern fn JSC__VM__heapSize(arg0: *bindings.VM) usize; -pub extern fn JSC__VM__holdAPILock(arg0: *bindings.VM, arg1: ?*anyopaque, ArgFn2: ?*const fn (?*anyopaque) callconv(.C) void) void; -pub extern fn JSC__VM__isEntered(arg0: *bindings.VM) bool; -pub extern fn JSC__VM__isJITEnabled(...) bool; -pub extern fn JSC__VM__notifyNeedDebuggerBreak(arg0: *bindings.VM) void; -pub extern fn JSC__VM__notifyNeedShellTimeoutCheck(arg0: *bindings.VM) void; -pub extern fn JSC__VM__notifyNeedTermination(arg0: *bindings.VM) void; -pub extern fn JSC__VM__notifyNeedWatchdogCheck(arg0: *bindings.VM) void; -pub extern fn JSC__VM__releaseWeakRefs(arg0: *bindings.VM) void; -pub extern fn JSC__VM__runGC(arg0: *bindings.VM, arg1: bool) JSC__JSValue; -pub extern fn JSC__VM__setControlFlowProfiler(arg0: *bindings.VM, arg1: bool) void; -pub extern fn JSC__VM__setExecutionForbidden(arg0: *bindings.VM, arg1: bool) void; -pub extern fn JSC__VM__setExecutionTimeLimit(arg0: *bindings.VM, arg1: f64) void; -pub extern fn JSC__VM__shrinkFootprint(arg0: *bindings.VM) void; -pub extern fn JSC__VM__throwError(arg0: *bindings.VM, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; -pub extern fn JSC__VM__whenIdle(arg0: *bindings.VM, ArgFn1: ?*const fn (...) callconv(.C) void) void; -pub extern fn JSC__ThrowScope__clearException(arg0: [*c]bindings.ThrowScope) void; -pub extern fn JSC__ThrowScope__declare(arg0: *bindings.VM, arg1: [*c]u8, arg2: [*c]u8, arg3: usize) bJSC__ThrowScope; -pub extern fn JSC__ThrowScope__exception(arg0: [*c]bindings.ThrowScope) [*c]bindings.Exception; -pub extern fn JSC__ThrowScope__release(arg0: [*c]bindings.ThrowScope) void; -pub extern fn JSC__CatchScope__clearException(arg0: [*c]bindings.CatchScope) void; -pub extern fn JSC__CatchScope__declare(arg0: *bindings.VM, arg1: [*c]u8, arg2: [*c]u8, arg3: usize) bJSC__CatchScope; -pub extern fn JSC__CatchScope__exception(arg0: [*c]bindings.CatchScope) [*c]bindings.Exception; -pub extern fn FFI__ptr__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; -pub extern fn Reader__u8__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; -pub extern fn Reader__u16__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; -pub extern fn Reader__u32__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; -pub extern fn Reader__ptr__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; -pub extern fn Reader__i8__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; -pub extern fn Reader__i16__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; -pub extern fn Reader__i32__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; -pub extern fn Reader__f32__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; -pub extern fn Reader__f64__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; -pub extern fn Reader__i64__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; -pub extern fn Reader__u64__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; -pub extern fn Reader__intptr__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; -pub extern fn Zig__GlobalObject__create(arg0: ?*anyopaque, arg1: i32, arg2: bool, arg3: ?*anyopaque) *bindings.JSGlobalObject; -pub extern fn Zig__GlobalObject__getModuleRegistryMap(arg0: *bindings.JSGlobalObject) ?*anyopaque; -pub extern fn Zig__GlobalObject__resetModuleRegistryMap(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque) bool; -pub extern fn Bun__Path__create(arg0: *bindings.JSGlobalObject, arg1: bool) JSC__JSValue; -pub extern fn ArrayBufferSink__assignToStream(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue, arg2: ?*anyopaque, arg3: [*c]*anyopaque) JSC__JSValue; -pub extern fn ArrayBufferSink__createObject(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque) JSC__JSValue; -pub extern fn ArrayBufferSink__detachPtr(JSValue0: JSC__JSValue) void; -pub extern fn ArrayBufferSink__fromJS(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) ?*anyopaque; -pub extern fn ArrayBufferSink__onClose(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue) void; -pub extern fn ArrayBufferSink__onReady(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, JSValue2: JSC__JSValue) void; -pub extern fn HTTPSResponseSink__assignToStream(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue, arg2: ?*anyopaque, arg3: [*c]*anyopaque) JSC__JSValue; -pub extern fn HTTPSResponseSink__createObject(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque) JSC__JSValue; -pub extern fn HTTPSResponseSink__detachPtr(JSValue0: JSC__JSValue) void; -pub extern fn HTTPSResponseSink__fromJS(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) ?*anyopaque; -pub extern fn HTTPSResponseSink__onClose(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue) void; -pub extern fn HTTPSResponseSink__onReady(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, JSValue2: JSC__JSValue) void; -pub extern fn HTTPResponseSink__assignToStream(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue, arg2: ?*anyopaque, arg3: [*c]*anyopaque) JSC__JSValue; -pub extern fn HTTPResponseSink__createObject(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque) JSC__JSValue; -pub extern fn HTTPResponseSink__detachPtr(JSValue0: JSC__JSValue) void; -pub extern fn HTTPResponseSink__fromJS(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) ?*anyopaque; -pub extern fn HTTPResponseSink__onClose(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue) void; -pub extern fn HTTPResponseSink__onReady(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, JSValue2: JSC__JSValue) void; -pub extern fn FileSink__assignToStream(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue, arg2: ?*anyopaque, arg3: [*c]*anyopaque) JSC__JSValue; -pub extern fn FileSink__createObject(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque) JSC__JSValue; -pub extern fn FileSink__detachPtr(JSValue0: JSC__JSValue) void; -pub extern fn FileSink__fromJS(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) ?*anyopaque; -pub extern fn FileSink__onClose(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue) void; -pub extern fn FileSink__onReady(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, JSValue2: JSC__JSValue) void; -pub extern fn ZigException__fromException(arg0: [*c]bindings.Exception) ZigException; +pub extern "C" fn JSC__JSObject__create(arg0: *bindings.JSGlobalObject, arg1: usize, arg2: ?*anyopaque, ArgFn3: ?*const fn (?*anyopaque, [*c]bindings.JSObject, *bindings.JSGlobalObject) callconv(.C) void) JSC__JSValue; +pub extern "C" fn JSC__JSObject__getArrayLength(arg0: [*c]bindings.JSObject) usize; +pub extern "C" fn JSC__JSObject__getDirect(arg0: [*c]bindings.JSObject, arg1: *bindings.JSGlobalObject, arg2: [*c]const ZigString) JSC__JSValue; +pub extern "C" fn JSC__JSObject__getIndex(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: u32) JSC__JSValue; +pub extern "C" fn JSC__JSObject__putRecord(arg0: [*c]bindings.JSObject, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString, arg3: [*c]ZigString, arg4: usize) void; +pub extern "C" fn ZigString__external(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (?*anyopaque, ?*anyopaque, usize) callconv(.C) void) JSC__JSValue; +pub extern "C" fn ZigString__to16BitValue(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn ZigString__toAtomicValue(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn ZigString__toErrorInstance(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn ZigString__toExternalU16(arg0: [*c]const u16, arg1: usize, arg2: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn ZigString__toExternalValue(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn ZigString__toExternalValueWithCallback(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject, ArgFn2: ?*const fn (?*anyopaque, ?*anyopaque, usize) callconv(.C) void) JSC__JSValue; +pub extern "C" fn ZigString__toRangeErrorInstance(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn ZigString__toSyntaxErrorInstance(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn ZigString__toTypeErrorInstance(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn ZigString__toValue(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn ZigString__toValueGC(arg0: [*c]const ZigString, arg1: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn WebCore__DOMURL__cast_(JSValue0: JSC__JSValue, arg1: *bindings.VM) ?*bindings.DOMURL; +pub extern "C" fn WebCore__DOMURL__fileSystemPath(arg0: ?*bindings.DOMURL) BunString; +pub extern "C" fn WebCore__DOMURL__href_(arg0: ?*bindings.DOMURL, arg1: [*c]ZigString) void; +pub extern "C" fn WebCore__DOMURL__pathname_(arg0: ?*bindings.DOMURL, arg1: [*c]ZigString) void; +pub extern "C" fn WebCore__DOMFormData__append(arg0: ?*bindings.DOMFormData, arg1: [*c]ZigString, arg2: [*c]ZigString) void; +pub extern "C" fn WebCore__DOMFormData__appendBlob(arg0: ?*bindings.DOMFormData, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString, arg3: ?*anyopaque, arg4: [*c]ZigString) void; +pub extern "C" fn WebCore__DOMFormData__count(arg0: ?*bindings.DOMFormData) usize; +pub extern "C" fn WebCore__DOMFormData__create(arg0: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn WebCore__DOMFormData__createFromURLQuery(arg0: *bindings.JSGlobalObject, arg1: [*c]ZigString) JSC__JSValue; +pub extern "C" fn WebCore__DOMFormData__fromJS(JSValue0: JSC__JSValue) ?*bindings.DOMFormData; +pub extern "C" fn WebCore__FetchHeaders__append(arg0: ?*bindings.FetchHeaders, arg1: [*c]const ZigString, arg2: [*c]const ZigString, arg3: *bindings.JSGlobalObject) void; +pub extern "C" fn WebCore__FetchHeaders__cast_(JSValue0: JSC__JSValue, arg1: *bindings.VM) ?*bindings.FetchHeaders; +pub extern "C" fn WebCore__FetchHeaders__clone(arg0: ?*bindings.FetchHeaders, arg1: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn WebCore__FetchHeaders__cloneThis(arg0: ?*bindings.FetchHeaders, arg1: *bindings.JSGlobalObject) ?*bindings.FetchHeaders; +pub extern "C" fn WebCore__FetchHeaders__copyTo(arg0: ?*bindings.FetchHeaders, arg1: [*c]StringPointer, arg2: [*c]StringPointer, arg3: [*c]u8) void; +pub extern "C" fn WebCore__FetchHeaders__count(arg0: ?*bindings.FetchHeaders, arg1: [*c]u32, arg2: [*c]u32) void; +pub extern "C" fn WebCore__FetchHeaders__createEmpty(...) ?*bindings.FetchHeaders; +pub extern "C" fn WebCore__FetchHeaders__createFromJS(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) ?*bindings.FetchHeaders; +pub extern "C" fn WebCore__FetchHeaders__createFromPicoHeaders_(arg0: ?*const anyopaque) ?*bindings.FetchHeaders; +pub extern "C" fn WebCore__FetchHeaders__createFromUWS(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque) ?*bindings.FetchHeaders; +pub extern "C" fn WebCore__FetchHeaders__createValue(arg0: *bindings.JSGlobalObject, arg1: [*c]StringPointer, arg2: [*c]StringPointer, arg3: [*c]const ZigString, arg4: u32) JSC__JSValue; +pub extern "C" fn WebCore__FetchHeaders__deref(arg0: ?*bindings.FetchHeaders) void; +pub extern "C" fn WebCore__FetchHeaders__fastGet_(arg0: ?*bindings.FetchHeaders, arg1: u8, arg2: [*c]ZigString) void; +pub extern "C" fn WebCore__FetchHeaders__fastHas_(arg0: ?*bindings.FetchHeaders, arg1: u8) bool; +pub extern "C" fn WebCore__FetchHeaders__fastRemove_(arg0: ?*bindings.FetchHeaders, arg1: u8) void; +pub extern "C" fn WebCore__FetchHeaders__get_(arg0: ?*bindings.FetchHeaders, arg1: [*c]const ZigString, arg2: [*c]ZigString, arg3: *bindings.JSGlobalObject) void; +pub extern "C" fn WebCore__FetchHeaders__has(arg0: ?*bindings.FetchHeaders, arg1: [*c]const ZigString, arg2: *bindings.JSGlobalObject) bool; +pub extern "C" fn WebCore__FetchHeaders__isEmpty(arg0: ?*bindings.FetchHeaders) bool; +pub extern "C" fn WebCore__FetchHeaders__put_(arg0: ?*bindings.FetchHeaders, arg1: [*c]const ZigString, arg2: [*c]const ZigString, arg3: *bindings.JSGlobalObject) void; +pub extern "C" fn WebCore__FetchHeaders__remove(arg0: ?*bindings.FetchHeaders, arg1: [*c]const ZigString, arg2: *bindings.JSGlobalObject) void; +pub extern "C" fn WebCore__FetchHeaders__toJS(arg0: ?*bindings.FetchHeaders, arg1: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn WebCore__FetchHeaders__toUWSResponse(arg0: ?*bindings.FetchHeaders, arg1: bool, arg2: ?*anyopaque) void; +pub extern "C" fn SystemError__toErrorInstance(arg0: [*c]const SystemError, arg1: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn JSC__JSCell__getObject(arg0: [*c]bindings.JSCell) [*c]bindings.JSObject; +pub extern "C" fn JSC__JSCell__getType(arg0: [*c]bindings.JSCell) u8; +pub extern "C" fn JSC__JSString__eql(arg0: [*c]const JSC__JSString, arg1: *bindings.JSGlobalObject, arg2: [*c]bindings.JSString) bool; +pub extern "C" fn JSC__JSString__is8Bit(arg0: [*c]const JSC__JSString) bool; +pub extern "C" fn JSC__JSString__iterator(arg0: [*c]bindings.JSString, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque) void; +pub extern "C" fn JSC__JSString__length(arg0: [*c]const JSC__JSString) usize; +pub extern "C" fn JSC__JSString__toObject(arg0: [*c]bindings.JSString, arg1: *bindings.JSGlobalObject) [*c]bindings.JSObject; +pub extern "C" fn JSC__JSString__toZigString(arg0: [*c]bindings.JSString, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString) void; +pub extern "C" fn JSC__JSModuleLoader__evaluate(arg0: *bindings.JSGlobalObject, arg1: [*c]const u8, arg2: usize, arg3: [*c]const u8, arg4: usize, arg5: [*c]const u8, arg6: usize, JSValue7: JSC__JSValue, arg8: [*c]bindings.JSValue) JSC__JSValue; +pub extern "C" fn JSC__JSModuleLoader__loadAndEvaluateModule(arg0: *bindings.JSGlobalObject, arg1: [*c]const BunString) [*c]bindings.JSInternalPromise; +pub extern "C" fn WebCore__AbortSignal__aborted(arg0: ?*bindings.AbortSignal) bool; +pub extern "C" fn WebCore__AbortSignal__abortReason(arg0: ?*bindings.AbortSignal) JSC__JSValue; +pub extern "C" fn WebCore__AbortSignal__addListener(arg0: ?*bindings.AbortSignal, arg1: ?*anyopaque, ArgFn2: ?*const fn (?*anyopaque, JSC__JSValue) callconv(.C) void) ?*bindings.AbortSignal; +pub extern "C" fn WebCore__AbortSignal__cleanNativeBindings(arg0: ?*bindings.AbortSignal, arg1: ?*anyopaque) void; +pub extern "C" fn WebCore__AbortSignal__create(arg0: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn WebCore__AbortSignal__createAbortError(arg0: [*c]const ZigString, arg1: [*c]const ZigString, arg2: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn WebCore__AbortSignal__createTimeoutError(arg0: [*c]const ZigString, arg1: [*c]const ZigString, arg2: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn WebCore__AbortSignal__fromJS(JSValue0: JSC__JSValue) ?*bindings.AbortSignal; +pub extern "C" fn WebCore__AbortSignal__ref(arg0: ?*bindings.AbortSignal) ?*bindings.AbortSignal; +pub extern "C" fn WebCore__AbortSignal__signal(arg0: ?*bindings.AbortSignal, JSValue1: JSC__JSValue) ?*bindings.AbortSignal; +pub extern "C" fn WebCore__AbortSignal__toJS(arg0: ?*bindings.AbortSignal, arg1: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn WebCore__AbortSignal__unref(arg0: ?*bindings.AbortSignal) ?*bindings.AbortSignal; +pub extern "C" fn JSC__JSPromise__asValue(arg0: ?*bindings.JSPromise, arg1: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn JSC__JSPromise__create(arg0: *bindings.JSGlobalObject) ?*bindings.JSPromise; +pub extern "C" fn JSC__JSPromise__isHandled(arg0: [*c]const JSC__JSPromise, arg1: *bindings.VM) bool; +pub extern "C" fn JSC__JSPromise__reject(arg0: ?*bindings.JSPromise, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; +pub extern "C" fn JSC__JSPromise__rejectAsHandled(arg0: ?*bindings.JSPromise, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; +pub extern "C" fn JSC__JSPromise__rejectAsHandledException(arg0: ?*bindings.JSPromise, arg1: *bindings.JSGlobalObject, arg2: [*c]bindings.Exception) void; +pub extern "C" fn JSC__JSPromise__rejectedPromise(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) ?*bindings.JSPromise; +pub extern "C" fn JSC__JSPromise__rejectedPromiseValue(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) JSC__JSValue; +pub extern "C" fn JSC__JSPromise__rejectOnNextTickWithHandled(arg0: ?*bindings.JSPromise, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue, arg3: bool) void; +pub extern "C" fn JSC__JSPromise__rejectWithCaughtException(arg0: ?*bindings.JSPromise, arg1: *bindings.JSGlobalObject, arg2: bJSC__ThrowScope) void; +pub extern "C" fn JSC__JSPromise__resolve(arg0: ?*bindings.JSPromise, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; +pub extern "C" fn JSC__JSPromise__resolvedPromise(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) ?*bindings.JSPromise; +pub extern "C" fn JSC__JSPromise__resolvedPromiseValue(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) JSC__JSValue; +pub extern "C" fn JSC__JSPromise__resolveOnNextTick(arg0: ?*bindings.JSPromise, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; +pub extern "C" fn JSC__JSPromise__result(arg0: ?*bindings.JSPromise, arg1: *bindings.VM) JSC__JSValue; +pub extern "C" fn JSC__JSPromise__setHandled(arg0: ?*bindings.JSPromise, arg1: *bindings.VM) void; +pub extern "C" fn JSC__JSPromise__status(arg0: [*c]const JSC__JSPromise, arg1: *bindings.VM) u32; +pub extern "C" fn JSC__JSInternalPromise__create(arg0: *bindings.JSGlobalObject) [*c]bindings.JSInternalPromise; +pub extern "C" fn JSC__JSInternalPromise__isHandled(arg0: [*c]const JSC__JSInternalPromise, arg1: *bindings.VM) bool; +pub extern "C" fn JSC__JSInternalPromise__reject(arg0: [*c]bindings.JSInternalPromise, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; +pub extern "C" fn JSC__JSInternalPromise__rejectAsHandled(arg0: [*c]bindings.JSInternalPromise, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; +pub extern "C" fn JSC__JSInternalPromise__rejectAsHandledException(arg0: [*c]bindings.JSInternalPromise, arg1: *bindings.JSGlobalObject, arg2: [*c]bindings.Exception) void; +pub extern "C" fn JSC__JSInternalPromise__rejectedPromise(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) [*c]bindings.JSInternalPromise; +pub extern "C" fn JSC__JSInternalPromise__rejectWithCaughtException(arg0: [*c]bindings.JSInternalPromise, arg1: *bindings.JSGlobalObject, arg2: bJSC__ThrowScope) void; +pub extern "C" fn JSC__JSInternalPromise__resolve(arg0: [*c]bindings.JSInternalPromise, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; +pub extern "C" fn JSC__JSInternalPromise__resolvedPromise(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) [*c]bindings.JSInternalPromise; +pub extern "C" fn JSC__JSInternalPromise__result(arg0: [*c]const JSC__JSInternalPromise, arg1: *bindings.VM) JSC__JSValue; +pub extern "C" fn JSC__JSInternalPromise__setHandled(arg0: [*c]bindings.JSInternalPromise, arg1: *bindings.VM) void; +pub extern "C" fn JSC__JSInternalPromise__status(arg0: [*c]const JSC__JSInternalPromise, arg1: *bindings.VM) u32; +pub extern "C" fn JSC__JSFunction__optimizeSoon(JSValue0: JSC__JSValue) void; +pub extern "C" fn JSC__JSGlobalObject__bunVM(arg0: *bindings.JSGlobalObject) ?*bindings.VirtualMachine; +pub extern "C" fn JSC__JSGlobalObject__createAggregateError(arg0: *bindings.JSGlobalObject, arg1: [*c]*anyopaque, arg2: u16, arg3: [*c]const ZigString) JSC__JSValue; +pub extern "C" fn JSC__JSGlobalObject__createSyntheticModule_(arg0: *bindings.JSGlobalObject, arg1: [*c]ZigString, arg2: usize, arg3: [*c]bindings.JSValue, arg4: usize) void; +pub extern "C" fn JSC__JSGlobalObject__deleteModuleRegistryEntry(arg0: *bindings.JSGlobalObject, arg1: [*c]ZigString) void; +pub extern "C" fn JSC__JSGlobalObject__generateHeapSnapshot(arg0: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn JSC__JSGlobalObject__getCachedObject(arg0: *bindings.JSGlobalObject, arg1: [*c]const ZigString) JSC__JSValue; +pub extern "C" fn JSC__JSGlobalObject__handleRejectedPromises(arg0: *bindings.JSGlobalObject) void; +pub extern "C" fn JSC__JSGlobalObject__putCachedObject(arg0: *bindings.JSGlobalObject, arg1: [*c]const ZigString, JSValue2: JSC__JSValue) JSC__JSValue; +pub extern "C" fn JSC__JSGlobalObject__queueMicrotaskJob(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue, JSValue2: JSC__JSValue, JSValue3: JSC__JSValue) void; +pub extern "C" fn JSC__JSGlobalObject__reload(arg0: *bindings.JSGlobalObject) void; +pub extern "C" fn JSC__JSGlobalObject__startRemoteInspector(arg0: *bindings.JSGlobalObject, arg1: [*c]u8, arg2: u16) bool; +pub extern "C" fn JSC__JSGlobalObject__vm(arg0: *bindings.JSGlobalObject) *bindings.VM; +pub extern "C" fn JSC__JSMap__create(arg0: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn JSC__JSMap__get_(arg0: ?*bindings.JSMap, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) JSC__JSValue; +pub extern "C" fn JSC__JSMap__has(arg0: ?*bindings.JSMap, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) bool; +pub extern "C" fn JSC__JSMap__remove(arg0: ?*bindings.JSMap, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) bool; +pub extern "C" fn JSC__JSMap__set(arg0: ?*bindings.JSMap, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue, JSValue3: JSC__JSValue) void; +pub extern "C" fn JSC__JSValue___then(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue, ArgFn3: ?*const fn (*bindings.JSGlobalObject, *bindings.CallFrame) callconv(.C) JSC__JSValue, ArgFn4: ?*const fn (*bindings.JSGlobalObject, *bindings.CallFrame) callconv(.C) JSC__JSValue) void; +pub extern "C" fn JSC__JSValue__asArrayBuffer_(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: ?*Bun__ArrayBuffer) bool; +pub extern "C" fn JSC__JSValue__asBigIntCompare(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) u8; +pub extern "C" fn JSC__JSValue__asCell(JSValue0: JSC__JSValue) [*c]bindings.JSCell; +pub extern "C" fn JSC__JSValue__asInternalPromise(JSValue0: JSC__JSValue) [*c]bindings.JSInternalPromise; +pub extern "C" fn JSC__JSValue__asNumber(JSValue0: JSC__JSValue) f64; +pub extern "C" fn JSC__JSValue__asObject(JSValue0: JSC__JSValue) bJSC__JSObject; +pub extern "C" fn JSC__JSValue__asPromise(JSValue0: JSC__JSValue) ?*bindings.JSPromise; +pub extern "C" fn JSC__JSValue__asString(JSValue0: JSC__JSValue) [*c]bindings.JSString; +pub extern "C" fn JSC__JSValue__coerceToDouble(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) f64; +pub extern "C" fn JSC__JSValue__coerceToInt32(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) i32; +pub extern "C" fn JSC__JSValue__coerceToInt64(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) i64; +pub extern "C" fn JSC__JSValue__createEmptyArray(arg0: *bindings.JSGlobalObject, arg1: usize) JSC__JSValue; +pub extern "C" fn JSC__JSValue__createEmptyObject(arg0: *bindings.JSGlobalObject, arg1: usize) JSC__JSValue; +pub extern "C" fn JSC__JSValue__createInternalPromise(arg0: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn JSC__JSValue__createObject2(arg0: *bindings.JSGlobalObject, arg1: [*c]const ZigString, arg2: [*c]const ZigString, JSValue3: JSC__JSValue, JSValue4: JSC__JSValue) JSC__JSValue; +pub extern "C" fn JSC__JSValue__createRangeError(arg0: [*c]const ZigString, arg1: [*c]const ZigString, arg2: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn JSC__JSValue__createRopeString(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn JSC__JSValue__createStringArray(arg0: *bindings.JSGlobalObject, arg1: [*c]const ZigString, arg2: usize, arg3: bool) JSC__JSValue; +pub extern "C" fn JSC__JSValue__createTypeError(arg0: [*c]const ZigString, arg1: [*c]const ZigString, arg2: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn JSC__JSValue__createUninitializedUint8Array(arg0: *bindings.JSGlobalObject, arg1: usize) JSC__JSValue; +pub extern "C" fn JSC__JSValue__deepEquals(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject) bool; +pub extern "C" fn JSC__JSValue__deepMatch(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject, arg3: bool) bool; +pub extern "C" fn JSC__JSValue__eqlCell(JSValue0: JSC__JSValue, arg1: [*c]bindings.JSCell) bool; +pub extern "C" fn JSC__JSValue__eqlValue(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__fastGet_(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: u8) JSC__JSValue; +pub extern "C" fn JSC__JSValue__fastGetDirect_(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: u8) JSC__JSValue; +pub extern "C" fn JSC__JSValue__forEach(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (*bindings.VM, *bindings.JSGlobalObject, ?*anyopaque, JSC__JSValue) callconv(.C) void) void; +pub extern "C" fn JSC__JSValue__forEachProperty(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (*bindings.JSGlobalObject, ?*anyopaque, [*c]ZigString, JSC__JSValue, bool) callconv(.C) void) void; +pub extern "C" fn JSC__JSValue__forEachPropertyOrdered(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (*bindings.JSGlobalObject, ?*anyopaque, [*c]ZigString, JSC__JSValue, bool) callconv(.C) void) void; +pub extern "C" fn JSC__JSValue__fromEntries(arg0: *bindings.JSGlobalObject, arg1: [*c]ZigString, arg2: [*c]ZigString, arg3: usize, arg4: bool) JSC__JSValue; +pub extern "C" fn JSC__JSValue__fromInt64NoTruncate(arg0: *bindings.JSGlobalObject, arg1: i64) JSC__JSValue; +pub extern "C" fn JSC__JSValue__fromUInt64NoTruncate(arg0: *bindings.JSGlobalObject, arg1: u64) JSC__JSValue; +pub extern "C" fn JSC__JSValue__getClassName(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString) void; +pub extern "C" fn JSC__JSValue__getErrorsProperty(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn JSC__JSValue__getIfPropertyExistsFromPath(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) JSC__JSValue; +pub extern "C" fn JSC__JSValue__getIfPropertyExistsImpl(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]const u8, arg3: u32) JSC__JSValue; +pub extern "C" fn JSC__JSValue__getLengthIfPropertyExistsInternal(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) f64; +pub extern "C" fn JSC__JSValue__getNameProperty(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString) void; +pub extern "C" fn JSC__JSValue__getPrototype(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn JSC__JSValue__getSymbolDescription(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString) void; +pub extern "C" fn JSC__JSValue__getUnixTimestamp(JSValue0: JSC__JSValue) f64; +pub extern "C" fn JSC__JSValue__isAggregateError(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) bool; +pub extern "C" fn JSC__JSValue__isAnyError(JSValue0: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__isAnyInt(JSValue0: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__isBigInt(JSValue0: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__isBigInt32(JSValue0: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__isBoolean(JSValue0: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__isCallable(JSValue0: JSC__JSValue, arg1: *bindings.VM) bool; +pub extern "C" fn JSC__JSValue__isClass(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) bool; +pub extern "C" fn JSC__JSValue__isConstructor(JSValue0: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__isCustomGetterSetter(JSValue0: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__isError(JSValue0: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__isException(JSValue0: JSC__JSValue, arg1: *bindings.VM) bool; +pub extern "C" fn JSC__JSValue__isGetterSetter(JSValue0: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__isHeapBigInt(JSValue0: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__isInstanceOf(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__isInt32(JSValue0: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__isInt32AsAnyInt(JSValue0: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__isIterable(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) bool; +pub extern "C" fn JSC__JSValue__isNumber(JSValue0: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__isObject(JSValue0: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__isPrimitive(JSValue0: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__isSameValue(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject) bool; +pub extern "C" fn JSC__JSValue__isSymbol(JSValue0: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__isTerminationException(JSValue0: JSC__JSValue, arg1: *bindings.VM) bool; +pub extern "C" fn JSC__JSValue__isUInt32AsAnyInt(JSValue0: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__jestDeepEquals(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject) bool; +pub extern "C" fn JSC__JSValue__jestDeepMatch(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject, arg3: bool) bool; +pub extern "C" fn JSC__JSValue__jestStrictDeepEquals(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject) bool; +pub extern "C" fn JSC__JSValue__jsBoolean(arg0: bool) JSC__JSValue; +pub extern "C" fn JSC__JSValue__jsDoubleNumber(arg0: f64) JSC__JSValue; +pub extern "C" fn JSC__JSValue__jsNull(...) JSC__JSValue; +pub extern "C" fn JSC__JSValue__jsNumberFromChar(arg0: u8) JSC__JSValue; +pub extern "C" fn JSC__JSValue__jsNumberFromDouble(arg0: f64) JSC__JSValue; +pub extern "C" fn JSC__JSValue__jsNumberFromInt64(arg0: i64) JSC__JSValue; +pub extern "C" fn JSC__JSValue__jsNumberFromU16(arg0: u16) JSC__JSValue; +pub extern "C" fn JSC__JSValue__jsonStringify(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: u32, arg3: [*c]BunString) void; +pub extern "C" fn JSC__JSValue__jsTDZValue(...) JSC__JSValue; +pub extern "C" fn JSC__JSValue__jsType(JSValue0: JSC__JSValue) u8; +pub extern "C" fn JSC__JSValue__jsUndefined(...) JSC__JSValue; +pub extern "C" fn JSC__JSValue__makeWithNameAndPrototype(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque, arg2: ?*anyopaque, arg3: [*c]const ZigString) JSC__JSValue; +pub extern "C" fn JSC__JSValue__parseJSON(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) JSC__JSValue; +pub extern "C" fn JSC__JSValue__push(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; +pub extern "C" fn JSC__JSValue__put(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]const ZigString, JSValue3: JSC__JSValue) void; +pub extern "C" fn JSC__JSValue__putIndex(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: u32, JSValue3: JSC__JSValue) void; +pub extern "C" fn JSC__JSValue__putRecord(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString, arg3: [*c]ZigString, arg4: usize) void; +pub extern "C" fn JSC__JSValue__strictDeepEquals(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject) bool; +pub extern "C" fn JSC__JSValue__stringIncludes(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__symbolFor(arg0: *bindings.JSGlobalObject, arg1: [*c]ZigString) JSC__JSValue; +pub extern "C" fn JSC__JSValue__symbolKeyFor(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString) bool; +pub extern "C" fn JSC__JSValue__toBoolean(JSValue0: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__toBooleanSlow(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) bool; +pub extern "C" fn JSC__JSValue__toError_(JSValue0: JSC__JSValue) JSC__JSValue; +pub extern "C" fn JSC__JSValue__toInt32(JSValue0: JSC__JSValue) i32; +pub extern "C" fn JSC__JSValue__toInt64(JSValue0: JSC__JSValue) i64; +pub extern "C" fn JSC__JSValue__toMatch(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) bool; +pub extern "C" fn JSC__JSValue__toObject(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) [*c]bindings.JSObject; +pub extern "C" fn JSC__JSValue__toString(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) [*c]bindings.JSString; +pub extern "C" fn JSC__JSValue__toStringOrNull(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) [*c]bindings.JSString; +pub extern "C" fn JSC__JSValue__toUInt64NoTruncate(JSValue0: JSC__JSValue) u64; +pub extern "C" fn JSC__JSValue__toZigException(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigException) void; +pub extern "C" fn JSC__JSValue__toZigString(JSValue0: JSC__JSValue, arg1: [*c]ZigString, arg2: *bindings.JSGlobalObject) void; +pub extern "C" fn JSC__Exception__create(arg0: *bindings.JSGlobalObject, arg1: [*c]bindings.JSObject, StackCaptureAction2: u8) [*c]bindings.Exception; +pub extern "C" fn JSC__Exception__getStackTrace(arg0: [*c]bindings.Exception, arg1: [*c]ZigStackTrace) void; +pub extern "C" fn JSC__Exception__value(arg0: [*c]bindings.Exception) JSC__JSValue; +pub extern "C" fn JSC__VM__blockBytesAllocated(arg0: *bindings.VM) usize; +pub extern "C" fn JSC__VM__clearExecutionTimeLimit(arg0: *bindings.VM) void; +pub extern "C" fn JSC__VM__collectAsync(arg0: *bindings.VM) void; +pub extern "C" fn JSC__VM__create(HeapType0: u8) *bindings.VM; +pub extern "C" fn JSC__VM__deferGC(arg0: *bindings.VM, arg1: ?*anyopaque, ArgFn2: ?*const fn (?*anyopaque) callconv(.C) void) void; +pub extern "C" fn JSC__VM__deinit(arg0: *bindings.VM, arg1: *bindings.JSGlobalObject) void; +pub extern "C" fn JSC__VM__deleteAllCode(arg0: *bindings.VM, arg1: *bindings.JSGlobalObject) void; +pub extern "C" fn JSC__VM__drainMicrotasks(arg0: *bindings.VM) void; +pub extern "C" fn JSC__VM__executionForbidden(arg0: *bindings.VM) bool; +pub extern "C" fn JSC__VM__externalMemorySize(arg0: *bindings.VM) usize; +pub extern "C" fn JSC__VM__heapSize(arg0: *bindings.VM) usize; +pub extern "C" fn JSC__VM__holdAPILock(arg0: *bindings.VM, arg1: ?*anyopaque, ArgFn2: ?*const fn (?*anyopaque) callconv(.C) void) void; +pub extern "C" fn JSC__VM__isEntered(arg0: *bindings.VM) bool; +pub extern "C" fn JSC__VM__isJITEnabled(...) bool; +pub extern "C" fn JSC__VM__notifyNeedDebuggerBreak(arg0: *bindings.VM) void; +pub extern "C" fn JSC__VM__notifyNeedShellTimeoutCheck(arg0: *bindings.VM) void; +pub extern "C" fn JSC__VM__notifyNeedTermination(arg0: *bindings.VM) void; +pub extern "C" fn JSC__VM__notifyNeedWatchdogCheck(arg0: *bindings.VM) void; +pub extern "C" fn JSC__VM__releaseWeakRefs(arg0: *bindings.VM) void; +pub extern "C" fn JSC__VM__runGC(arg0: *bindings.VM, arg1: bool) JSC__JSValue; +pub extern "C" fn JSC__VM__setControlFlowProfiler(arg0: *bindings.VM, arg1: bool) void; +pub extern "C" fn JSC__VM__setExecutionForbidden(arg0: *bindings.VM, arg1: bool) void; +pub extern "C" fn JSC__VM__setExecutionTimeLimit(arg0: *bindings.VM, arg1: f64) void; +pub extern "C" fn JSC__VM__shrinkFootprint(arg0: *bindings.VM) void; +pub extern "C" fn JSC__VM__throwError(arg0: *bindings.VM, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; +pub extern "C" fn JSC__VM__whenIdle(arg0: *bindings.VM, ArgFn1: ?*const fn (...) callconv(.C) void) void; +pub extern "C" fn JSC__ThrowScope__clearException(arg0: [*c]bindings.ThrowScope) void; +pub extern "C" fn JSC__ThrowScope__declare(arg0: *bindings.VM, arg1: [*c]u8, arg2: [*c]u8, arg3: usize) bJSC__ThrowScope; +pub extern "C" fn JSC__ThrowScope__exception(arg0: [*c]bindings.ThrowScope) [*c]bindings.Exception; +pub extern "C" fn JSC__ThrowScope__release(arg0: [*c]bindings.ThrowScope) void; +pub extern "C" fn JSC__CatchScope__clearException(arg0: [*c]bindings.CatchScope) void; +pub extern "C" fn JSC__CatchScope__declare(arg0: *bindings.VM, arg1: [*c]u8, arg2: [*c]u8, arg3: usize) bJSC__CatchScope; +pub extern "C" fn JSC__CatchScope__exception(arg0: [*c]bindings.CatchScope) [*c]bindings.Exception; +pub extern "C" fn FFI__ptr__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; +pub extern "C" fn Reader__u8__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; +pub extern "C" fn Reader__u16__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; +pub extern "C" fn Reader__u32__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; +pub extern "C" fn Reader__ptr__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; +pub extern "C" fn Reader__i8__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; +pub extern "C" fn Reader__i16__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; +pub extern "C" fn Reader__i32__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; +pub extern "C" fn Reader__f32__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; +pub extern "C" fn Reader__f64__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; +pub extern "C" fn Reader__i64__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; +pub extern "C" fn Reader__u64__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; +pub extern "C" fn Reader__intptr__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; +pub extern "C" fn Zig__GlobalObject__create(arg0: ?*anyopaque, arg1: i32, arg2: bool, arg3: ?*anyopaque) *bindings.JSGlobalObject; +pub extern "C" fn Zig__GlobalObject__getModuleRegistryMap(arg0: *bindings.JSGlobalObject) ?*anyopaque; +pub extern "C" fn Zig__GlobalObject__resetModuleRegistryMap(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque) bool; +pub extern "C" fn Bun__Path__create(arg0: *bindings.JSGlobalObject, arg1: bool) JSC__JSValue; +pub extern "C" fn ArrayBufferSink__assignToStream(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue, arg2: ?*anyopaque, arg3: [*c]*anyopaque) JSC__JSValue; +pub extern "C" fn ArrayBufferSink__createObject(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque) JSC__JSValue; +pub extern "C" fn ArrayBufferSink__detachPtr(JSValue0: JSC__JSValue) void; +pub extern "C" fn ArrayBufferSink__fromJS(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) ?*anyopaque; +pub extern "C" fn ArrayBufferSink__onClose(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue) void; +pub extern "C" fn ArrayBufferSink__onReady(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, JSValue2: JSC__JSValue) void; +pub extern "C" fn HTTPSResponseSink__assignToStream(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue, arg2: ?*anyopaque, arg3: [*c]*anyopaque) JSC__JSValue; +pub extern "C" fn HTTPSResponseSink__createObject(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque) JSC__JSValue; +pub extern "C" fn HTTPSResponseSink__detachPtr(JSValue0: JSC__JSValue) void; +pub extern "C" fn HTTPSResponseSink__fromJS(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) ?*anyopaque; +pub extern "C" fn HTTPSResponseSink__onClose(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue) void; +pub extern "C" fn HTTPSResponseSink__onReady(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, JSValue2: JSC__JSValue) void; +pub extern "C" fn HTTPResponseSink__assignToStream(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue, arg2: ?*anyopaque, arg3: [*c]*anyopaque) JSC__JSValue; +pub extern "C" fn HTTPResponseSink__createObject(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque) JSC__JSValue; +pub extern "C" fn HTTPResponseSink__detachPtr(JSValue0: JSC__JSValue) void; +pub extern "C" fn HTTPResponseSink__fromJS(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) ?*anyopaque; +pub extern "C" fn HTTPResponseSink__onClose(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue) void; +pub extern "C" fn HTTPResponseSink__onReady(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, JSValue2: JSC__JSValue) void; +pub extern "C" fn FileSink__assignToStream(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue, arg2: ?*anyopaque, arg3: [*c]*anyopaque) JSC__JSValue; +pub extern "C" fn FileSink__createObject(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque) JSC__JSValue; +pub extern "C" fn FileSink__detachPtr(JSValue0: JSC__JSValue) void; +pub extern "C" fn FileSink__fromJS(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) ?*anyopaque; +pub extern "C" fn FileSink__onClose(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue) void; +pub extern "C" fn FileSink__onReady(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, JSValue2: JSC__JSValue) void; +pub extern "C" fn ZigException__fromException(arg0: [*c]bindings.Exception) ZigException; diff --git a/src/bun.js/config.zig b/src/bun.js/config.zig index f95146c6d..e8fdaeba8 100644 --- a/src/bun.js/config.zig +++ b/src/bun.js/config.zig @@ -18,7 +18,7 @@ const Api = @import("../api/schema.zig").Api; const options = @import("../options.zig"); const Bundler = bun.bundler.ServeBundler; const js_printer = bun.js_printer; -const http = @import("../http.zig"); +const http = @import("../bun_dev_http_server.zig"); pub const DefaultBunDefines = struct { pub const Keys = struct { diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index fc2bd7a05..f1ef15b73 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -32,7 +32,7 @@ const ServerEntryPoint = bun.bundler.ServerEntryPoint; const js_printer = bun.js_printer; const js_parser = bun.js_parser; const js_ast = bun.JSAst; -const http = @import("../http.zig"); +const http = @import("../bun_dev_http_server.zig"); const NodeFallbackModules = @import("../node_fallbacks.zig"); const ImportKind = ast.ImportKind; const Analytics = @import("../analytics/analytics_thread.zig"); diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index 755e16647..e165b20fa 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -31,7 +31,7 @@ const ServerEntryPoint = bun.bundler.ServerEntryPoint; const js_printer = bun.js_printer; const js_parser = bun.js_parser; const js_ast = bun.JSAst; -const http = @import("../http.zig"); +const http = @import("../bun_dev_http_server.zig"); const NodeFallbackModules = @import("../node_fallbacks.zig"); const ImportKind = ast.ImportKind; const Analytics = @import("../analytics/analytics_thread.zig"); @@ -408,7 +408,7 @@ pub const RuntimeTranspilerStore = struct { defer { if (should_close_input_file_fd and input_file_fd != 0) { - _ = bun.JSC.Node.Syscall.close(input_file_fd); + _ = bun.sys.close(input_file_fd); input_file_fd = 0; } } @@ -1444,7 +1444,7 @@ pub const ModuleLoader = struct { }; defer { if (should_close_input_file_fd and input_file_fd != 0) { - _ = bun.JSC.Node.Syscall.close(input_file_fd); + _ = bun.sys.close(input_file_fd); input_file_fd = 0; } } diff --git a/src/bun.js/node/dir_iterator.zig b/src/bun.js/node/dir_iterator.zig index 968fde001..994ddaa31 100644 --- a/src/bun.js/node/dir_iterator.zig +++ b/src/bun.js/node/dir_iterator.zig @@ -11,6 +11,7 @@ const os = std.os; const Dir = std.fs.Dir; const JSC = @import("root").bun.JSC; const PathString = JSC.PathString; +const bun = @import("root").bun; const IteratorError = error{ AccessDenied, SystemResources } || os.UnexpectedError; const mem = std.mem; @@ -188,11 +189,37 @@ pub const Iterator = switch (builtin.os.tag) { if (io.Information == 0) return .{ .result = null }; self.index = 0; self.end_index = io.Information; - switch (rc) { - .SUCCESS => {}, - .ACCESS_DENIED => return error.AccessDenied, // Double-check that the Dir was opened with iteration ability + // If the handle is not a directory, we'll get STATUS_INVALID_PARAMETER. + if (rc == .INVALID_PARAMETER) { + return .{ + .err = .{ + .errno = @as(bun.sys.Error.Int, @truncate(@intFromEnum(bun.C.SystemErrno.ENOTDIR))), + .syscall = .NtQueryDirectoryFile, + }, + }; + } + + if (rc == .NO_MORE_FILES) { + self.end_index = self.index; + return .{ .result = null }; + } + + if (rc != .SUCCESS) { + if ((bun.windows.Win32Error.fromNTStatus(rc).toSystemErrno())) |errno| { + return .{ + .err = .{ + .errno = @truncate(@intFromEnum(errno)), + .syscall = .NtQueryDirectoryFile, + }, + }; + } - else => return w.unexpectedStatus(rc), + return .{ + .err = .{ + .errno = @truncate(@intFromEnum(bun.C.SystemErrno.EUNKNOWN)), + .syscall = .NtQueryDirectoryFile, + }, + }; } } @@ -208,8 +235,7 @@ pub const Iterator = switch (builtin.os.tag) { if (mem.eql(u16, name_utf16le, &[_]u16{'.'}) or mem.eql(u16, name_utf16le, &[_]u16{ '.', '.' })) continue; // Trust that Windows gives us valid UTF-16LE - const name_utf8_len = std.unicode.utf16leToUtf8(self.name_data[0..], name_utf16le) catch unreachable; - const name_utf8 = self.name_data[0..name_utf8_len]; + const name_utf8 = strings.fromWPath(self.name_data[0..], name_utf16le); const kind = blk: { const attrs = dir_info.FileAttributes; if (attrs & w.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk Entry.Kind.directory; diff --git a/src/bun.js/node/node_fs.zig b/src/bun.js/node/node_fs.zig index 130ab8cdc..01952dc68 100644 --- a/src/bun.js/node/node_fs.zig +++ b/src/bun.js/node/node_fs.zig @@ -31,9 +31,9 @@ const StringOrBuffer = JSC.Node.StringOrBuffer; const ArgumentsSlice = JSC.Node.ArgumentsSlice; const TimeLike = JSC.Node.TimeLike; const Mode = JSC.Node.Mode; - -const uid_t = std.os.uid_t; -const gid_t = std.os.gid_t; +const E = C.E; +const uid_t = if (Environment.isPosix) std.os.uid_t else i32; +const gid_t = if (Environment.isPosix) std.os.gid_t else i32; /// u63 to allow one null bit const ReadPosition = i64; @@ -44,12 +44,16 @@ pub const FlavoredIO = struct { io: *AsyncIO, }; -pub const default_permission = Syscall.S.IRUSR | - Syscall.S.IWUSR | - Syscall.S.IRGRP | - Syscall.S.IWGRP | - Syscall.S.IROTH | - Syscall.S.IWOTH; +pub const default_permission = if (Environment.isPosix) + Syscall.S.IRUSR | + Syscall.S.IWUSR | + Syscall.S.IRGRP | + Syscall.S.IWGRP | + Syscall.S.IROTH | + Syscall.S.IWOTH +else + // TODO: + 0; const ArrayBuffer = JSC.MarkedArrayBuffer; const Buffer = JSC.Buffer; @@ -1212,7 +1216,9 @@ pub const Arguments = struct { // be absolute. When using 'junction', the target argument // will automatically be normalized to absolute path. if (next_val.isString()) { - comptime if (Environment.isWindows) @compileError("Add support for type argument on Windows"); + if (comptime Environment.isWindows) { + bun.todo(@src(), {}); + } arguments.eat(); } } @@ -2174,7 +2180,7 @@ pub const Arguments = struct { mode: Mode = 0o666, file: PathOrFileDescriptor, data: StringOrBuffer, - dirfd: FileDescriptor = @as(FileDescriptor, @intCast(std.fs.cwd().fd)), + dirfd: FileDescriptor, pub fn deinit(self: WriteFile) void { self.file.deinit(); @@ -2290,6 +2296,7 @@ pub const Arguments = struct { .flag = flag, .mode = mode, .data = data, + .dirfd = bun.toFD(std.fs.cwd().fd), }; } }; @@ -3058,6 +3065,10 @@ pub const NodeFS = struct { pub const ReturnType = Return; pub fn access(this: *NodeFS, args: Arguments.Access, comptime _: Flavor) Maybe(Return.Access) { + if (comptime Environment.isWindows) { + return Maybe(Return.Access).todo; + } + var path = args.path.sliceZ(&this.sync_error_buf); const rc = Syscall.system.access(path, @intFromEnum(args.mode)); return Maybe(Return.Access).errnoSysP(rc, .access, path) orelse Maybe(Return.Access).success; @@ -3391,6 +3402,10 @@ pub const NodeFS = struct { } pub fn chown(this: *NodeFS, args: Arguments.Chown, comptime flavor: Flavor) Maybe(Return.Chown) { + if (comptime Environment.isWindows) { + return Maybe(Return.Fchmod).todo; + } + const path = args.path.sliceZ(&this.sync_error_buf); switch (comptime flavor) { @@ -3403,6 +3418,10 @@ pub const NodeFS = struct { /// This should almost never be async pub fn chmod(this: *NodeFS, args: Arguments.Chmod, comptime flavor: Flavor) Maybe(Return.Chmod) { + if (comptime Environment.isWindows) { + return Maybe(Return.Fchmod).todo; + } + const path = args.path.sliceZ(&this.sync_error_buf); switch (comptime flavor) { @@ -3418,6 +3437,10 @@ pub const NodeFS = struct { /// This should almost never be async pub fn fchmod(_: *NodeFS, args: Arguments.FChmod, comptime flavor: Flavor) Maybe(Return.Fchmod) { + if (comptime Environment.isWindows) { + return Maybe(Return.Fchmod).todo; + } + switch (comptime flavor) { .sync => { return Syscall.fchmod(args.fd, args.mode); @@ -3428,6 +3451,10 @@ pub const NodeFS = struct { return Maybe(Return.Fchmod).todo; } pub fn fchown(_: *NodeFS, args: Arguments.Fchown, comptime flavor: Flavor) Maybe(Return.Fchown) { + if (comptime Environment.isWindows) { + return Maybe(Return.Fchown).todo; + } + switch (comptime flavor) { .sync => { return Maybe(Return.Fchown).errnoSys(C.fchown(args.fd, args.uid, args.gid), .fchown) orelse @@ -3439,6 +3466,9 @@ pub const NodeFS = struct { return Maybe(Return.Fchown).todo; } pub fn fdatasync(_: *NodeFS, args: Arguments.FdataSync, comptime flavor: Flavor) Maybe(Return.Fdatasync) { + if (comptime Environment.isWindows) { + return Maybe(Return.Fdatasync).todo; + } switch (comptime flavor) { .sync => return Maybe(Return.Fdatasync).errnoSys(system.fdatasync(args.fd), .fdatasync) orelse Maybe(Return.Fdatasync).success, @@ -3448,12 +3478,18 @@ pub const NodeFS = struct { return Maybe(Return.Fdatasync).todo; } pub fn fstat(_: *NodeFS, args: Arguments.Fstat, comptime flavor: Flavor) Maybe(Return.Fstat) { + if (comptime Environment.isWindows) { + return Maybe(Return.Fstat).todo; + } + switch (comptime flavor) { .sync => { - return switch (Syscall.fstat(args.fd)) { - .result => |result| Maybe(Return.Fstat){ .result = Stats.init(result, false) }, - .err => |err| Maybe(Return.Fstat){ .err = err }, - }; + if (comptime Environment.isPosix) { + return switch (Syscall.fstat(args.fd)) { + .result => |result| Maybe(Return.Fstat){ .result = Stats.init(result, false) }, + .err => |err| Maybe(Return.Fstat){ .err = err }, + }; + } }, else => {}, } @@ -3462,6 +3498,10 @@ pub const NodeFS = struct { } pub fn fsync(_: *NodeFS, args: Arguments.Fsync, comptime flavor: Flavor) Maybe(Return.Fsync) { + if (comptime Environment.isWindows) { + return Maybe(Return.Fsync).todo; + } + switch (comptime flavor) { .sync => return Maybe(Return.Fsync).errnoSys(system.fsync(args.fd), .fsync) orelse Maybe(Return.Fsync).success, @@ -3472,8 +3512,7 @@ pub const NodeFS = struct { } pub fn ftruncateSync(args: Arguments.FTruncate) Maybe(Return.Ftruncate) { - return Maybe(Return.Ftruncate).errnoSys(system.ftruncate(args.fd, args.len orelse 0), .ftruncate) orelse - Maybe(Return.Ftruncate).success; + return Syscall.ftruncate(args.fd, args.len orelse 0); } pub fn ftruncate(_: *NodeFS, args: Arguments.FTruncate, comptime flavor: Flavor) Maybe(Return.Ftruncate) { @@ -3485,6 +3524,10 @@ pub const NodeFS = struct { return Maybe(Return.Ftruncate).todo; } pub fn futimes(_: *NodeFS, args: Arguments.Futimes, comptime flavor: Flavor) Maybe(Return.Futimes) { + if (comptime Environment.isWindows) { + return Maybe(Return.Futimes).todo; + } + var times = [2]std.os.timespec{ .{ .tv_sec = args.mtime, @@ -3508,6 +3551,10 @@ pub const NodeFS = struct { } pub fn lchmod(this: *NodeFS, args: Arguments.LCHmod, comptime flavor: Flavor) Maybe(Return.Lchmod) { + if (comptime Environment.isWindows) { + return Maybe(Return.Lchmod).todo; + } + const path = args.path.sliceZ(&this.sync_error_buf); switch (comptime flavor) { @@ -3522,6 +3569,10 @@ pub const NodeFS = struct { } pub fn lchown(this: *NodeFS, args: Arguments.LChown, comptime flavor: Flavor) Maybe(Return.Lchown) { + if (comptime Environment.isWindows) { + return Maybe(Return.Lchown).todo; + } + const path = args.path.sliceZ(&this.sync_error_buf); switch (comptime flavor) { @@ -3550,6 +3601,10 @@ pub const NodeFS = struct { return Maybe(Return.Link).todo; } pub fn lstat(this: *NodeFS, args: Arguments.Lstat, comptime flavor: Flavor) Maybe(Return.Lstat) { + if (comptime Environment.isWindows) { + return Maybe(Return.Lstat).todo; + } + _ = flavor; return switch (Syscall.lstat( args.path.sliceZ( @@ -3589,7 +3644,7 @@ pub const NodeFS = struct { // TODO: verify this works correctly with unicode codepoints pub fn mkdirRecursive(this: *NodeFS, args: Arguments.Mkdir, comptime flavor: Flavor) Maybe(Return.Mkdir) { const Option = Maybe(Return.Mkdir); - if (comptime Environment.isWindows) @compileError("This needs to be implemented on Windows."); + if (comptime Environment.isWindows) return Option.todo; switch (comptime flavor) { // The sync version does no allocation except when returning the path @@ -3822,6 +3877,7 @@ pub const NodeFS = struct { } pub fn read(this: *NodeFS, args: Arguments.Read, comptime flavor: Flavor) Maybe(Return.Read) { + if (comptime Environment.isWindows) return Maybe(Return.Read).todo; return if (args.position != null) this._pread( args, @@ -3835,14 +3891,17 @@ pub const NodeFS = struct { } pub fn readv(this: *NodeFS, args: Arguments.Readv, comptime flavor: Flavor) Maybe(Return.Read) { + if (comptime Environment.isWindows) return Maybe(Return.Read).todo; return if (args.position != null) _preadv(this, args, flavor) else _readv(this, args, flavor); } pub fn writev(this: *NodeFS, args: Arguments.Writev, comptime flavor: Flavor) Maybe(Return.Write) { + if (comptime Environment.isWindows) return Maybe(Return.Write).todo; return if (args.position != null) _pwritev(this, args, flavor) else _writev(this, args, flavor); } pub fn write(this: *NodeFS, args: Arguments.Write, comptime flavor: Flavor) Maybe(Return.Write) { + if (comptime Environment.isWindows) return Maybe(Return.Write).todo; return if (args.position != null) _pwrite(this, args, flavor) else _write(this, args, flavor); } fn _write(_: *NodeFS, args: Arguments.Write, comptime flavor: Flavor) Maybe(Return.Write) { @@ -4023,7 +4082,7 @@ pub const NodeFS = struct { } var entries = std.ArrayList(ExpectedType).init(bun.default_allocator); - var dir = std.fs.Dir{ .fd = fd }; + var dir = std.fs.Dir{ .fd = bun.fdcast(fd) }; var iterator = DirIterator.iterate(dir); var entry = iterator.next(); while (switch (entry) { @@ -4159,9 +4218,8 @@ pub const NodeFS = struct { // Only used in DOMFormData if (args.offset > 0) { - std.os.lseek_SET(fd, args.offset) catch {}; + _ = Syscall.setFileOffset(fd, args.offset); } - // For certain files, the size might be 0 but the file might still have contents. const size = @as( u64, @@ -4318,13 +4376,13 @@ pub const NodeFS = struct { 0 else brk: { // on linux, it's absolutely positioned - const pos = JSC.Node.Syscall.system.lseek( + const pos = bun.sys.system.lseek( fd, @as(std.os.off_t, @intCast(0)), std.os.linux.SEEK.CUR, ); - switch (JSC.Node.Syscall.getErrno(pos)) { + switch (bun.sys.getErrno(pos)) { .SUCCESS => break :brk @as(usize, @intCast(pos)), else => break :preallocate, } @@ -4551,7 +4609,7 @@ pub const NodeFS = struct { else => .FAULT, }; return Maybe(Return.Rm){ - .err = JSC.Node.Syscall.Error.fromCode(errno, .rmdir), + .err = bun.sys.Error.fromCode(errno, .rmdir), }; }; @@ -4617,10 +4675,10 @@ pub const NodeFS = struct { return Maybe(Return.Rm).success; } - } else if (comptime Environment.isLinux) { + } else if (comptime Environment.isLinux or Environment.isWindows) { if (args.recursive) { std.fs.cwd().deleteTree(args.path.slice()) catch |err| { - const errno: std.os.E = switch (err) { + const errno: E = switch (err) { error.InvalidHandle => .BADF, error.AccessDenied => .PERM, error.FileTooBig => .FBIG, @@ -4650,15 +4708,15 @@ pub const NodeFS = struct { return Maybe(Return.Rm).success; } return Maybe(Return.Rm){ - .err = JSC.Node.Syscall.Error.fromCode(errno, .unlink), + .err = bun.sys.Error.fromCode(errno, .unlink), }; }; return Maybe(Return.Rm).success; } } - { - var dest = args.path.sliceZ(&this.sync_error_buf); + if (comptime Environment.isPosix) { + var dest = args.path.osPath(&this.sync_error_buf); std.os.unlinkZ(dest) catch |er| { // empircally, it seems to return AccessDenied when the // file is actually a directory on macOS. @@ -4670,7 +4728,7 @@ pub const NodeFS = struct { return Maybe(Return.Rm).success; } - const code: std.os.E = switch (err) { + const code: E = switch (err) { error.AccessDenied => .PERM, error.SymLinkLoop => .LOOP, error.NameTooLong => .NAMETOOLONG, @@ -4684,7 +4742,7 @@ pub const NodeFS = struct { }; return .{ - .err = JSC.Node.Syscall.Error.fromCode( + .err = bun.sys.Error.fromCode( code, .rmdir, ), @@ -4699,7 +4757,7 @@ pub const NodeFS = struct { } { - const code: std.os.E = switch (er) { + const code: E = switch (er) { error.AccessDenied => .PERM, error.SymLinkLoop => .LOOP, error.NameTooLong => .NAMETOOLONG, @@ -4713,7 +4771,66 @@ pub const NodeFS = struct { }; return .{ - .err = JSC.Node.Syscall.Error.fromCode( + .err = bun.sys.Error.fromCode( + code, + .unlink, + ), + }; + } + }; + + return Maybe(Return.Rm).success; + } + + if (comptime Environment.isWindows) { + var dest = args.path.osPath(&this.sync_error_buf); + std.os.windows.DeleteFile(dest, .{ + .dir = null, + .remove_dir = brk: { + const file_attrs = std.os.windows.GetFileAttributesW(dest.ptr) catch |err| { + if (args.force) { + return Maybe(Return.Rm).success; + } + + const code: E = switch (err) { + error.FileNotFound => .NOENT, + error.PermissionDenied => .PERM, + else => .INVAL, + }; + + return .{ + .err = bun.sys.Error.fromCode( + code, + .unlink, + ), + }; + }; + // TODO: check FILE_ATTRIBUTE_INVALID + break :brk (file_attrs & std.os.windows.FILE_ATTRIBUTE_DIRECTORY) != 0; + }, + }) catch |er| { + // empircally, it seems to return AccessDenied when the + // file is actually a directory on macOS. + + if (args.force) { + return Maybe(Return.Rm).success; + } + + { + const code: E = switch (er) { + error.FileNotFound => .NOENT, + error.AccessDenied => .PERM, + error.NameTooLong => .INVAL, + error.FileBusy => .BUSY, + error.NotDir => .NOTDIR, + error.IsDir => .ISDIR, + error.DirNotEmpty => .INVAL, + error.NetworkNotFound => .NOENT, + else => .UNKNOWN, + }; + + return .{ + .err = bun.sys.Error.fromCode( code, .unlink, ), @@ -4730,6 +4847,9 @@ pub const NodeFS = struct { return Maybe(Return.Rm).todo; } pub fn stat(this: *NodeFS, args: Arguments.Stat, comptime flavor: Flavor) Maybe(Return.Stat) { + if (comptime Environment.isWindows) { + return Maybe(Return.Stat).todo; + } _ = flavor; return @as(Maybe(Return.Stat), switch (Syscall.stat( @@ -4748,6 +4868,10 @@ pub const NodeFS = struct { } pub fn symlink(this: *NodeFS, args: Arguments.Symlink, comptime flavor: Flavor) Maybe(Return.Symlink) { + if (comptime Environment.isWindows) { + return Maybe(Return.Symlink).todo; + } + var to_buf: [bun.MAX_PATH_BYTES]u8 = undefined; switch (comptime flavor) { @@ -4763,6 +4887,10 @@ pub const NodeFS = struct { return Maybe(Return.Symlink).todo; } fn _truncate(this: *NodeFS, path: PathLike, len: JSC.WebCore.Blob.SizeType, comptime flavor: Flavor) Maybe(Return.Truncate) { + if (comptime Environment.isWindows) { + return Maybe(Return.Truncate).todo; + } + switch (comptime flavor) { .sync => { return Maybe(Return.Truncate).errno(C.truncate(path.sliceZ(&this.sync_error_buf), len)) orelse @@ -4787,6 +4915,10 @@ pub const NodeFS = struct { }; } pub fn unlink(this: *NodeFS, args: Arguments.Unlink, comptime flavor: Flavor) Maybe(Return.Unlink) { + if (comptime Environment.isWindows) { + return Maybe(Return.Unlink).todo; + } + switch (comptime flavor) { .sync => { return Maybe(Return.Unlink).errnoSysP(system.unlink(args.path.sliceZ(&this.sync_error_buf)), .unlink, args.path.slice()) orelse @@ -4801,6 +4933,10 @@ pub const NodeFS = struct { return Maybe(Return.UnwatchFile).todo; } pub fn utimes(this: *NodeFS, args: Arguments.Utimes, comptime flavor: Flavor) Maybe(Return.Utimes) { + if (comptime Environment.isWindows) { + return Maybe(Return.Utimes).todo; + } + var times = [2]std.c.timeval{ .{ .tv_sec = args.mtime, @@ -4829,6 +4965,10 @@ pub const NodeFS = struct { } pub fn lutimes(this: *NodeFS, args: Arguments.Lutimes, comptime flavor: Flavor) Maybe(Return.Lutimes) { + if (comptime Environment.isWindows) { + return Maybe(Return.Lutimes).todo; + } + var times = [2]std.c.timeval{ .{ .tv_sec = args.mtime, @@ -4856,6 +4996,11 @@ pub const NodeFS = struct { return Maybe(Return.Lutimes).todo; } pub fn watch(_: *NodeFS, args: Arguments.Watch, comptime _: Flavor) Maybe(Return.Watch) { + if (comptime Environment.isWindows) { + args.global_this.throwTODO("watch is not supported on Windows yet"); + return Maybe(Return.Watch){ .result = JSC.JSValue.undefined }; + } + const watcher = args.createFSWatcher() catch |err| { var buf = std.fmt.allocPrint(bun.default_allocator, "{s} watching {}", .{ @errorName(err), strings.QuotedFormatter{ .text = args.path.slice() } }) catch unreachable; defer bun.default_allocator.free(buf); diff --git a/src/bun.js/node/node_os.zig b/src/bun.js/node/node_os.zig index a4efe4454..07dec1c7d 100644 --- a/src/bun.js/node/node_os.zig +++ b/src/bun.js/node/node_os.zig @@ -359,7 +359,12 @@ pub const Os = struct { pub fn hostname(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSC.JSValue { JSC.markBinding(@src()); - var name_buffer: [std.os.HOST_NAME_MAX]u8 = undefined; + if (comptime Environment.isWindows) { + globalThis.throwTODO("hostname() is not implemented on Windows"); + return .zero; + } + + var name_buffer: [bun.HOST_NAME_MAX]u8 = undefined; return JSC.ZigString.init(std.os.gethostname(&name_buffer) catch "unknown").withEncoding().toValueGC(globalThis); } @@ -369,14 +374,18 @@ pub const Os = struct { const result = C.getSystemLoadavg(); return JSC.JSArray.from(globalThis, &.{ - JSC.JSValue.jsDoubleNumber(result[0]), - JSC.JSValue.jsDoubleNumber(result[1]), - JSC.JSValue.jsDoubleNumber(result[2]), + JSC.JSValue.jsNumber(result[0]), + JSC.JSValue.jsNumber(result[1]), + JSC.JSValue.jsNumber(result[2]), }); } pub fn networkInterfaces(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSC.JSValue { JSC.markBinding(@src()); + if (comptime Environment.isWindows) { + globalThis.throwTODO("networkInterfaces() is not implemented on Windows"); + return .zero; + } // getifaddrs sets a pointer to a linked list var interface_start: ?*C.ifaddrs = null; @@ -558,7 +567,7 @@ pub const Os = struct { pub fn release(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSC.JSValue { JSC.markBinding(@src()); - var name_buffer: [std.os.HOST_NAME_MAX]u8 = undefined; + var name_buffer: [bun.HOST_NAME_MAX]u8 = undefined; return JSC.ZigString.init(C.getRelease(&name_buffer)).withEncoding().toValueGC(globalThis); } @@ -680,7 +689,7 @@ pub const Os = struct { pub fn version(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSC.JSValue { JSC.markBinding(@src()); - var name_buffer: [std.os.HOST_NAME_MAX]u8 = undefined; + var name_buffer: [bun.HOST_NAME_MAX]u8 = undefined; return JSC.ZigString.init(C.getVersion(&name_buffer)).withEncoding().toValueGC(globalThis); } diff --git a/src/bun.js/node/path_watcher.zig b/src/bun.js/node/path_watcher.zig index 1f1b9d1a1..4f44a68ff 100644 --- a/src/bun.js/node/path_watcher.zig +++ b/src/bun.js/node/path_watcher.zig @@ -437,6 +437,10 @@ pub const PathWatcherManager = struct { watcher: *PathWatcher, buf: *[bun.MAX_PATH_BYTES + 1]u8, ) !void { + if (comptime Environment.isWindows) { + bun.todo(@src(), "implement directory watching on windows"); + return; + } const manager = this.manager; const path = this.path; const fd = path.fd; @@ -480,6 +484,10 @@ pub const PathWatcherManager = struct { } fn run(this: *DirectoryRegisterTask) void { + if (comptime Environment.isWindows) { + return bun.todo(@src(), {}); + } + var buf: [bun.MAX_PATH_BYTES + 1]u8 = undefined; while (this.getNext()) |watcher| { @@ -656,7 +664,7 @@ pub const PathWatcherManager = struct { var it = this.file_paths.iterator(); while (it.next()) |*entry| { const path = entry.value_ptr.*; - std.os.close(path.fd); + _ = bun.sys.close(path.fd); bun.default_allocator.free(path.path); } diff --git a/src/bun.js/node/syscall.zig b/src/bun.js/node/syscall.zig index 13158481f..95c343f1f 100644 --- a/src/bun.js/node/syscall.zig +++ b/src/bun.js/node/syscall.zig @@ -15,15 +15,16 @@ const fd_t = bun.FileDescriptor; const C = @import("root").bun.C; const linux = os.linux; const Maybe = JSC.Maybe; +const kernel32 = bun.windows; const log = bun.Output.scoped(.SYS, false); pub const syslog = log; // On Linux AARCh64, zig is missing stat & lstat syscalls const use_libc = !(Environment.isLinux and Environment.isX64); -pub const system = if (Environment.isLinux) linux else @import("root").bun.AsyncIO.darwin; +pub const system = if (Environment.isLinux) linux else @import("root").bun.AsyncIO.system; pub const S = struct { - pub usingnamespace if (Environment.isLinux) linux.S else std.os.S; + pub usingnamespace if (Environment.isLinux) linux.S else if (Environment.isPosix) std.os.S else struct {}; }; const sys = std.os.system; @@ -48,9 +49,11 @@ else if (Environment.isLinux) else @compileError("STAT"); +const windows = bun.windows; + pub const Tag = enum(u8) { TODO, - + dup, access, chmod, chown, @@ -110,6 +113,8 @@ pub const Tag = enum(u8) { pwritev, readv, preadv, + NtQueryDirectoryFile, + pub var strings = std.EnumMap(Tag, JSC.C.JSStringRef).initFull(null); }; const PathString = @import("root").bun.PathString; @@ -130,43 +135,92 @@ pub fn getcwd(buf: *[bun.MAX_PATH_BYTES]u8) Maybe([]const u8) { Result.errnoSys(0, .getcwd).?; } -pub fn fchmod(fd: bun.FileDescriptor, mode: JSC.Node.Mode) Maybe(void) { +pub fn fchmod(fd_: bun.FileDescriptor, mode: JSC.Node.Mode) Maybe(void) { + const fd = bun.fdcast(fd_); return Maybe(void).errnoSys(C.fchmod(fd, mode), .fchmod) orelse Maybe(void).success; } -pub fn chdir(destination: [:0]const u8) Maybe(void) { - const rc = sys.chdir(destination); - return Maybe(void).errnoSys(rc, .chdir) orelse Maybe(void).success; +pub fn chdirOSPath(destination: bun.OSPathSlice) Maybe(void) { + if (comptime Environment.isPosix) { + const rc = sys.chdir(destination); + return Maybe(void).errnoSys(rc, .chdir) orelse Maybe(void).success; + } + + if (comptime Environment.isWindows) { + if (kernel32.SetCurrentDirectory(destination) != 0) { + return Maybe(void).errnoSys(0, .chdir) orelse Maybe(void).success; + } + + return Maybe(void).success; + } + + @compileError("Not implemented yet"); +} + +pub fn chdir(destination: anytype) Maybe(void) { + const Type = @TypeOf(destination); + + if (comptime Environment.isPosix) { + if (comptime Type == []u8 or Type == []const u8) { + return chdirOSPath( + &(std.os.toPosixPath(destination) catch return .{ .err = .{ + .errno = @intFromEnum(bun.C.SystemErrno.EINVAL), + .syscall = .chdir, + } }), + ); + } + + return chdirOSPath(destination); + } + + if (comptime Environment.isWindows) { + if (comptime Type == bun.OSPathSlice or Type == [:0]u16) { + return chdirOSPath(@as(bun.OSPathSlice, destination)); + } + + if (comptime Type == *[*:0]u16) { + if (kernel32.SetCurrentDirectory(destination) != 0) { + return Maybe(void).errnoSys(0, .chdir) orelse Maybe(void).success; + } + + return Maybe(void).success; + } + + var wbuf: bun.MAX_WPATH = undefined; + return chdirOSPath(bun.strings.toWPath(&wbuf, destination)); + } + + return Maybe(void).todo; } -pub fn stat(path: [:0]const u8) Maybe(os.Stat) { - var stat_ = mem.zeroes(os.Stat); +pub fn stat(path: [:0]const u8) Maybe(bun.Stat) { + var stat_ = mem.zeroes(bun.Stat); const rc = statSym(path, &stat_); if (comptime Environment.allow_assert) log("stat({s}) = {d}", .{ bun.asByteSlice(path), rc }); - if (Maybe(os.Stat).errnoSys(rc, .stat)) |err| return err; - return Maybe(os.Stat){ .result = stat_ }; + if (Maybe(bun.Stat).errnoSys(rc, .stat)) |err| return err; + return Maybe(bun.Stat){ .result = stat_ }; } -pub fn lstat(path: [:0]const u8) Maybe(os.Stat) { - var stat_ = mem.zeroes(os.Stat); - if (Maybe(os.Stat).errnoSys(lstat64(path, &stat_), .lstat)) |err| return err; - return Maybe(os.Stat){ .result = stat_ }; +pub fn lstat(path: [:0]const u8) Maybe(bun.Stat) { + var stat_ = mem.zeroes(bun.Stat); + if (Maybe(bun.Stat).errnoSys(lstat64(path, &stat_), .lstat)) |err| return err; + return Maybe(bun.Stat){ .result = stat_ }; } -pub fn fstat(fd: bun.FileDescriptor) Maybe(os.Stat) { - var stat_ = mem.zeroes(os.Stat); +pub fn fstat(fd: bun.FileDescriptor) Maybe(bun.Stat) { + var stat_ = mem.zeroes(bun.Stat); const rc = fstatSym(fd, &stat_); if (comptime Environment.allow_assert) log("fstat({d}) = {d}", .{ fd, rc }); - if (Maybe(os.Stat).errnoSys(rc, .fstat)) |err| return err; - return Maybe(os.Stat){ .result = stat_ }; + if (Maybe(bun.Stat).errnoSys(rc, .fstat)) |err| return err; + return Maybe(bun.Stat){ .result = stat_ }; } pub fn mkdir(file_path: [:0]const u8, flags: JSC.Node.Mode) Maybe(void) { @@ -177,16 +231,29 @@ pub fn mkdir(file_path: [:0]const u8, flags: JSC.Node.Mode) Maybe(void) { if (comptime Environment.isLinux) { return Maybe(void).errnoSysP(linux.mkdir(file_path, flags), .mkdir, file_path) orelse Maybe(void).success; } + var wbuf: bun.MAX_WPATH = undefined; + _ = kernel32.CreateDirectoryW(bun.strings.toWPath(&wbuf, file_path).ptr, null); + + return Maybe(void).errnoSysP(0, .mkdir, file_path) orelse Maybe(void).success; } -pub fn fcntl(fd: bun.FileDescriptor, cmd: i32, arg: usize) Maybe(usize) { +pub fn fcntl(fd_: bun.FileDescriptor, cmd: i32, arg: usize) Maybe(usize) { + const fd = bun.fdcast(fd_); const result = fcntl_symbol(fd, cmd, arg); if (Maybe(usize).errnoSys(result, .fcntl)) |err| return err; return .{ .result = @as(usize, @intCast(result)) }; } -pub fn getErrno(rc: anytype) std.os.E { - if (comptime Environment.isMac) return std.os.errno(rc); +pub fn getErrno(rc: anytype) bun.C.E { + if (comptime Environment.isWindows) { + if (bun.windows.Win32Error.get().toSystemErrno()) |e| { + return e.toE(); + } + + return bun.C.E.UNKNOWN; + } + + if (comptime use_libc) return std.os.errno(rc); const Type = @TypeOf(rc); return switch (Type) { @@ -196,7 +263,139 @@ pub fn getErrno(rc: anytype) std.os.E { }; } -pub fn openat(dirfd: bun.FileDescriptor, file_path: [:0]const u8, flags: JSC.Node.Mode, perm: JSC.Node.Mode) Maybe(bun.FileDescriptor) { +// pub fn openOptionsFromFlagsWindows(flags: u32) windows.OpenFileOptions { +// const w = windows; +// const O = std.os.O; + +// var access_mask: w.ULONG = w.READ_CONTROL | w.FILE_WRITE_ATTRIBUTES | w.SYNCHRONIZE; +// if (flags & O.RDWR != 0) { +// access_mask |= w.GENERIC_READ | w.GENERIC_WRITE; +// } else if (flags & O.WRONLY != 0) { +// access_mask |= w.GENERIC_WRITE; +// } else { +// access_mask |= w.GENERIC_READ | w.GENERIC_WRITE; +// } + +// const filter: windows.OpenFileOptions.Filter = if (flags & O.DIRECTORY != 0) .dir_only else .file_only; +// const follow_symlinks: bool = flags & O.NOFOLLOW == 0; + +// const creation: w.ULONG = blk: { +// if (flags & O.CREAT != 0) { +// if (flags & O.EXCL != 0) { +// break :blk w.FILE_CREATE; +// } +// } +// break :blk w.FILE_OPEN; +// }; + +// return .{ +// .access_mask = access_mask, +// .io_mode = .blocking, +// .creation = creation, +// .filter = filter, +// .follow_symlinks = follow_symlinks, +// }; +// } +const O = std.os.O; +const w = std.os.windows; + +pub fn openatWindows(dirfD: bun.FileDescriptor, path: []const u16, flags: JSC.Node.Mode) Maybe(bun.FileDescriptor) { + const nonblock = flags & O.NONBLOCK != 0; + + var access_mask: w.ULONG = w.READ_CONTROL | w.FILE_WRITE_ATTRIBUTES | w.SYNCHRONIZE; + + if (flags & O.RDWR != 0) { + access_mask |= w.GENERIC_READ | w.GENERIC_WRITE; + } else if (flags & O.WRONLY != 0) { + access_mask |= w.GENERIC_WRITE; + } else if (flags & O.APPEND != 0) { + access_mask |= w.FILE_APPEND_DATA; + } else { + access_mask |= w.GENERIC_READ; + } + + var result: windows.HANDLE = undefined; + + const path_len_bytes = std.math.cast(u16, path.len * 2) orelse return .{ + .err = .{ + .errno = @intFromEnum(bun.C.E.NOMEM), + .syscall = .open, + }, + }; + var nt_name = windows.UNICODE_STRING{ + .Length = path_len_bytes, + .MaximumLength = path_len_bytes, + .Buffer = @constCast(path.ptr), + }; + var attr = windows.OBJECT_ATTRIBUTES{ + .Length = @sizeOf(windows.OBJECT_ATTRIBUTES), + .RootDirectory = if (dirfD == bun.invalid_fd or std.fs.path.isAbsoluteWindowsWTF16(path)) null else bun.fdcast(dirfD), + .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here. + .ObjectName = &nt_name, + .SecurityDescriptor = null, + .SecurityQualityOfService = null, + }; + var io: windows.IO_STATUS_BLOCK = undefined; + const blocking_flag: windows.ULONG = if (!nonblock) windows.FILE_SYNCHRONOUS_IO_NONALERT else 0; + const file_or_dir_flag: windows.ULONG = switch (flags & O.DIRECTORY != 0) { + // .file_only => windows.FILE_NON_DIRECTORY_FILE, + true => windows.FILE_DIRECTORY_FILE, + false => 0, + }; + const follow_symlinks = flags & O.NOFOLLOW == 0; + const creation: w.ULONG = blk: { + if (flags & O.CREAT != 0) { + if (flags & O.EXCL != 0) { + break :blk w.FILE_CREATE; + } + } + break :blk w.FILE_OPEN; + }; + + const wflags: windows.ULONG = if (follow_symlinks) file_or_dir_flag | blocking_flag else file_or_dir_flag | windows.FILE_OPEN_REPARSE_POINT; + + while (true) { + const rc = windows.ntdll.NtCreateFile( + &result, + access_mask, + &attr, + &io, + null, + w.FILE_ATTRIBUTE_NORMAL, + w.FILE_SHARE_WRITE | w.FILE_SHARE_READ | w.FILE_SHARE_DELETE, + creation, + wflags, + null, + 0, + ); + switch (windows.Win32Error.fromNTStatus(rc)) { + .SUCCESS => { + return JSC.Maybe(bun.FileDescriptor){ + .result = bun.toFD(result), + }; + }, + else => |code| { + if (code.toSystemErrno()) |sys_err| { + return .{ + .err = .{ + .errno = @truncate(@intFromEnum(sys_err)), + .syscall = .open, + }, + }; + } + + return .{ + .err = .{ + .errno = @intFromEnum(bun.C.E.UNKNOWN), + .syscall = .open, + }, + }; + }, + } + } +} + +pub fn openatOSPath(dirfd: bun.FileDescriptor, file_path: bun.OSPathSlice, flags: JSC.Node.Mode, perm: JSC.Node.Mode) Maybe(bun.FileDescriptor) { if (comptime Environment.isMac) { // https://opensource.apple.com/source/xnu/xnu-7195.81.3/libsyscall/wrappers/open-base.c const rc = bun.AsyncIO.darwin.@"openat$NOCANCEL"(dirfd, file_path.ptr, @as(c_uint, @intCast(flags)), @as(c_int, @intCast(perm))); @@ -213,6 +412,10 @@ pub fn openat(dirfd: bun.FileDescriptor, file_path: [:0]const u8, flags: JSC.Nod }; } + if (comptime Environment.isWindows) { + return openatWindows(dirfd, file_path, flags); + } + while (true) { const rc = Syscall.system.openat(@as(Syscall.system.fd_t, @intCast(dirfd)), file_path, flags, perm); log("openat({d}, {s}) = {d}", .{ dirfd, file_path, rc }); @@ -233,14 +436,23 @@ pub fn openat(dirfd: bun.FileDescriptor, file_path: [:0]const u8, flags: JSC.Nod unreachable; } +pub fn openat(dirfd: bun.FileDescriptor, file_path: [:0]const u8, flags: JSC.Node.Mode, perm: JSC.Node.Mode) Maybe(bun.FileDescriptor) { + if (comptime Environment.isWindows) { + var wbuf: bun.MAX_WPATH = undefined; + return openatWindows(dirfd, bun.strings.toWPath(&wbuf, file_path), flags); + } + + return openatOSPath(dirfd, file_path, flags, perm); +} + pub fn open(file_path: [:0]const u8, flags: JSC.Node.Mode, perm: JSC.Node.Mode) Maybe(bun.FileDescriptor) { // this is what open() does anyway. - return openat(@as(bun.FileDescriptor, @intCast(std.fs.cwd().fd)), file_path, flags, perm); + return openat(bun.toFD((std.fs.cwd().fd)), file_path, flags, perm); } /// This function will prevent stdout and stderr from being closed. -pub fn close(fd: std.os.fd_t) ?Syscall.Error { - if (fd == std.os.STDOUT_FILENO or fd == std.os.STDERR_FILENO) { +pub fn close(fd: bun.FileDescriptor) ?Syscall.Error { + if (fd == bun.STDOUT_FD or fd == bun.STDERR_FD) { log("close({d}) SKIPPED", .{fd}); return null; } @@ -248,7 +460,7 @@ pub fn close(fd: std.os.fd_t) ?Syscall.Error { return closeAllowingStdoutAndStderr(fd); } -pub fn closeAllowingStdoutAndStderr(fd: std.os.fd_t) ?Syscall.Error { +pub fn closeAllowingStdoutAndStderr(fd: bun.FileDescriptor) ?Syscall.Error { log("close({d})", .{fd}); std.debug.assert(fd != bun.invalid_fd); if (comptime std.meta.trait.isSignedInt(@TypeOf(fd))) @@ -269,6 +481,14 @@ pub fn closeAllowingStdoutAndStderr(fd: std.os.fd_t) ?Syscall.Error { }; } + if (comptime Environment.isWindows) { + if (kernel32.CloseHandle(bun.fdcast(fd)) == 0) { + return Syscall.Error{ .errno = @intFromEnum(os.E.BADF), .syscall = .close }; + } + + return null; + } + @compileError("Not implemented yet"); } @@ -278,7 +498,8 @@ const max_count = switch (builtin.os.tag) { else => std.math.maxInt(isize), }; -pub fn write(fd: os.fd_t, bytes: []const u8) Maybe(usize) { +pub fn write(fd_: bun.FileDescriptor, bytes: []const u8) Maybe(usize) { + const fd = bun.fdcast(fd_); const adjusted_len = @min(max_count, bytes.len); if (comptime Environment.isMac) { @@ -314,7 +535,8 @@ fn veclen(buffers: anytype) usize { return len; } -pub fn writev(fd: os.fd_t, buffers: []std.os.iovec) Maybe(usize) { +pub fn writev(fd_: bun.FileDescriptor, buffers: []std.os.iovec) Maybe(usize) { + const fd = bun.fdcast(fd_); if (comptime Environment.isMac) { const rc = writev_sym(fd, @as([*]std.os.iovec_const, @ptrCast(buffers.ptr)), @as(i32, @intCast(buffers.len))); if (comptime Environment.allow_assert) @@ -342,7 +564,8 @@ pub fn writev(fd: os.fd_t, buffers: []std.os.iovec) Maybe(usize) { } } -pub fn pwritev(fd: os.fd_t, buffers: []std.os.iovec, position: isize) Maybe(usize) { +pub fn pwritev(fd_: bun.FileDescriptor, buffers: []std.os.iovec, position: isize) Maybe(usize) { + const fd = bun.fdcast(fd_); if (comptime Environment.isMac) { const rc = pwritev_sym(fd, @as([*]std.os.iovec_const, @ptrCast(buffers.ptr)), @as(i32, @intCast(buffers.len)), position); if (comptime Environment.allow_assert) @@ -370,7 +593,8 @@ pub fn pwritev(fd: os.fd_t, buffers: []std.os.iovec, position: isize) Maybe(usiz } } -pub fn readv(fd: os.fd_t, buffers: []std.os.iovec) Maybe(usize) { +pub fn readv(fd_: bun.FileDescriptor, buffers: []std.os.iovec) Maybe(usize) { + const fd = bun.fdcast(fd_); if (comptime Environment.isMac) { const rc = readv_sym(fd, buffers.ptr, @as(i32, @intCast(buffers.len))); if (comptime Environment.allow_assert) @@ -398,7 +622,8 @@ pub fn readv(fd: os.fd_t, buffers: []std.os.iovec) Maybe(usize) { } } -pub fn preadv(fd: os.fd_t, buffers: []std.os.iovec, position: isize) Maybe(usize) { +pub fn preadv(fd_: bun.FileDescriptor, buffers: []std.os.iovec, position: isize) Maybe(usize) { + const fd = bun.fdcast(fd_); if (comptime Environment.isMac) { const rc = preadv_sym(fd, buffers.ptr, @as(i32, @intCast(buffers.len)), position); if (comptime Environment.allow_assert) @@ -463,8 +688,10 @@ else const fcntl_symbol = system.fcntl; -pub fn pread(fd: os.fd_t, buf: []u8, offset: i64) Maybe(usize) { +pub fn pread(fd_: bun.FileDescriptor, buf: []u8, offset: i64) Maybe(usize) { + const fd = bun.fdcast(fd_); const adjusted_len = @min(buf.len, max_count); + const ioffset = @as(i64, @bitCast(offset)); // the OS treats this as unsigned while (true) { const rc = pread_sym(fd, buf.ptr, adjusted_len, ioffset); @@ -482,7 +709,8 @@ const pwrite_sym = if (builtin.os.tag == .linux and builtin.link_libc) else sys.pwrite; -pub fn pwrite(fd: os.fd_t, bytes: []const u8, offset: i64) Maybe(usize) { +pub fn pwrite(fd_: bun.FileDescriptor, bytes: []const u8, offset: i64) Maybe(usize) { + const fd = bun.fdcast(fd_); const adjusted_len = @min(bytes.len, max_count); const ioffset = @as(i64, @bitCast(offset)); // the OS treats this as unsigned @@ -499,7 +727,8 @@ pub fn pwrite(fd: os.fd_t, bytes: []const u8, offset: i64) Maybe(usize) { unreachable; } -pub fn read(fd: os.fd_t, buf: []u8) Maybe(usize) { +pub fn read(fd_: bun.FileDescriptor, buf: []u8) Maybe(usize) { + const fd = bun.fdcast(fd_); const debug_timer = bun.Output.DebugTimer.start(); const adjusted_len = @min(buf.len, max_count); if (comptime Environment.isMac) { @@ -526,7 +755,8 @@ pub fn read(fd: os.fd_t, buf: []u8) Maybe(usize) { unreachable; } -pub fn recv(fd: os.fd_t, buf: []u8, flag: u32) Maybe(usize) { +pub fn recv(fd_: bun.FileDescriptor, buf: []u8, flag: u32) Maybe(usize) { + const fd = bun.fdcast(fd_); const adjusted_len = @min(buf.len, max_count); if (comptime Environment.isMac) { @@ -553,7 +783,8 @@ pub fn recv(fd: os.fd_t, buf: []u8, flag: u32) Maybe(usize) { unreachable; } -pub fn send(fd: os.fd_t, buf: []const u8, flag: u32) Maybe(usize) { +pub fn send(fd_: bun.FileDescriptor, buf: []const u8, flag: u32) Maybe(usize) { + const fd = bun.fdcast(fd_); if (comptime Environment.isMac) { const rc = system.@"sendto$NOCANCEL"(fd, buf.ptr, buf.len, flag, null, 0); if (Maybe(usize).errnoSys(rc, .send)) |err| { @@ -589,6 +820,13 @@ pub fn readlink(in: [:0]const u8, buf: []u8) Maybe(usize) { } pub fn ftruncate(fd: fd_t, size: isize) Maybe(void) { + if (comptime Environment.isWindows) { + if (kernel32.SetFileValidData(bun.fdcast(fd), size) == 0) { + return Maybe(void).errnoSys(0, .ftruncate) orelse Maybe(void).success; + } + + return Maybe(void).success; + } while (true) { if (Maybe(void).errnoSys(sys.ftruncate(fd, size), .ftruncate)) |err| { if (err.getErrno() == .INTR) continue; @@ -682,18 +920,17 @@ pub fn unlink(from: [:0]const u8) Maybe(void) { unreachable; } -pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) Maybe([]u8) { +pub fn getFdPath(fd_: bun.FileDescriptor, out_buffer: *[MAX_PATH_BYTES]u8) Maybe([]u8) { + const fd = bun.fdcast(fd_); switch (comptime builtin.os.tag) { .windows => { - const windows = std.os.windows; var wide_buf: [windows.PATH_MAX_WIDE]u16 = undefined; - const wide_slice = windows.GetFinalPathNameByHandle(fd, .{}, wide_buf[0..]) catch { - return Maybe([]u8){ .err = .{ .errno = .EBADF } }; + const wide_slice = std.os.windows.GetFinalPathNameByHandle(fd, .{}, wide_buf[0..]) catch { + return Maybe([]u8){ .err = .{ .errno = @intFromEnum(bun.C.SystemErrno.EBADF) } }; }; // Trust that Windows gives us valid UTF-16LE. - const end_index = std.unicode.utf16leToUtf8(out_buffer, wide_slice) catch unreachable; - return .{ .result = out_buffer[0..end_index] }; + return .{ .result = @constCast(bun.strings.fromWPath(out_buffer, wide_slice)) }; }, .macos, .ios, .watchos, .tvos => { // On macOS, we can use F.GETPATH fcntl command to query the OS for @@ -738,9 +975,10 @@ fn mmap( length: usize, prot: u32, flags: u32, - fd: os.fd_t, + fd_: bun.FileDescriptor, offset: u64, ) Maybe([]align(mem.page_size) u8) { + const fd = bun.fdcast(fd_); const ioffset = @as(i64, @bitCast(offset)); // the OS treats this as unsigned const rc = std.c.mmap(ptr, length, prot, flags, fd, ioffset); const fail = std.c.MAP.FAILED; @@ -793,9 +1031,10 @@ pub fn munmap(memory: []align(mem.page_size) const u8) Maybe(void) { } pub const Error = struct { + const E = bun.C.E; const max_errno_value = brk: { - const errno_values = std.enums.values(os.E); - var err = @intFromEnum(os.E.SUCCESS); + const errno_values = std.enums.values(E); + var err = @intFromEnum(E.SUCCESS); for (errno_values) |errn| { err = @max(err, @intFromEnum(errn)); } @@ -806,13 +1045,13 @@ pub const Error = struct { errno: Int, syscall: Syscall.Tag = @as(Syscall.Tag, @enumFromInt(0)), path: []const u8 = "", - fd: i32 = -1, + fd: bun.FileDescriptor = bun.invalid_fd, pub inline fn isRetry(this: *const Error) bool { return this.getErrno() == .AGAIN; } - pub fn fromCode(errno: os.E, syscall: Syscall.Tag) Error { + pub fn fromCode(errno: E, syscall: Syscall.Tag) Error { return .{ .errno = @as(Int, @truncate(@intFromEnum(errno))), .syscall = syscall }; } @@ -820,20 +1059,20 @@ pub const Error = struct { try self.toSystemError().format(fmt, opts, writer); } - pub const oom = fromCode(os.E.NOMEM, .read); + pub const oom = fromCode(E.NOMEM, .read); pub const retry = Error{ .errno = if (Environment.isLinux) - @as(Int, @intCast(@intFromEnum(os.E.AGAIN))) + @as(Int, @intCast(@intFromEnum(E.AGAIN))) else if (Environment.isMac) - @as(Int, @intCast(@intFromEnum(os.E.WOULDBLOCK))) + @as(Int, @intCast(@intFromEnum(E.WOULDBLOCK))) else - @as(Int, @intCast(@intFromEnum(os.E.INTR))), + @as(Int, @intCast(@intFromEnum(E.INTR))), .syscall = .retry, }; - pub inline fn getErrno(this: Error) os.E { - return @as(os.E, @enumFromInt(this.errno)); + pub inline fn getErrno(this: Error) E { + return @as(E, @enumFromInt(this.errno)); } pub inline fn withPath(this: Error, path: anytype) Error { @@ -848,7 +1087,7 @@ pub const Error = struct { return Error{ .errno = this.errno, .syscall = this.syscall, - .fd = @as(i32, @intCast(fd)), + .fd = @intCast(fd), }; } @@ -889,8 +1128,10 @@ pub const Error = struct { err.path = bun.String.create(this.path); } - if (this.fd != -1) { - err.fd = this.fd; + if (this.fd != bun.invalid_fd) { + if (this.fd <= std.math.maxInt(i32)) { + err.fd = @intCast(this.fd); + } } return err; @@ -905,7 +1146,8 @@ pub const Error = struct { } }; -pub fn setPipeCapacityOnLinux(fd: bun.FileDescriptor, capacity: usize) Maybe(usize) { +pub fn setPipeCapacityOnLinux(fd_: bun.FileDescriptor, capacity: usize) Maybe(usize) { + const fd = bun.fdcast(fd_); if (comptime !Environment.isLinux) @compileError("Linux-only"); std.debug.assert(capacity > 0); @@ -941,16 +1183,16 @@ pub fn getMaxPipeSizeOnLinux() usize { fn once() c_int { const strings = bun.strings; const default_out_size = 512 * 1024; - const pipe_max_size_fd = switch (JSC.Node.Syscall.open("/proc/sys/fs/pipe-max-size", std.os.O.RDONLY, 0)) { + const pipe_max_size_fd = switch (bun.sys.open("/proc/sys/fs/pipe-max-size", std.os.O.RDONLY, 0)) { .result => |fd2| fd2, .err => |err| { log("Failed to open /proc/sys/fs/pipe-max-size: {d}\n", .{err.errno}); return default_out_size; }, }; - defer _ = JSC.Node.Syscall.close(pipe_max_size_fd); + defer _ = bun.sys.close(pipe_max_size_fd); var max_pipe_size_buf: [128]u8 = undefined; - const max_pipe_size = switch (JSC.Node.Syscall.read(pipe_max_size_fd, max_pipe_size_buf[0..])) { + const max_pipe_size = switch (bun.sys.read(pipe_max_size_fd, max_pipe_size_buf[0..])) { .result => |bytes_read| std.fmt.parseInt(i64, strings.trim(max_pipe_size_buf[0..bytes_read], "\n"), 10) catch |err| { log("Failed to parse /proc/sys/fs/pipe-max-size: {any}\n", .{@errorName(err)}); return default_out_size; @@ -968,3 +1210,126 @@ pub fn getMaxPipeSizeOnLinux() usize { }.once, c_int)), ); } + +pub fn existsOSPath(path: bun.OSPathSlice) bool { + if (comptime Environment.isPosix) { + return system.access(path, 0) == 0; + } + + if (comptime Environment.isWindows) { + const rc = kernel32.GetFileAttributesW(path) != windows.INVALID_FILE_ATTRIBUTES; + if (rc == windows.FALSE) { + return false; + } + return true; + } + + @compileError("TODO: existsOSPath"); +} + +pub fn isExecutableFileOSPath(path: bun.OSPathSlice) bool { + if (comptime Environment.isPosix) { + return bun.is_executable_fileZ(path); + } + + if (comptime Environment.isWindows) { + var out: windows.DWORD = 8; + const rc = kernel32.GetBinaryTypeW(path, &out); + log("GetBinaryTypeW({}) = {d}", .{ bun.String.init(path), out }); + + if (rc == windows.FALSE) { + return false; + } + + return switch (out) { + kernel32.SCS_32BIT_BINARY, + kernel32.SCS_64BIT_BINARY, + kernel32.SCS_DOS_BINARY, + kernel32.SCS_OS216_BINARY, + kernel32.SCS_PIF_BINARY, + kernel32.SCS_POSIX_BINARY, + => true, + else => false, + }; + } + + @compileError("TODO: isExecutablePath"); +} + +pub fn isExecutableFilePath(path: anytype) bool { + const Type = @TypeOf(path); + if (comptime Environment.isPosix) { + switch (Type) { + *[*:0]const u8, *[*:0]u8, [*:0]const u8, [*:0]u8 => return bun.is_executable_fileZ(path), + [:0]const u8, [:0]u8 => return bun.is_executable_fileZ(path.ptr), + []const u8, []u8 => return bun.is_executable_fileZ(&(std.os.toPosixPath(path) catch return false)), + else => @compileError("TODO: isExecutableFilePath"), + } + } + + if (comptime Environment.isWindows) { + var buf: [(bun.MAX_PATH_BYTES / 2) + 1]u16 = undefined; + return isExecutableFileOSPath(bun.strings.toWPath(&buf, path)); + } + + @compileError("TODO: isExecutablePath"); +} + +pub fn setFileOffset(fd: bun.FileDescriptor, offset: usize) Maybe(void) { + if (comptime Environment.isLinux) { + return Maybe(void).errnoSysFd( + linux.lseek(@intCast(fd), @intCast(offset), os.SEEK.SET), + .lseek, + @as(bun.FileDescriptor, @intCast(fd)), + ) orelse Maybe(void).success; + } + + if (comptime Environment.isMac) { + return Maybe(void).errnoSysFd( + std.c.lseek(fd, @as(std.c.off_t, @intCast(offset)), os.SEEK.SET), + .lseek, + @as(bun.FileDescriptor, @intCast(fd)), + ) orelse Maybe(void).success; + } + + if (comptime Environment.isWindows) { + const offset_high: u64 = @as(u32, @intCast(offset >> 32)); + const offset_low: u64 = @as(u32, @intCast(offset & 0xFFFFFFFF)); + var plarge_integer: i64 = @bitCast(offset_high); + const rc = kernel32.SetFilePointerEx( + bun.fdcast(fd), + @as(windows.LARGE_INTEGER, @bitCast(offset_low)), + &plarge_integer, + windows.FILE_BEGIN, + ); + if (rc == windows.FALSE) { + return Maybe(void).errnoSys(0, .lseek) orelse Maybe(void).success; + } + return Maybe(void).success; + } +} + +pub fn dup(fd: bun.FileDescriptor) Maybe(bun.FileDescriptor) { + if (comptime Environment.isWindows) { + var target: *windows.HANDLE = undefined; + const process = kernel32.GetCurrentProcess(); + const out = kernel32.DuplicateHandle( + process, + bun.fdcast(fd), + process, + target, + 0, + w.TRUE, + w.DUPLICATE_SAME_ACCESS, + ); + if (out == 0) { + if (Maybe(bun.FileDescriptor).errnoSysFd(0, .dup, fd)) |err| { + return err; + } + } + return Maybe(bun.FileDescriptor){ .result = bun.toFD(out) }; + } + + const out = std.c.dup(fd); + return Maybe(bun.FileDescriptor).errnoSysFd(out, .dup, fd) orelse Maybe(bun.FileDescriptor){ .result = bun.toFD(out) }; +} diff --git a/src/bun.js/node/types.zig b/src/bun.js/node/types.zig index 6c4ee9f51..51094d629 100644 --- a/src/bun.js/node/types.zig +++ b/src/bun.js/node/types.zig @@ -20,7 +20,7 @@ const is_bindgen: bool = std.meta.globalOption("bindgen", bool) orelse false; const meta = bun.meta; /// Time in seconds. Not nanos! pub const TimeLike = c_int; -pub const Mode = if (Environment.isLinux) u32 else std.os.mode_t; +pub const Mode = bun.C.Mode; const heap_allocator = bun.default_allocator; pub fn DeclEnum(comptime T: type) type { const fieldInfos = std.meta.declarations(T); @@ -83,6 +83,12 @@ pub fn Maybe(comptime ResultType: type) type { pub const todo: @This() = @This(){ .err = Syscall.Error.todo }; + pub fn throw(this: @This()) !void { + if (this == .err) { + return bun.AsyncIO.asError(this.err.errno); + } + } + pub fn toJS(this: @This(), globalThis: *JSC.JSGlobalObject) JSC.JSValue { switch (this) { .err => |e| { @@ -171,7 +177,7 @@ pub fn Maybe(comptime ResultType: type) type { .err = .{ .errno = @as(Syscall.Error.Int, @truncate(@intFromEnum(err))), .syscall = syscall, - .fd = @as(i32, @intCast(fd)), + .fd = @intCast(bun.toFD(fd)), }, }, }; @@ -687,6 +693,18 @@ pub const PathLike = union(Tag) { return sliceZWithForceCopy(this, buf, false); } + pub inline fn sliceW(this: PathLike, buf: *[bun.MAX_PATH_BYTES]u8) [:0]const u16 { + return bun.strings.toWPath(@alignCast(std.mem.bytesAsSlice(u16, buf)), this.slice()); + } + + pub inline fn osPath(this: PathLike, buf: *[bun.MAX_PATH_BYTES]u8) bun.OSPathSlice { + if (comptime Environment.isWindows) { + return sliceW(this, buf); + } + + return sliceZWithForceCopy(this, buf, false); + } + pub inline fn sliceZAssume( this: PathLike, ) [:0]const u8 { @@ -772,7 +790,7 @@ pub const PathLike = union(Tag) { }; pub const Valid = struct { - pub fn fileDescriptor(fd: bun.FileDescriptor, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) bool { + pub fn fileDescriptor(fd: i64, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) bool { if (fd < 0) { JSC.throwInvalidArguments("Invalid file descriptor, must not be negative number", .{}, ctx, exception); return false; @@ -985,12 +1003,12 @@ pub const ArgumentsSlice = struct { pub fn fileDescriptorFromJS(ctx: JSC.C.JSContextRef, value: JSC.JSValue, exception: JSC.C.ExceptionRef) ?bun.FileDescriptor { if (!value.isNumber() or value.isBigInt()) return null; - const fd = value.toInt32(); + const fd = value.toInt64(); if (!Valid.fileDescriptor(fd, ctx, exception)) { return null; } - return @as(bun.FileDescriptor, @truncate(fd)); + return @as(bun.FileDescriptor, @intCast(fd)); } // Node.js docs: @@ -1427,26 +1445,46 @@ pub fn StatType(comptime Big: bool) type { } pub fn isBlockDevice(this: *This) JSC.JSValue { + if (comptime Environment.isWindows) { + JSC.VirtualMachine.get().global.throwTODO(comptime @src().fn_name ++ " is not implemented yet"); + return .zero; + } return JSC.JSValue.jsBoolean(os.S.ISBLK(@as(Mode, @intCast(this.modeInternal())))); } pub fn isCharacterDevice(this: *This) JSC.JSValue { + if (comptime Environment.isWindows) { + JSC.VirtualMachine.get().global.throwTODO(comptime @src().fn_name ++ " is not implemented yet"); + return .zero; + } return JSC.JSValue.jsBoolean(os.S.ISCHR(@as(Mode, @intCast(this.modeInternal())))); } pub fn isDirectory(this: *This) JSC.JSValue { + if (comptime Environment.isWindows) { + JSC.VirtualMachine.get().global.throwTODO(comptime @src().fn_name ++ " is not implemented yet"); + return .zero; + } return JSC.JSValue.jsBoolean(os.S.ISDIR(@as(Mode, @intCast(this.modeInternal())))); } pub fn isFIFO(this: *This) JSC.JSValue { + if (comptime Environment.isWindows) { + JSC.VirtualMachine.get().global.throwTODO(comptime @src().fn_name ++ " is not implemented yet"); + return .zero; + } return JSC.JSValue.jsBoolean(os.S.ISFIFO(@as(Mode, @intCast(this.modeInternal())))); } pub fn isFile(this: *This) JSC.JSValue { - return JSC.JSValue.jsBoolean(os.S.ISREG(@as(Mode, @intCast(this.modeInternal())))); + return JSC.JSValue.jsBoolean(bun.isRegularFile(@as(Mode, @intCast(this.modeInternal())))); } pub fn isSocket(this: *This) JSC.JSValue { + if (comptime Environment.isWindows) { + JSC.VirtualMachine.get().global.throwTODO(comptime @src().fn_name ++ " is not implemented yet"); + return .zero; + } return JSC.JSValue.jsBoolean(os.S.ISSOCK(@as(Mode, @intCast(this.modeInternal())))); } @@ -1456,6 +1494,10 @@ pub fn StatType(comptime Big: bool) type { /// /// See https://nodejs.org/api/fs.html#statsissymboliclink pub fn isSymbolicLink(this: *This) JSC.JSValue { + if (comptime Environment.isWindows) { + JSC.VirtualMachine.get().global.throwTODO(comptime @src().fn_name ++ " is not implemented yet"); + return .zero; + } return JSC.JSValue.jsBoolean(os.S.ISLNK(@as(Mode, @intCast(this.modeInternal())))); } @@ -1465,7 +1507,7 @@ pub fn StatType(comptime Big: bool) type { bun.default_allocator.destroy(this); } - pub fn init(stat_: os.Stat) This { + pub fn init(stat_: bun.Stat) This { const aTime = stat_.atime(); const mTime = stat_.mtime(); const cTime = stat_.ctime(); @@ -1495,7 +1537,7 @@ pub fn StatType(comptime Big: bool) type { }; } - pub fn initWithAllocator(allocator: std.mem.Allocator, stat: std.os.Stat) *This { + pub fn initWithAllocator(allocator: std.mem.Allocator, stat: bun.Stat) *This { var this = allocator.create(This) catch unreachable; this.* = init(stat); return this; @@ -1558,7 +1600,7 @@ pub const Stats = union(enum) { big: StatsBig, small: StatsSmall, - pub inline fn init(stat_: os.Stat, big: bool) Stats { + pub inline fn init(stat_: bun.Stat, big: bool) Stats { if (big) { return .{ .big = StatsBig.init(stat_) }; } else { @@ -2285,7 +2327,7 @@ pub const Path = struct { pub const Process = struct { pub fn getArgv0(globalObject: *JSC.JSGlobalObject) callconv(.C) JSC.JSValue { - return JSC.ZigString.fromUTF8(bun.span(std.os.argv[0])).toValueGC(globalObject); + return JSC.ZigString.fromUTF8(bun.span(bun.argv()[0])).toValueGC(globalObject); } pub fn getExecPath(globalObject: *JSC.JSGlobalObject) callconv(.C) JSC.JSValue { @@ -2305,13 +2347,13 @@ pub const Process = struct { JSC.ZigString, // argv omits "bun" because it could be "bun run" or "bun" and it's kind of ambiguous // argv also omits the script name - std.os.argv.len -| 1, + bun.argv().len -| 1, ) catch unreachable; defer allocator.free(args); var used: usize = 0; const offset: usize = 1; - for (std.os.argv[@min(std.os.argv.len, offset)..]) |arg_| { + for (bun.argv()[@min(bun.argv().len, offset)..]) |arg_| { const arg = bun.span(arg_); if (arg.len == 0) continue; diff --git a/src/bun.js/rare_data.zig b/src/bun.js/rare_data.zig index ab9cc9ea4..30adeabe3 100644 --- a/src/bun.js/rare_data.zig +++ b/src/bun.js/rare_data.zig @@ -225,7 +225,7 @@ pub fn stderr(rare: *RareData) *Blob.Store { return rare.stderr_store orelse brk: { var store = default_allocator.create(Blob.Store) catch unreachable; var mode: JSC.Node.Mode = 0; - switch (Syscall.fstat(std.os.STDERR_FILENO)) { + switch (Syscall.fstat(bun.STDERR_FD)) { .result => |stat| { mode = stat.mode; }, @@ -238,7 +238,7 @@ pub fn stderr(rare: *RareData) *Blob.Store { .data = .{ .file = Blob.FileStore{ .pathlike = .{ - .fd = std.os.STDERR_FILENO, + .fd = bun.STDERR_FD, }, .is_atty = Output.stderr_descriptor_type == .terminal, .mode = mode, @@ -255,7 +255,7 @@ pub fn stdout(rare: *RareData) *Blob.Store { return rare.stdout_store orelse brk: { var store = default_allocator.create(Blob.Store) catch unreachable; var mode: JSC.Node.Mode = 0; - switch (Syscall.fstat(std.os.STDOUT_FILENO)) { + switch (Syscall.fstat(bun.STDOUT_FD)) { .result => |stat| { mode = stat.mode; }, @@ -267,7 +267,7 @@ pub fn stdout(rare: *RareData) *Blob.Store { .data = .{ .file = Blob.FileStore{ .pathlike = .{ - .fd = std.os.STDOUT_FILENO, + .fd = bun.STDOUT_FD, }, .is_atty = Output.stdout_descriptor_type == .terminal, .mode = mode, @@ -283,7 +283,7 @@ pub fn stdin(rare: *RareData) *Blob.Store { return rare.stdin_store orelse brk: { var store = default_allocator.create(Blob.Store) catch unreachable; var mode: JSC.Node.Mode = 0; - switch (Syscall.fstat(std.os.STDIN_FILENO)) { + switch (Syscall.fstat(bun.STDIN_FD)) { .result => |stat| { mode = stat.mode; }, @@ -295,9 +295,9 @@ pub fn stdin(rare: *RareData) *Blob.Store { .data = .{ .file = Blob.FileStore{ .pathlike = .{ - .fd = std.os.STDIN_FILENO, + .fd = bun.STDIN_FD, }, - .is_atty = std.os.isatty(std.os.STDIN_FILENO), + .is_atty = std.os.isatty(bun.fdcast(bun.STDIN_FD)), .mode = mode, }, }, diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig index 77cd79d21..e52c9f0e2 100644 --- a/src/bun.js/test/jest.zig +++ b/src/bun.js/test/jest.zig @@ -3,8 +3,7 @@ const bun = @import("root").bun; const js_parser = bun.js_parser; const js_ast = bun.JSAst; const Api = @import("../../api/schema.zig").Api; -const RequestContext = @import("../../http.zig").RequestContext; -const MimeType = @import("../../http.zig").MimeType; +const MimeType = @import("../../bun_dev_http_server.zig").MimeType; const ZigURL = @import("../../url.zig").URL; const HTTPClient = @import("root").bun.HTTP; const NetworkThread = HTTPClient.NetworkThread; diff --git a/src/bun.js/test/snapshot.zig b/src/bun.js/test/snapshot.zig index 12c7b3c36..072194b11 100644 --- a/src/bun.js/test/snapshot.zig +++ b/src/bun.js/test/snapshot.zig @@ -227,11 +227,11 @@ pub const Snapshots = struct { if (this.snapshot_dir_path == null or !strings.eqlLong(dir_path, this.snapshot_dir_path.?, true)) { remain[0] = 0; const snapshot_dir_path = snapshot_file_path_buf[0 .. snapshot_file_path_buf.len - remain.len :0]; - switch (JSC.Node.Syscall.mkdir(snapshot_dir_path, 0o777)) { + switch (bun.sys.mkdir(snapshot_dir_path, 0o777)) { .result => this.snapshot_dir_path = dir_path, .err => |err| { switch (err.getErrno()) { - std.os.E.EXIST => this.snapshot_dir_path = dir_path, + .EXIST => this.snapshot_dir_path = dir_path, else => return JSC.Maybe(void){ .err = err, }, @@ -249,7 +249,7 @@ pub const Snapshots = struct { var flags: JSC.Node.Mode = std.os.O.CREAT | std.os.O.RDWR; if (this.update_snapshots) flags |= std.os.O.TRUNC; - const fd = switch (JSC.Node.Syscall.open(snapshot_file_path, flags, 0o644)) { + const fd = switch (bun.sys.open(snapshot_file_path, flags, 0o644)) { .result => |_fd| _fd, .err => |err| return JSC.Maybe(void){ .err = err, @@ -258,7 +258,7 @@ pub const Snapshots = struct { var file: File = .{ .id = file_id, - .file = .{ .handle = fd }, + .file = .{ .handle = bun.fdcast(fd) }, }; if (this.update_snapshots) { diff --git a/src/bun.js/webcore/blob.zig b/src/bun.js/webcore/blob.zig index c8d842a21..f30a4a3d3 100644 --- a/src/bun.js/webcore/blob.zig +++ b/src/bun.js/webcore/blob.zig @@ -1,8 +1,7 @@ const std = @import("std"); const Api = @import("../../api/schema.zig").Api; const bun = @import("root").bun; -const RequestContext = @import("../../http.zig").RequestContext; -const MimeType = @import("../../http.zig").MimeType; +const MimeType = @import("../../bun_dev_http_server.zig").MimeType; const ZigURL = @import("../../url.zig").URL; const HTTPClient = @import("root").bun.HTTP; const NetworkThread = HTTPClient.NetworkThread; @@ -331,7 +330,7 @@ pub const Blob = struct { switch (pathlike_tag) { .fd => { - const fd = @as(i32, @intCast(try reader.readIntNative(u32))); + const fd = @as(bun.FileDescriptor, @intCast(try reader.readIntNative(bun.FileDescriptor))); var blob = try allocator.create(Blob); blob.* = Blob.findOrCreateFileFromPath( @@ -1021,7 +1020,7 @@ pub const Blob = struct { ) JSC.JSValue { const fd: bun.FileDescriptor = if (comptime !needs_open) pathlike.fd else brk: { var file_path: [bun.MAX_PATH_BYTES]u8 = undefined; - switch (JSC.Node.Syscall.open( + switch (bun.sys.open( pathlike.path.sliceZ(&file_path), // we deliberately don't use O_TRUNC here // it's a perf optimization @@ -1046,11 +1045,11 @@ pub const Blob = struct { // we only truncate if it's a path // if it's a file descriptor, we assume they want manual control over that behavior if (truncate) { - _ = JSC.Node.Syscall.system.ftruncate(fd, @as(i64, @intCast(written))); + _ = bun.sys.ftruncate(fd, @as(i64, @intCast(written))); } if (needs_open) { - _ = JSC.Node.Syscall.close(fd); + _ = bun.sys.close(fd); } } if (!str.isEmpty()) { @@ -1059,7 +1058,7 @@ pub const Blob = struct { var remain = decoded.slice(); while (remain.len > 0) { - const result = JSC.Node.Syscall.write(fd, remain); + const result = bun.sys.write(fd, remain); switch (result) { .result => |res| { written += res; @@ -1091,7 +1090,7 @@ pub const Blob = struct { ) JSC.JSValue { const fd: bun.FileDescriptor = if (comptime !needs_open) pathlike.fd else brk: { var file_path: [bun.MAX_PATH_BYTES]u8 = undefined; - switch (JSC.Node.Syscall.open( + switch (bun.sys.open( pathlike.path.sliceZ(&file_path), // we deliberately don't use O_TRUNC here // it's a perf optimization @@ -1112,11 +1111,11 @@ pub const Blob = struct { var written: usize = 0; defer { if (truncate) { - _ = JSC.Node.Syscall.system.ftruncate(fd, @as(i64, @intCast(written))); + _ = bun.sys.ftruncate(fd, @as(i64, @intCast(written))); } if (needs_open) { - _ = JSC.Node.Syscall.close(fd); + _ = bun.sys.close(fd); } } @@ -1124,7 +1123,7 @@ pub const Blob = struct { const end = remain.ptr + remain.len; while (remain.ptr != end) { - const result = JSC.Node.Syscall.write(fd, remain); + const result = bun.sys.write(fd, remain); switch (result) { .result => |res| { written += res; @@ -1321,16 +1320,16 @@ pub const Blob = struct { }; }, .fd => { - switch (path_.fd) { - std.os.STDIN_FILENO => return Blob.initWithStore( + switch (bun.FDTag.get(path_.fd)) { + .stdin => return Blob.initWithStore( vm.rareData().stdin(), globalThis, ), - std.os.STDERR_FILENO => return Blob.initWithStore( + .stderr => return Blob.initWithStore( vm.rareData().stderr(), globalThis, ), - std.os.STDOUT_FILENO => return Blob.initWithStore( + .stdout => return Blob.initWithStore( vm.rareData().stdout(), globalThis, ), @@ -1509,7 +1508,7 @@ pub const Blob = struct { var path = path_string.sliceZ(&buf); - this.opened_fd = switch (JSC.Node.Syscall.open(path, open_flags_, JSC.Node.default_permission)) { + this.opened_fd = switch (bun.sys.open(path, open_flags_, JSC.Node.default_permission)) { .result => |fd| fd, .err => |err| { this.errno = AsyncIO.asError(err.errno); @@ -1563,23 +1562,45 @@ pub const Blob = struct { var path_buffer = completion.operation.open.path; defer bun.default_allocator.free(bun.span(path_buffer)); defer bun.default_allocator.destroy(state); - this.opened_fd = result catch { - this.errno = AsyncIO.asError(-completion.result); - // do not use path_buffer here because it is a temporary - var path_string = if (@hasField(This, "file_store")) - this.file_store.pathlike.path - else - this.file_blob.store.?.data.file.pathlike.path; - - this.system_error = (JSC.Node.Syscall.Error{ - .errno = @as(JSC.Node.Syscall.Error.Int, @intCast(-completion.result)), - .path = path_string.slice(), - .syscall = .open, - }).toSystemError(); - - callback(this, null_fd); - return; - }; + if (comptime Environment.isPosix) { + this.opened_fd = result catch { + this.errno = AsyncIO.asError(-completion.result); + // do not use path_buffer here because it is a temporary + var path_string = if (@hasField(This, "file_store")) + this.file_store.pathlike.path + else + this.file_blob.store.?.data.file.pathlike.path; + + this.system_error = (bun.sys.Error{ + .errno = @as(bun.sys.Error.Int, @intCast(-completion.result)), + .path = path_string.slice(), + .syscall = .open, + }).toSystemError(); + + callback(this, null_fd); + return; + }; + } else if (comptime Environment.isWindows) { + this.opened_fd = result catch |err| { + this.errno = err; + // do not use path_buffer here because it is a temporary + var path_string = if (@hasField(This, "file_store")) + this.file_store.pathlike.path + else + this.file_blob.store.?.data.file.pathlike.path; + + this.system_error = (bun.sys.Error{ + .errno = @as(bun.sys.Error.Int, @intFromEnum(bun.C.SystemErrno.fromError(err).?)), + .path = path_string.slice(), + .syscall = .open, + }).toSystemError(); + + callback(this, null_fd); + return; + }; + } else { + @compileError("Unsupported platform"); + } callback(this, this.opened_fd); } @@ -1771,8 +1792,8 @@ pub const Blob = struct { this.read_len = @as(SizeType, @truncate(result catch |err| { if (@hasField(HTTPClient.NetworkThread.Completion, "result")) { this.errno = AsyncIO.asError(-completion.result); - this.system_error = (JSC.Node.Syscall.Error{ - .errno = @as(JSC.Node.Syscall.Error.Int, @intCast(-completion.result)), + this.system_error = (bun.sys.Error{ + .errno = @as(bun.sys.Error.Int, @intCast(-completion.result)), .syscall = .read, }).toSystemError(); } else { @@ -1821,7 +1842,12 @@ pub const Blob = struct { } fn resolveSizeAndLastModified(this: *ReadFile, fd: bun.FileDescriptor) void { - const stat: std.os.Stat = switch (JSC.Node.Syscall.fstat(fd)) { + if (comptime Environment.isWindows) { + bun.todo(@src(), {}); + return; + } + + const stat: bun.Stat = switch (bun.sys.fstat(fd)) { .result => |result| result, .err => |err| { this.errno = AsyncIO.asError(err.errno); @@ -1850,14 +1876,14 @@ pub const Blob = struct { return; } - if (stat.size > 0 and std.os.S.ISREG(stat.mode)) { + if (stat.size > 0 and bun.isRegularFile(stat.mode)) { this.size = @min( @as(SizeType, @truncate(@as(SizeType, @intCast(@max(@as(i64, @intCast(stat.size)), 0))))), this.max_length, ); // read up to 4k at a time if // they didn't explicitly set a size and we're reading from something that's not a regular file - } else if (stat.size == 0 and !std.os.S.ISREG(stat.mode)) { + } else if (stat.size == 0 and !bun.isRegularFile(stat.mode)) { this.size = if (this.max_length == Blob.max_size) 4096 else @@ -2206,14 +2232,14 @@ pub const Blob = struct { pub fn doCloseFile(this: *CopyFile, comptime which: IOWhich) void { switch (which) { .both => { - _ = JSC.Node.Syscall.close(this.destination_fd); - _ = JSC.Node.Syscall.close(this.source_fd); + _ = bun.sys.close(this.destination_fd); + _ = bun.sys.close(this.source_fd); }, .destination => { - _ = JSC.Node.Syscall.close(this.destination_fd); + _ = bun.sys.close(this.destination_fd); }, .source => { - _ = JSC.Node.Syscall.close(this.source_fd); + _ = bun.sys.close(this.source_fd); }, } } @@ -2226,7 +2252,7 @@ pub const Blob = struct { // open source file first // if it fails, we don't want the extra destination file hanging out if (which == .both or which == .source) { - this.source_fd = switch (JSC.Node.Syscall.open( + this.source_fd = switch (bun.sys.open( this.source_file_store.pathlike.path.sliceZAssume(), open_source_flags, 0, @@ -2240,7 +2266,7 @@ pub const Blob = struct { } if (which == .both or which == .destination) { - this.destination_fd = switch (JSC.Node.Syscall.open( + this.destination_fd = switch (bun.sys.open( this.destination_file_store.pathlike.path.sliceZAssume(), open_destination_flags, JSC.Node.default_permission, @@ -2248,7 +2274,7 @@ pub const Blob = struct { .result => |result| result, .err => |errno| { if (which == .both) { - _ = JSC.Node.Syscall.close(this.source_fd); + _ = bun.sys.close(this.source_fd); this.source_fd = 0; } @@ -2264,7 +2290,7 @@ pub const Blob = struct { copy_file_range, splice, - pub const tag = std.EnumMap(TryWith, JSC.Node.Syscall.Tag).init(.{ + pub const tag = std.EnumMap(TryWith, bun.sys.Tag).init(.{ .sendfile = .sendfile, .copy_file_range = .copy_file_range, .splice = .splice, @@ -2366,15 +2392,15 @@ pub const Blob = struct { } } - this.system_error = (JSC.Node.Syscall.Error{ - .errno = @as(JSC.Node.Syscall.Error.Int, @intCast(@intFromEnum(linux.E.INVAL))), + this.system_error = (bun.sys.Error{ + .errno = @as(bun.sys.Error.Int, @intCast(@intFromEnum(linux.E.INVAL))), .syscall = TryWith.tag.get(use).?, }).toSystemError(); return AsyncIO.asError(linux.E.INVAL); }, else => |errno| { - this.system_error = (JSC.Node.Syscall.Error{ - .errno = @as(JSC.Node.Syscall.Error.Int, @intCast(@intFromEnum(errno))), + this.system_error = (bun.sys.Error{ + .errno = @as(bun.sys.Error.Int, @intCast(@intFromEnum(errno))), .syscall = TryWith.tag.get(use).?, }).toSystemError(); return AsyncIO.asError(errno); @@ -2389,7 +2415,7 @@ pub const Blob = struct { } pub fn doFCopyFile(this: *CopyFile) anyerror!void { - switch (JSC.Node.Syscall.fcopyfile(this.source_fd, this.destination_fd, os.system.COPYFILE_DATA)) { + switch (bun.sys.fcopyfile(this.source_fd, this.destination_fd, os.system.COPYFILE_DATA)) { .err => |errno| { this.system_error = errno.toSystemError(); @@ -2403,7 +2429,7 @@ pub const Blob = struct { var source_buf: [bun.MAX_PATH_BYTES]u8 = undefined; var dest_buf: [bun.MAX_PATH_BYTES]u8 = undefined; - switch (JSC.Node.Syscall.clonefile( + switch (bun.sys.clonefile( this.source_file_store.pathlike.path.sliceZ(&source_buf), this.destination_file_store.pathlike.path.sliceZ( &dest_buf, @@ -2420,7 +2446,7 @@ pub const Blob = struct { pub fn runAsync(this: *CopyFile) void { // defer task.onFinish(); - var stat_: ?std.os.Stat = null; + var stat_: ?bun.Stat = null; if (this.destination_file_store.pathlike == .fd) { this.destination_fd = this.destination_file_store.pathlike.fd; @@ -2430,6 +2456,15 @@ pub const Blob = struct { this.source_fd = this.source_file_store.pathlike.fd; } + if (comptime Environment.isWindows) { + this.system_error = SystemError{ + .code = bun.String.static("TODO"), + .syscall = bun.String.static("CopyFileEx"), + .message = bun.String.static("Not implemented on Windows yet"), + }; + return; + } + // Do we need to open both files? if (this.destination_fd == null_fd and this.source_fd == null_fd) { @@ -2441,7 +2476,7 @@ pub const Blob = struct { // stat the output file, make sure it: // 1. Exists - switch (JSC.Node.Syscall.stat(this.source_file_store.pathlike.path.sliceZAssume())) { + switch (bun.sys.stat(this.source_file_store.pathlike.path.sliceZAssume())) { .result => |result| { stat_ = result; @@ -2506,7 +2541,7 @@ pub const Blob = struct { if (this.destination_file_store.pathlike == .fd) {} - const stat: std.os.Stat = stat_ orelse switch (JSC.Node.Syscall.fstat(this.source_fd)) { + const stat: bun.Stat = stat_ orelse switch (bun.sys.fstat(this.source_fd)) { .result => |result| result, .err => |err| { this.doClose(); @@ -2612,7 +2647,7 @@ pub const Blob = struct { } if (this.mode != 0) { - return std.os.S.ISREG(this.mode); + return bun.isRegularFile(this.mode); } return null; @@ -2787,9 +2822,14 @@ pub const Blob = struct { return JSValue.jsBoolean(true); } + if (comptime Environment.isWindows) { + this.globalThis.throwTODO("exists is not implemented on Windows"); + return JSValue.jsUndefined(); + } + // We say regular files and pipes exist. // This is mostly meant for "Can we use this in new Response(file)?" - return JSValue.jsBoolean(std.os.S.ISREG(store.data.file.mode) or std.os.S.ISFIFO(store.data.file.mode)); + return JSValue.jsBoolean(bun.isRegularFile(store.data.file.mode) or std.os.S.ISFIFO(store.data.file.mode)); } // This mostly means 'can it be read?' @@ -3150,30 +3190,35 @@ pub const Blob = struct { /// resolve file stat like size, last_modified fn resolveFileStat(store: *Store) void { + if (comptime Environment.isWindows) { + bun.todo(@src(), {}); + return; + } + if (store.data.file.pathlike == .path) { var buffer: [bun.MAX_PATH_BYTES]u8 = undefined; - switch (JSC.Node.Syscall.stat(store.data.file.pathlike.path.sliceZ(&buffer))) { + switch (bun.sys.stat(store.data.file.pathlike.path.sliceZ(&buffer))) { .result => |stat| { - store.data.file.max_size = if (std.os.S.ISREG(stat.mode) or stat.size > 0) + store.data.file.max_size = if (bun.isRegularFile(stat.mode) or stat.size > 0) @as(SizeType, @truncate(@as(u64, @intCast(@max(stat.size, 0))))) else Blob.max_size; store.data.file.mode = stat.mode; - store.data.file.seekable = std.os.S.ISREG(stat.mode); + store.data.file.seekable = bun.isRegularFile(stat.mode); store.data.file.last_modified = toJSTime(stat.mtime().tv_sec, stat.mtime().tv_nsec); }, // the file may not exist yet. Thats's okay. else => {}, } } else if (store.data.file.pathlike == .fd) { - switch (JSC.Node.Syscall.fstat(store.data.file.pathlike.fd)) { + switch (bun.sys.fstat(store.data.file.pathlike.fd)) { .result => |stat| { - store.data.file.max_size = if (std.os.S.ISREG(stat.mode) or stat.size > 0) + store.data.file.max_size = if (bun.isRegularFile(stat.mode) or stat.size > 0) @as(SizeType, @truncate(@as(u64, @intCast(@max(stat.size, 0))))) else Blob.max_size; store.data.file.mode = stat.mode; - store.data.file.seekable = std.os.S.ISREG(stat.mode); + store.data.file.seekable = bun.isRegularFile(stat.mode); store.data.file.last_modified = toJSTime(stat.mtime().tv_sec, stat.mtime().tv_nsec); }, // the file may not exist yet. Thats's okay. diff --git a/src/bun.js/webcore/body.zig b/src/bun.js/webcore/body.zig index 2cf4de874..1519ef148 100644 --- a/src/bun.js/webcore/body.zig +++ b/src/bun.js/webcore/body.zig @@ -1,8 +1,7 @@ const std = @import("std"); const Api = @import("../../api/schema.zig").Api; const bun = @import("root").bun; -const RequestContext = @import("../../http.zig").RequestContext; -const MimeType = @import("../../http.zig").MimeType; +const MimeType = @import("../../bun_dev_http_server.zig").MimeType; const ZigURL = @import("../../url.zig").URL; const HTTPClient = @import("root").bun.HTTP; const NetworkThread = HTTPClient.NetworkThread; diff --git a/src/bun.js/webcore/encoding.zig b/src/bun.js/webcore/encoding.zig index 890dad7bd..6f31fef82 100644 --- a/src/bun.js/webcore/encoding.zig +++ b/src/bun.js/webcore/encoding.zig @@ -1,7 +1,6 @@ const std = @import("std"); const Api = @import("../../api/schema.zig").Api; -const RequestContext = @import("../../http.zig").RequestContext; -const MimeType = @import("../../http.zig").MimeType; +const MimeType = @import("../../bun_dev_http_server.zig").MimeType; const ZigURL = @import("../../url.zig").URL; const HTTPClient = @import("root").bun.HTTP; const NetworkThread = HTTPClient.NetworkThread; diff --git a/src/bun.js/webcore/request.zig b/src/bun.js/webcore/request.zig index aaa3f6b79..fc38e1825 100644 --- a/src/bun.js/webcore/request.zig +++ b/src/bun.js/webcore/request.zig @@ -1,8 +1,8 @@ const std = @import("std"); const Api = @import("../../api/schema.zig").Api; const bun = @import("root").bun; -const RequestContext = @import("../../http.zig").RequestContext; -const MimeType = @import("../../http.zig").MimeType; +const RequestContext = @import("../../bun_dev_http_server.zig").RequestContext; +const MimeType = @import("../../bun_dev_http_server.zig").MimeType; const ZigURL = @import("../../url.zig").URL; const HTTPClient = @import("root").bun.HTTP; const NetworkThread = HTTPClient.NetworkThread; @@ -176,6 +176,7 @@ pub const Request = struct { } pub fn fromRequestContext(ctx: *RequestContext) !Request { + if (comptime Environment.isWindows) unreachable; var req = Request{ .url = bun.String.create(ctx.full_url), .body = try InitRequestBodyValue(.{ .Null = {} }), diff --git a/src/bun.js/webcore/response.zig b/src/bun.js/webcore/response.zig index df92dff15..2164062a1 100644 --- a/src/bun.js/webcore/response.zig +++ b/src/bun.js/webcore/response.zig @@ -1,8 +1,8 @@ const std = @import("std"); const Api = @import("../../api/schema.zig").Api; const bun = @import("root").bun; -const RequestContext = @import("../../http.zig").RequestContext; -const MimeType = @import("../../http.zig").MimeType; +const RequestContext = @import("../../bun_dev_http_server.zig").RequestContext; +const MimeType = @import("../../bun_dev_http_server.zig").MimeType; const ZigURL = @import("../../url.zig").URL; const HTTPClient = @import("root").bun.HTTP; const FetchRedirect = HTTPClient.FetchRedirect; @@ -293,10 +293,13 @@ pub const Response = struct { } pub fn mimeType(response: *const Response, request_ctx_: ?*const RequestContext) string { + if (comptime Environment.isWindows) unreachable; return mimeTypeWithDefault(response, MimeType.other, request_ctx_); } pub fn mimeTypeWithDefault(response: *const Response, default: MimeType, request_ctx_: ?*const RequestContext) string { + if (comptime Environment.isWindows) unreachable; + if (response.header(.ContentType)) |content_type| { return content_type; } @@ -679,7 +682,7 @@ pub const Fetch = struct { .AnyBlob => this.AnyBlob.detach(), .Sendfile => { if (@max(this.Sendfile.offset, this.Sendfile.remain) > 0) - _ = JSC.Node.Syscall.close(this.Sendfile.fd); + _ = bun.sys.close(this.Sendfile.fd); this.Sendfile.offset = 0; this.Sendfile.remain = 0; }, @@ -1750,8 +1753,8 @@ pub const Fetch = struct { if (body.needsToReadFile()) { prepare_body: { const opened_fd_res: JSC.Node.Maybe(bun.FileDescriptor) = switch (body.Blob.store.?.data.file.pathlike) { - .fd => |fd| JSC.Node.Maybe(bun.FileDescriptor).errnoSysFd(JSC.Node.Syscall.system.dup(fd), .open, fd) orelse .{ .result = fd }, - .path => |path| JSC.Node.Syscall.open(path.sliceZ(&globalThis.bunVM().nodeFS().sync_error_buf), std.os.O.RDONLY | std.os.O.NOCTTY, 0), + .fd => |fd| bun.sys.dup(fd), + .path => |path| bun.sys.open(path.sliceZ(&globalThis.bunVM().nodeFS().sync_error_buf), std.os.O.RDONLY | std.os.O.NOCTTY, 0), }; const opened_fd = switch (opened_fd_res) { @@ -1772,7 +1775,7 @@ pub const Fetch = struct { if (proxy == null and bun.HTTP.Sendfile.isEligible(url)) { use_sendfile: { - const stat: std.os.Stat = switch (JSC.Node.Syscall.fstat(opened_fd)) { + const stat: bun.Stat = switch (bun.sys.fstat(opened_fd)) { .result => |result| result, // bail out for any reason .err => break :use_sendfile, @@ -1780,7 +1783,7 @@ pub const Fetch = struct { if (Environment.isMac) { // macOS only supports regular files for sendfile() - if (!std.os.S.ISREG(stat.mode)) { + if (!bun.isRegularFile(stat.mode)) { break :use_sendfile; } } @@ -1792,7 +1795,7 @@ pub const Fetch = struct { const original_size = body.Blob.size; const stat_size = @as(Blob.SizeType, @intCast(stat.size)); - const blob_size = if (std.os.S.ISREG(stat.mode)) + const blob_size = if (bun.isRegularFile(stat.mode)) stat_size else @min(original_size, stat_size); @@ -1806,7 +1809,7 @@ pub const Fetch = struct { }, }; - if (std.os.S.ISREG(stat.mode)) { + if (bun.isRegularFile(stat.mode)) { http_body.Sendfile.offset = @min(http_body.Sendfile.offset, stat_size); http_body.Sendfile.remain = @min(@max(http_body.Sendfile.remain, http_body.Sendfile.offset), stat_size) -| http_body.Sendfile.offset; } @@ -1829,7 +1832,7 @@ pub const Fetch = struct { ); if (body.Blob.store.?.data.file.pathlike == .path) { - _ = JSC.Node.Syscall.close(opened_fd); + _ = bun.sys.close(opened_fd); } switch (res) { diff --git a/src/bun.js/webcore/streams.zig b/src/bun.js/webcore/streams.zig index b3415c4f7..94f10925f 100644 --- a/src/bun.js/webcore/streams.zig +++ b/src/bun.js/webcore/streams.zig @@ -1,8 +1,7 @@ const std = @import("std"); const Api = @import("../../api/schema.zig").Api; const bun = @import("root").bun; -const RequestContext = @import("../../http.zig").RequestContext; -const MimeType = @import("../../http.zig").MimeType; +const MimeType = @import("../../bun_dev_http_server.zig").MimeType; const ZigURL = @import("../../url.zig").URL; const HTTPClient = @import("root").bun.HTTP; const NetworkThread = HTTPClient.NetworkThread; @@ -35,7 +34,7 @@ const JSPromise = JSC.JSPromise; const JSValue = JSC.JSValue; const JSError = JSC.JSError; const JSGlobalObject = JSC.JSGlobalObject; - +const E = bun.C.E; const VirtualMachine = JSC.VirtualMachine; const Task = JSC.Task; const JSPrinter = bun.js_printer; @@ -46,7 +45,7 @@ const Blob = JSC.WebCore.Blob; const Response = JSC.WebCore.Response; const Request = JSC.WebCore.Request; const assert = std.debug.assert; -const Syscall = JSC.Node.Syscall; +const Syscall = bun.sys; const AnyBlob = JSC.WebCore.AnyBlob; pub const ReadableStream = struct { @@ -451,12 +450,20 @@ pub const StreamStart = union(Tag) { .FileSink => { var chunk_size: JSC.WebCore.Blob.SizeType = 0; - if (value.get(globalThis, "highWaterMark")) |chunkSize| { + if (value.getTruthy(globalThis, "highWaterMark")) |chunkSize| { if (chunkSize.isNumber()) chunk_size = @as(JSC.WebCore.Blob.SizeType, @intCast(@max(0, @as(i51, @truncate(chunkSize.toInt64()))))); } - if (value.get(globalThis, "path")) |path| { + if (value.getTruthy(globalThis, "path")) |path| { + if (!path.isString()) { + return .{ + .err = Syscall.Error{ + .errno = @intFromEnum(bun.C.SystemErrno.EINVAL), + }, + }; + } + return .{ .FileSink = .{ .chunk_size = chunk_size, @@ -465,12 +472,28 @@ pub const StreamStart = union(Tag) { }, }, }; - } else if (value.get(globalThis, "fd")) |fd| { + } else if (value.getTruthy(globalThis, "fd")) |fd_value| { + if (!fd_value.isAnyInt()) { + return .{ + .err = Syscall.Error{ + .errno = @intFromEnum(bun.C.SystemErrno.EBADF), + }, + }; + } + const fd = fd_value.toInt64(); + if (fd < 0) { + return .{ + .err = Syscall.Error{ + .errno = @intFromEnum(bun.C.SystemErrno.EBADF), + }, + }; + } + return .{ .FileSink = .{ .chunk_size = chunk_size, .input_path = .{ - .fd = fd.toInt32(), + .fd = @as(bun.FileDescriptor, @intCast(fd)), }, }, }; @@ -487,7 +510,7 @@ pub const StreamStart = union(Tag) { var empty = true; var chunk_size: JSC.WebCore.Blob.SizeType = 2048; - if (value.get(globalThis, "highWaterMark")) |chunkSize| { + if (value.getTruthy(globalThis, "highWaterMark")) |chunkSize| { if (chunkSize.isNumber()) { empty = false; chunk_size = @as(JSC.WebCore.Blob.SizeType, @intCast(@max(256, @as(i51, @truncate(chunkSize.toInt64()))))); @@ -1189,24 +1212,24 @@ pub const FileSink = struct { const auto_close = this.auto_close; const fd = if (!auto_close) input_path.fd - else switch (JSC.Node.Syscall.open(input_path.path.toSliceZ(&file_buf), std.os.O.WRONLY | std.os.O.NONBLOCK | std.os.O.CLOEXEC | std.os.O.CREAT, mode)) { + else switch (bun.sys.open(input_path.path.toSliceZ(&file_buf), std.os.O.WRONLY | std.os.O.NONBLOCK | std.os.O.CLOEXEC | std.os.O.CREAT, mode)) { .result => |_fd| _fd, .err => |err| return .{ .err = err.withPath(input_path.path.slice()) }, }; if (this.poll_ref == null) { - const stat: std.os.Stat = switch (JSC.Node.Syscall.fstat(fd)) { + const stat: bun.Stat = switch (bun.sys.fstat(fd)) { .result => |result| result, .err => |err| { if (auto_close) { - _ = JSC.Node.Syscall.close(fd); + _ = bun.sys.close(fd); } return .{ .err = err.withPathLike(input_path) }; }, }; this.mode = stat.mode; - this.auto_truncate = this.auto_truncate and (std.os.S.ISREG(this.mode)); + this.auto_truncate = this.auto_truncate and (bun.isRegularFile(this.mode)); } else { this.auto_truncate = false; this.max_write_size = max_fifo_size; @@ -1259,7 +1282,7 @@ pub const FileSink = struct { // On Linux, we can adjust the pipe size to avoid blocking. this.has_adjusted_pipe_size_on_linux = true; - switch (JSC.Node.Syscall.setPipeCapacityOnLinux(fd, @min(Syscall.getMaxPipeSizeOnLinux(), remain_len))) { + switch (bun.sys.setPipeCapacityOnLinux(fd, @min(Syscall.getMaxPipeSizeOnLinux(), remain_len))) { .result => |len| { if (len > 0) { this.max_write_size = len; @@ -1358,11 +1381,11 @@ pub const FileSink = struct { if (max_to_write > 0) { while (remain.len > 0) { const write_buf = remain[0..@min(remain.len, max_to_write)]; - const res = JSC.Node.Syscall.write(fd, write_buf); + const res = bun.sys.write(fd, write_buf); if (res == .err) { const retry = - std.os.E.AGAIN; + E.AGAIN; switch (res.err.getErrno()) { retry => { @@ -1461,10 +1484,10 @@ pub const FileSink = struct { } if (this.auto_truncate) - std.os.ftruncate(fd, total) catch {}; + std.os.ftruncate(bun.fdcast(fd), total) catch {}; if (this.auto_close) { - _ = JSC.Node.Syscall.close(fd); + _ = bun.sys.close(fd); this.fd = bun.invalid_fd; } } @@ -1501,7 +1524,7 @@ pub const FileSink = struct { this.scheduled_count = 0; } - _ = JSC.Node.Syscall.close(this.fd); + _ = bun.sys.close(this.fd); this.fd = bun.invalid_fd; } } @@ -1668,7 +1691,7 @@ pub const FileSink = struct { this.fd = bun.invalid_fd; if (this.auto_close) - _ = JSC.Node.Syscall.close(fd); + _ = bun.sys.close(fd); } this.pending.result = .done; @@ -2461,7 +2484,8 @@ pub fn HTTPServerWritable(comptime ssl: bool) type { return this.buffer.ptr[this.offset..this.buffer.cap][0..this.buffer.len]; } - pub fn onWritable(this: *@This(), write_offset: c_ulong, _: *UWSResponse) callconv(.C) bool { + pub fn onWritable(this: *@This(), write_offset_: c_ulong, _: *UWSResponse) callconv(.C) bool { + const write_offset: u64 = @as(u64, write_offset_); log("onWritable ({d})", .{write_offset}); if (this.done) { @@ -3681,7 +3705,7 @@ pub const FIFO = struct { buf: []u8 = &[_]u8{}, view: JSC.Strong = .{}, poll_ref: ?*JSC.FilePoll = null, - fd: bun.FileDescriptor = 0, + fd: bun.FileDescriptor = bun.invalid_fd, to_read: ?u32 = null, close_on_empty_read: bool = false, auto_sizer: ?*AutoSizer = null, @@ -3720,7 +3744,7 @@ pub const FIFO = struct { if (signal_close) { this.fd = bun.invalid_fd; if (this.auto_close) - _ = JSC.Node.Syscall.close(fd); + _ = bun.sys.close(fd); } this.to_read = null; @@ -3783,7 +3807,7 @@ pub const FIFO = struct { if (!is_readable and (this.close_on_empty_read or poll.isHUP())) { // it might be readable actually this.close_on_empty_read = true; - switch (bun.isReadable(@as(std.os.fd_t, @intCast(poll.fd)))) { + switch (bun.isReadable(@intCast(poll.fd))) { .ready => { this.close_on_empty_read = false; return null; @@ -3806,7 +3830,7 @@ pub const FIFO = struct { // this happens if we've registered a watcher but we haven't // ticked the event loop since registering it - switch (bun.isReadable(@as(std.os.fd_t, @intCast(poll.fd)))) { + switch (bun.isReadable(@intCast(poll.fd))) { .ready => { poll.flags.insert(.readable); return null; @@ -3991,8 +4015,8 @@ pub const FIFO = struct { ) ReadResult { switch (Syscall.read(this.fd, buf)) { .err => |err| { - const retry = std.os.E.AGAIN; - const errno: std.os.E = brk: { + const retry = E.AGAIN; + const errno: E = brk: { const _errno = err.getErrno(); if (comptime Environment.isLinux) { @@ -4113,69 +4137,86 @@ pub const File = struct { }, }; - if ((file.is_atty orelse false) or (fd < 3 and std.os.isatty(fd))) { - var termios = std.mem.zeroes(std.os.termios); - _ = std.c.tcgetattr(fd, &termios); - bun.C.cfmakeraw(&termios); - file.is_atty = true; + if ((file.is_atty orelse false) or (fd < 3 and std.os.isatty(bun.fdcast(fd)))) { + if (comptime Environment.isPosix) { + var termios = std.mem.zeroes(std.os.termios); + _ = std.c.tcgetattr(fd, &termios); + bun.C.cfmakeraw(&termios); + file.is_atty = true; + } } if (!auto_close and !(file.is_atty orelse false)) { + if (comptime Environment.isWindows) { + bun.todo(@src(), {}); + } else { + // ensure we have non-blocking IO set + switch (Syscall.fcntl(fd, std.os.F.GETFL, 0)) { + .err => return .{ .err = Syscall.Error.fromCode(E.BADF, .fcntl) }, + .result => |flags| { + // if we do not, clone the descriptor and set non-blocking + // it is important for us to clone it so we don't cause Weird Things to happen + if ((flags & std.os.O.NONBLOCK) == 0) { + auto_close = true; + fd = switch (Syscall.fcntl(fd, std.os.F.DUPFD, 0)) { + .result => |_fd| @as(@TypeOf(fd), @intCast(_fd)), + .err => |err| return .{ .err = err }, + }; - // ensure we have non-blocking IO set - switch (Syscall.fcntl(fd, std.os.F.GETFL, 0)) { - .err => return .{ .err = Syscall.Error.fromCode(std.os.E.BADF, .fcntl) }, - .result => |flags| { - // if we do not, clone the descriptor and set non-blocking - // it is important for us to clone it so we don't cause Weird Things to happen - if ((flags & std.os.O.NONBLOCK) == 0) { - auto_close = true; - fd = switch (Syscall.fcntl(fd, std.os.F.DUPFD, 0)) { - .result => |_fd| @as(@TypeOf(fd), @intCast(_fd)), - .err => |err| return .{ .err = err }, - }; - - switch (Syscall.fcntl(fd, std.os.F.SETFL, flags | std.os.O.NONBLOCK)) { - .err => |err| return .{ .err = err }, - .result => |_| {}, + switch (Syscall.fcntl(fd, std.os.F.SETFL, flags | std.os.O.NONBLOCK)) { + .err => |err| return .{ .err = err }, + .result => |_| {}, + } } - } - }, + }, + } } } + var size: Blob.SizeType = 0; + if (comptime Environment.isPosix) { + const stat: bun.Stat = switch (Syscall.fstat(fd)) { + .result => |result| result, + .err => |err| { + if (auto_close) { + _ = Syscall.close(fd); + } + return .{ .err = err }; + }, + }; - const stat: std.os.Stat = switch (Syscall.fstat(fd)) { - .result => |result| result, - .err => |err| { + if (std.os.S.ISDIR(stat.mode)) { if (auto_close) { _ = Syscall.close(fd); } - return .{ .err = err }; - }, - }; - - if (std.os.S.ISDIR(stat.mode)) { - if (auto_close) { - _ = Syscall.close(fd); + return .{ .err = Syscall.Error.fromCode(.ISDIR, .fstat) }; } - return .{ .err = Syscall.Error.fromCode(.ISDIR, .fstat) }; - } - if (std.os.S.ISSOCK(stat.mode)) { - if (auto_close) { - _ = Syscall.close(fd); + if (std.os.S.ISSOCK(stat.mode)) { + if (auto_close) { + _ = Syscall.close(fd); + } + return .{ .err = Syscall.Error.fromCode(.INVAL, .fstat) }; } - return .{ .err = Syscall.Error.fromCode(.INVAL, .fstat) }; - } - file.mode = @as(JSC.Node.Mode, @intCast(stat.mode)); - this.mode = file.mode; + file.mode = @as(JSC.Node.Mode, @intCast(stat.mode)); + this.mode = file.mode; - this.seekable = std.os.S.ISREG(stat.mode); - file.seekable = this.seekable; + this.seekable = bun.isRegularFile(stat.mode); + file.seekable = this.seekable; + size = @intCast(stat.size); + } else if (comptime Environment.isWindows) outer: { + const std_file = std.fs.File{ + .handle = bun.fdcast(fd), + }; + size = @intCast(std_file.getEndPos() catch { + this.seekable = false; + break :outer; + }); + this.seekable = true; + } if (this.seekable) { - this.remaining_bytes = @as(Blob.SizeType, @intCast(stat.size)); + this.remaining_bytes = size; file.max_size = this.remaining_bytes; if (this.remaining_bytes == 0) { @@ -4250,7 +4291,7 @@ pub const File = struct { const to_read = @min(@as(usize, this.concurrent.chunk_size), remaining.len); switch (Syscall.read(this.fd, remaining[0..to_read])) { .err => |err| { - const retry = std.os.E.AGAIN; + const retry = E.AGAIN; switch (err.getErrno()) { retry => break, @@ -4381,7 +4422,7 @@ pub const File = struct { pub fn doRead(this: *File, buf: []u8) ReadResult { switch (Syscall.read(this.fd, buf)) { .err => |err| { - const retry = std.os.E.AGAIN; + const retry = bun.C.E.AGAIN; const errno = err.getErrno(); switch (errno) { @@ -4596,8 +4637,14 @@ pub const FileReader = struct { return result; } + const is_fifo = if (comptime Environment.isPosix) + std.os.S.ISFIFO(readable_file.mode) or std.os.S.ISCHR(readable_file.mode) + else + // TODO: windows + bun.todo(@src(), false); + // for our purposes, ISCHR and ISFIFO are the same - if (std.os.S.ISFIFO(readable_file.mode) or std.os.S.ISCHR(readable_file.mode)) { + if (is_fifo) { this.lazy_readable = .{ .readable = .{ .FIFO = .{ @@ -4743,6 +4790,10 @@ pub fn NewReadyWatcher( } if (comptime @hasField(Context, "mode")) { + if (comptime Environment.isWindows) { + return bun.todo(@src(), false); + } + return std.os.S.ISFIFO(this.mode); } @@ -4784,7 +4835,7 @@ pub fn NewReadyWatcher( } pub fn watch(this: *Context, fd_: anytype) void { - const fd = @as(c_int, @intCast(fd_)); + const fd = @as(bun.FileDescriptor, @intCast(fd_)); var poll_ref: *JSC.FilePoll = this.poll_ref orelse brk: { this.poll_ref = JSC.FilePoll.init( JSC.VirtualMachine.get(), diff --git a/src/bun.zig b/src/bun.zig index c4dad48cf..3c428cbbf 100644 --- a/src/bun.zig +++ b/src/bun.zig @@ -263,12 +263,17 @@ pub const fmt = struct { pub const Output = @import("./output.zig"); pub const Global = @import("./__global.zig"); -pub const FileDescriptor = if (Environment.isBrowser) u0 else std.os.fd_t; +pub const FileDescriptor = if (Environment.isBrowser) + u0 +else if (Environment.isWindows) + u64 +else + std.os.fd_t; // When we are on a computer with an absurdly high number of max open file handles // such is often the case with macOS // As a useful optimization, we can store file descriptors and just keep them open...forever -pub const StoredFileDescriptorType = if (Environment.isWindows or Environment.isBrowser) u0 else std.os.fd_t; +pub const StoredFileDescriptorType = if (Environment.isBrowser) u0 else FileDescriptor; pub const StringTypes = @import("string_types.zig"); pub const stringZ = StringTypes.stringZ; @@ -285,6 +290,7 @@ pub inline fn constStrToU8(s: []const u8) []u8 { } pub const MAX_PATH_BYTES: usize = if (Environment.isWasm) 1024 else std.fs.MAX_PATH_BYTES; +pub const MAX_WPATH = [MAX_PATH_BYTES / 2:0]u16; pub inline fn cast(comptime To: type, value: anytype) To { if (comptime std.meta.trait.isIntegral(@TypeOf(value))) { @@ -599,10 +605,14 @@ pub fn ensureNonBlocking(fd: anytype) void { } const global_scope_log = Output.scoped(.bun, false); -pub fn isReadable(fd: std.os.fd_t) PollFlag { +pub fn isReadable(fd: FileDescriptor) PollFlag { + if (comptime Environment.isWindows) { + return todo(@src(), PollFlag.not_ready); + } + var polls = [_]std.os.pollfd{ .{ - .fd = fd, + .fd = @intCast(fd), .events = std.os.POLL.IN | std.os.POLL.ERR, .revents = 0, }, @@ -619,10 +629,14 @@ pub fn isReadable(fd: std.os.fd_t) PollFlag { } pub const PollFlag = enum { ready, not_ready, hup }; -pub fn isWritable(fd: std.os.fd_t) PollFlag { +pub fn isWritable(fd: FileDescriptor) PollFlag { + if (comptime Environment.isWindows) { + return todo(@src(), PollFlag.not_ready); + } + var polls = [_]std.os.pollfd{ .{ - .fd = fd, + .fd = @intCast(fd), .events = std.os.POLL.OUT, .revents = 0, }, @@ -700,7 +714,13 @@ pub fn rangeOfSliceInBuffer(slice: []const u8, buffer: []const u8) ?[2]u32 { return r; } -pub const invalid_fd = std.math.maxInt(FileDescriptor); +pub const invalid_fd = if (Environment.isWindows) + // on windows, max usize is the process handle, a very valid fd + std.math.maxInt(i32) + 1 +else + std.math.maxInt(FileDescriptor); + +pub const UFileDescriptor = if (Environment.isWindows) usize else u32; pub const simdutf = @import("./bun.js/bindings/bun-simdutf.zig"); @@ -966,6 +986,7 @@ pub const fs = @import("./fs.zig"); pub const Bundler = bundler.Bundler; pub const bundler = @import("./bundler.zig"); pub const which = @import("./which.zig").which; +pub const is_executable_fileZ = @import("./which.zig").is_executable_file; pub const js_parser = @import("./js_parser.zig"); pub const js_printer = @import("./js_printer.zig"); pub const js_lexer = @import("./js_lexer.zig"); @@ -1022,7 +1043,7 @@ var needs_proc_self_workaround: bool = false; // necessary on linux because other platforms don't have an optional // /proc/self/fd fn getFdPathViaCWD(fd: std.os.fd_t, buf: *[@This().MAX_PATH_BYTES]u8) ![]u8 { - const prev_fd = try std.os.openatZ(std.os.AT.FDCWD, ".", 0, 0); + const prev_fd = try std.os.openatZ(std.fs.cwd().fd, ".", 0, 0); var needs_chdir = false; defer { if (needs_chdir) std.os.fchdir(prev_fd) catch unreachable; @@ -1035,7 +1056,8 @@ fn getFdPathViaCWD(fd: std.os.fd_t, buf: *[@This().MAX_PATH_BYTES]u8) ![]u8 { /// Get the absolute path to a file descriptor. /// On Linux, when `/proc/self/fd` is not available, this function will attempt to use `fchdir` and `getcwd` to get the path instead. -pub fn getFdPath(fd: std.os.fd_t, buf: *[@This().MAX_PATH_BYTES]u8) ![]u8 { +pub fn getFdPath(fd_: anytype, buf: *[@This().MAX_PATH_BYTES]u8) ![]u8 { + const fd = fdcast(toFD(fd_)); if (comptime !Environment.isLinux) { return std.os.getFdPath(fd, buf); } @@ -1294,9 +1316,9 @@ pub fn reloadProcess( clear_terminal: bool, ) void { const PosixSpawn = @import("./bun.js/api/bun/spawn.zig").PosixSpawn; - - var dupe_argv = allocator.allocSentinel(?[*:0]const u8, std.os.argv.len, null) catch unreachable; - for (std.os.argv, dupe_argv) |src, *dest| { + const bun = @This(); + var dupe_argv = allocator.allocSentinel(?[*:0]const u8, bun.argv().len, null) catch unreachable; + for (bun.argv(), dupe_argv) |src, *dest| { dest.* = (allocator.dupeZ(u8, sliceTo(src, 0)) catch unreachable).ptr; } @@ -1593,3 +1615,220 @@ pub inline fn assertComptime() void { @compileError("This function can only be called in comptime."); } } + +const TODO_LOG = Output.scoped(.TODO, false); +pub inline fn todo(src: std.builtin.SourceLocation, value: anytype) @TypeOf(value) { + if (comptime Environment.allow_assert) { + TODO_LOG("{s}() at {s}:{d}:{d}", .{ src.fn_name, src.file, src.line, src.column }); + } + + return value; +} + +pub inline fn fdcast(fd: FileDescriptor) std.os.fd_t { + if (comptime FileDescriptor == std.os.fd_t) { + return fd; + } + + return @ptrFromInt(fd); +} + +pub inline fn socketcast(fd: FileDescriptor) std.os.fd_t { + if (comptime FileDescriptor == std.os.fd_t) { + return fd; + } + + return @ptrFromInt(fd); +} + +pub inline fn toFD(fd: anytype) FileDescriptor { + const FD = @TypeOf(fd); + if (comptime FileDescriptor == std.os.fd_t) { + return @intCast(fd); + } + + if (comptime FD == std.os.fd_t) { + return @intFromPtr(fd); + } + + return @intCast(fd); +} + +pub const HOST_NAME_MAX = if (Environment.isWindows) + // TODO: i have no idea what this value should be + 256 +else + std.os.HOST_NAME_MAX; + +pub const enums = @import("./enums.zig"); +const WindowsStat = extern struct { + dev: u32, + ino: u32, + nlink: usize, + + mode: JSC.Node.Mode, + uid: u32, + gid: u32, + rdev: u32, + size: u32, + blksize: isize, + blocks: i64, + + atim: std.c.timespec, + mtim: std.c.timespec, + ctim: std.c.timespec, + + pub fn mtime(this: *const WindowsStat) std.c.timespec { + return this.mtim; + } + + pub fn ctime(this: *const WindowsStat) std.c.timespec { + return this.ctim; + } + + pub fn atime(this: *const WindowsStat) std.c.timespec { + return this.atim; + } +}; + +pub const Stat = if (Environment.isPosix) std.os.Stat else WindowsStat; + +pub const posix = struct { + pub const STDOUT_FD = std.os.STDOUT_FILENO; + pub const STDERR_FD = std.os.STDERR_FILENO; + pub const STDIN_FD = std.os.STDIN_FILENO; + pub inline fn argv() [][*:0]u8 { + return std.os.argv; + } + + pub fn stdio(i: anytype) FileDescriptor { + return switch (i) { + STDOUT_FD => STDOUT_FD, + STDERR_FD => STDERR_FD, + STDIN_FD => STDIN_FD, + else => @panic("Invalid stdio fd"), + }; + } +}; + +pub const win32 = struct { + pub var STDOUT_FD: FileDescriptor = undefined; + pub var STDERR_FD: FileDescriptor = undefined; + pub var STDIN_FD: FileDescriptor = undefined; + var argv_: [][*:0]u8 = undefined; + var args_buf: [255][*:0]u8 = undefined; + + pub inline fn argv() [][*:0]u8 { + return argv_; + } + + pub fn stdio(i: anytype) FileDescriptor { + return switch (i) { + 0 => STDIN_FD, + 1 => STDOUT_FD, + 2 => STDERR_FD, + else => @panic("Invalid stdio fd"), + }; + } + + pub fn populateArgv() void { + const kernel32 = windows; + + var wargv_all = kernel32.GetCommandLineW(); + var num_args: c_int = 0; + var start = kernel32.CommandLineToArgvW(wargv_all, &num_args); + defer _ = kernel32.LocalFree(@ptrCast(start)); + var wargv = start[0..@as(usize, @intCast(num_args))]; + var argv_list = std.ArrayList([*:0]u8).init(default_allocator); + argv_list.items = &args_buf; + argv_list.capacity = args_buf.len; + + if (wargv.len > args_buf.len) { + var ptrs = default_allocator.alloc(?[*]u8, wargv.len + 1) catch unreachable; + ptrs[ptrs.len - 1] = null; + argv_list.items = @ptrCast(ptrs[0 .. ptrs.len - 1]); + argv_list.capacity = argv_list.items.len + 1; + } + + const probably_overestimated_length = strings.elementLengthUTF16IntoUTF8([]const u16, sliceTo(wargv_all, 0)) + argv_list.items.len; + var buf = default_allocator.alloc(u8, probably_overestimated_length) catch unreachable; + var builder = StringBuilder{ + .cap = probably_overestimated_length, + .ptr = buf.ptr, + .len = 0, + }; + + for (wargv) |warg_| { + var warg = sliceTo(warg_, 0); + argv_list.appendAssumeCapacity( + (builder.append16(warg) orelse brk: { + var list = strings.convertUTF16ToUTF8(std.ArrayList(u8).init(default_allocator), []const u16, warg) catch unreachable; + list.append(0) catch unreachable; + break :brk list.items.ptr[0..list.items.len :0]; + }).ptr, + ); + } + + argv_ = argv_list.items.ptr[0..argv_list.items.len]; + } +}; + +pub usingnamespace if (@import("builtin").target.os.tag != .windows) posix else win32; + +pub fn isRegularFile(mode: JSC.Node.Mode) bool { + if (comptime Environment.isPosix) { + return std.os.S.ISREG(mode); + } + + if (comptime Environment.isWindows) { + return todo(@src(), true); + } + + @compileError("Unsupported platform"); +} + +pub const sys = @import("./bun.js/node/syscall.zig"); + +pub const windows = @import("./windows.zig"); + +pub const FDTag = enum { + none, + stderr, + stdin, + stdout, + pub fn get(fd_: anytype) FDTag { + const fd = toFD(fd_); + if (comptime Environment.isWindows) { + if (fd == win32.STDOUT_FD) { + return .stdout; + } else if (fd == win32.STDERR_FD) { + return .stderr; + } else if (fd == win32.STDIN_FD) { + return .stdin; + } + + return .none; + } else { + return switch (fd) { + posix.STDIN_FD => FDTag.stdin, + posix.STDOUT_FD => FDTag.stdout, + posix.STDERR_FD => FDTag.stderr, + else => .none, + }; + } + } +}; + +pub fn fdi32(fd_: anytype) i32 { + if (comptime Environment.isPosix) { + return @intCast(toFD(fd_)); + } + + if (comptime @TypeOf(fd_) == *anyopaque) { + return @intCast(@intFromPtr(fd_)); + } + + return @intCast(fd_); +} + +pub const OSPathSlice = if (Environment.isWindows) [:0]const u16 else [:0]const u8; diff --git a/src/http.zig b/src/bun_dev_http_server.zig index f29b7cad9..6dfc24889 100644 --- a/src/http.zig +++ b/src/bun_dev_http_server.zig @@ -64,7 +64,7 @@ threadlocal var res_headers_buf: [100]picohttp.Header = undefined; const sync = @import("./sync.zig"); const JavaScript = @import("root").bun.JSC; const JavaScriptCore = JavaScriptCore.C; -const Syscall = JavaScript.Node.Syscall; +const Syscall = bun.sys; const Router = @import("./router.zig"); pub const Watcher = watcher.NewWatcher(*Server); const ZigURL = @import("./url.zig").URL; @@ -96,7 +96,7 @@ fn disableSIGPIPESoClosingTheTabDoesntCrash(conn: anytype) void { } var http_editor_context: EditorContext = EditorContext{}; -pub const RequestContext = struct { +const PosixRequestContext = struct { request: Request, method: Method, url: URLPath, @@ -2512,6 +2512,8 @@ pub const RequestContext = struct { } }; +pub const RequestContext = if (!Environment.isPosix) struct {} else PosixRequestContext; + // // u32 == File ID from Watcher // pub const WatcherBuildChannel = sync.Channel(u32, .Dynamic); // pub const WatcherBuildQueue = struct { @@ -3287,6 +3289,8 @@ pub const Server = struct { pub var global_start_time: std.time.Timer = undefined; pub fn start(allocator: std.mem.Allocator, options: Api.TransformOptions, comptime DebugType: type, debug: DebugType) !void { + if (comptime Environment.isWindows) unreachable; + var log = logger.Log.init(allocator); var server = try allocator.create(Server); server.* = Server{ diff --git a/src/bundler.zig b/src/bundler.zig index 734555ef5..2848b4b8f 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -990,7 +990,7 @@ pub const Bundler = struct { null, ) catch return null; - const _file = Fs.File{ .path = file_path, .contents = entry.contents }; + const _file = Fs.PathContentsPair{ .path = file_path, .contents = entry.contents }; var source = try logger.Source.initFile(_file, bundler.allocator); source.contents_is_recycled = !cache_files; @@ -1008,12 +1008,12 @@ pub const Bundler = struct { output_file.size = css_writer.ctx.context.bytes_written; var file_op = options.OutputFile.FileOperation.fromFile(file.handle, file_path.pretty); - file_op.fd = file.handle; + file_op.fd = bun.toFD(file.handle); file_op.is_tmpdir = false; if (Outstream == std.fs.Dir) { - file_op.dir = outstream.fd; + file_op.dir = bun.toFD(outstream.fd); if (bundler.fs.fs.needToCloseFiles()) { file.close(); @@ -1028,7 +1028,7 @@ pub const Bundler = struct { var pathname = try bundler.allocator.alloc(u8, hashed_name.len + file_path.name.ext.len); bun.copy(u8, pathname, hashed_name); bun.copy(u8, pathname[hashed_name.len..], file_path.name.ext); - const dir = if (bundler.options.output_dir_handle) |output_handle| output_handle.fd else 0; + const dir = if (bundler.options.output_dir_handle) |output_handle| bun.toFD(output_handle.fd) else 0; output_file.value = .{ .copy = options.OutputFile.FileOperation{ @@ -1266,7 +1266,7 @@ pub const Bundler = struct { if (this_parse.file_fd_ptr) |file_fd_ptr| { file_fd_ptr.* = entry.fd; } - break :brk logger.Source.initRecycledFile(Fs.File{ .path = path, .contents = entry.contents }, bundler.allocator) catch return null; + break :brk logger.Source.initRecycledFile(.{ .path = path, .contents = entry.contents }, bundler.allocator) catch return null; }; if (comptime return_file_only) { @@ -1563,9 +1563,9 @@ pub const Bundler = struct { else => { var abs_path = path.text; const file = try std.fs.openFileAbsolute(abs_path, .{ .mode = .read_only }); - var stat = try file.stat(); + const size = try file.getEndPos(); return ServeResult{ - .file = options.OutputFile.initFile(file, abs_path, stat.size), + .file = options.OutputFile.initFile(file, abs_path, size), .mime_type = MimeType.byLoader( loader, mime_type_ext[1..], diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig index 97118ac70..67cdee041 100644 --- a/src/bundler/bundle_v2.zig +++ b/src/bundler/bundle_v2.zig @@ -2555,7 +2555,7 @@ pub const ParseTask = struct { const will_close_file_descriptor = task.contents_or_fd == .fd and entry.fd > 2 and this.ctx.bun_watcher == null; if (will_close_file_descriptor) { - _ = JSC.Node.Syscall.close(entry.fd); + _ = bun.sys.close(entry.fd); } if (!will_close_file_descriptor and entry.fd > 2) task.contents_or_fd = .{ @@ -9166,7 +9166,7 @@ const LinkerContext = struct { }, }, .encoding = .buffer, - .dirfd = @as(bun.FileDescriptor, @intCast(root_dir.dir.fd)), + .dirfd = bun.toFD(root_dir.dir.fd), .file = .{ .path = JSC.Node.PathLike{ .string = JSC.PathString.init(source_map_final_rel_path), @@ -9236,7 +9236,7 @@ const LinkerContext = struct { .encoding = .buffer, .mode = if (chunk.is_executable) 0o755 else 0o644, - .dirfd = @as(bun.FileDescriptor, @intCast(root_dir.dir.fd)), + .dirfd = bun.toFD(root_dir.dir.fd), .file = .{ .path = JSC.Node.PathLike{ .string = JSC.PathString.init(rel_path), @@ -9305,7 +9305,7 @@ const LinkerContext = struct { }, }, .encoding = .buffer, - .dirfd = @as(bun.FileDescriptor, @intCast(root_dir.dir.fd)), + .dirfd = bun.toFD(root_dir.dir.fd), .file = .{ .path = JSC.Node.PathLike{ .string = JSC.PathString.init(components_manifest_path), @@ -9381,7 +9381,7 @@ const LinkerContext = struct { }, }, .encoding = .buffer, - .dirfd = @as(bun.FileDescriptor, @intCast(root_dir.dir.fd)), + .dirfd = bun.toFD(root_dir.dir.fd), .file = .{ .path = JSC.Node.PathLike{ .string = JSC.PathString.init(src.dest_path), @@ -2,9 +2,10 @@ const std = @import("std"); const bun = @import("root").bun; const Environment = @import("./env.zig"); -const PlatformSpecific = switch (@import("builtin").target.os.tag) { - .macos => @import("./darwin_c.zig"), +const PlatformSpecific = switch (Environment.os) { + .mac => @import("./darwin_c.zig"), .linux => @import("./linux_c.zig"), + .windows => @import("./windows_c.zig"), else => struct {}, }; pub usingnamespace PlatformSpecific; @@ -18,7 +19,9 @@ const Kind = std.fs.File.Kind; const StatError = std.fs.File.StatError; const errno = os.errno; const mode_t = C.mode_t; -const libc_stat = C.Stat; +// TODO: this is wrong on Windows +const libc_stat = bun.Stat; + const zeroes = mem.zeroes; pub const darwin = @import("./darwin_c.zig"); pub const linux = @import("./linux_c.zig"); @@ -29,8 +32,11 @@ pub extern "c" fn fchmodat(c_int, [*c]const u8, mode_t, c_int) c_int; pub extern "c" fn fchown(std.c.fd_t, std.c.uid_t, std.c.gid_t) c_int; pub extern "c" fn lchown(path: [*:0]const u8, std.c.uid_t, std.c.gid_t) c_int; pub extern "c" fn chown(path: [*:0]const u8, std.c.uid_t, std.c.gid_t) c_int; +// TODO: this is wrong on Windows pub extern "c" fn lstat64([*c]const u8, [*c]libc_stat) c_int; +// TODO: this is wrong on Windows pub extern "c" fn fstat64([*c]const u8, [*c]libc_stat) c_int; +// TODO: this is wrong on Windows pub extern "c" fn stat64([*c]const u8, [*c]libc_stat) c_int; pub extern "c" fn lchmod(path: [*:0]const u8, mode: mode_t) c_int; pub extern "c" fn truncate([*:0]const u8, i64) c_int; // note: truncate64 is not a thing @@ -129,24 +135,37 @@ pub fn moveFileZWithHandle(from_handle: std.os.fd_t, from_dir: std.os.fd_t, file // On Linux, this will be fast because sendfile() supports copying between two file descriptors on disk // macOS & BSDs will be slow because pub fn moveFileZSlow(from_dir: std.os.fd_t, filename: [*:0]const u8, to_dir: std.os.fd_t, destination: [*:0]const u8) !void { - const in_handle = try std.os.openatZ(from_dir, filename, std.os.O.RDONLY | std.os.O.CLOEXEC, 0o600); + const in_handle = try std.os.openatZ(from_dir, filename, std.os.O.RDONLY | std.os.O.CLOEXEC, if (Environment.isWindows) 0 else 0o600); defer std.os.close(in_handle); try copyFileZSlowWithHandle(in_handle, to_dir, destination); std.os.unlinkatZ(from_dir, filename, 0) catch {}; } pub fn copyFileZSlowWithHandle(in_handle: std.os.fd_t, to_dir: std.os.fd_t, destination: [*:0]const u8) !void { - const stat_ = try std.os.fstat(in_handle); + const stat_ = if (comptime Environment.isPosix) try std.os.fstat(in_handle) else void{}; + const size = brk: { + if (comptime Environment.isPosix) { + break :brk stat_.size; + } + + break :brk try std.os.windows.GetFileSizeEx(in_handle); + }; + // delete if exists, don't care if it fails. it may fail due to the file not existing // delete here because we run into weird truncation issues if we do not // ftruncate() instead didn't work. // this is technically racy because it could end up deleting the file without saving std.os.unlinkatZ(to_dir, destination, 0) catch {}; - const out_handle = try std.os.openatZ(to_dir, destination, std.os.O.WRONLY | std.os.O.CREAT | std.os.O.CLOEXEC, 0o022); + const out_handle = try std.os.openatZ( + to_dir, + destination, + std.os.O.WRONLY | std.os.O.CREAT | std.os.O.CLOEXEC, + if (comptime Environment.isPosix) 0o022 else 0, + ); defer std.os.close(out_handle); if (comptime Environment.isLinux) { - _ = std.os.system.fallocate(out_handle, 0, 0, @as(i64, @intCast(stat_.size))); - _ = try std.os.sendfile(out_handle, in_handle, 0, @as(usize, @intCast(stat_.size)), &[_]std.os.iovec_const{}, &[_]std.os.iovec_const{}, 0); + _ = std.os.system.fallocate(out_handle, 0, 0, @as(i64, @intCast(size))); + _ = try std.os.sendfile(out_handle, in_handle, 0, @as(usize, @intCast(size)), &[_]std.os.iovec_const{}, &[_]std.os.iovec_const{}, 0); } else { if (comptime Environment.isMac) { // if this fails, it doesn't matter @@ -154,7 +173,7 @@ pub fn copyFileZSlowWithHandle(in_handle: std.os.fd_t, to_dir: std.os.fd_t, dest PlatformSpecific.preallocate_file( out_handle, @as(std.os.off_t, @intCast(0)), - @as(std.os.off_t, @intCast(stat_.size)), + @as(std.os.off_t, @intCast(size)), ) catch {}; } @@ -170,11 +189,16 @@ pub fn copyFileZSlowWithHandle(in_handle: std.os.fd_t, to_dir: std.os.fd_t, dest } } - _ = fchmod(out_handle, stat_.mode); - _ = fchown(out_handle, stat_.uid, stat_.gid); + if (comptime Environment.isPosix) { + _ = fchmod(out_handle, stat_.mode); + _ = fchown(out_handle, stat_.uid, stat_.gid); + } } pub fn kindFromMode(mode: os.mode_t) std.fs.File.Kind { + if (comptime Environment.isWindows) { + return bun.todo(@src(), std.fs.File.Kind.unknown); + } return switch (mode & os.S.IFMT) { os.S.IFBLK => std.fs.File.Kind.block_device, os.S.IFCHR => std.fs.File.Kind.character_device, @@ -315,43 +339,6 @@ pub fn getSelfExeSharedLibPaths(allocator: std.mem.Allocator) error{OutOfMemory} /// with POSIX_ prefix for the advice system call argument. pub extern "c" fn posix_madvise(ptr: *anyopaque, len: usize, advice: i32) c_int; -// System related -pub fn getFreeMemory() u64 { - if (comptime Environment.isLinux) { - return linux.get_free_memory(); - } else if (comptime Environment.isMac) { - return darwin.get_free_memory(); - } else { - return -1; - } -} - -pub fn getTotalMemory() u64 { - if (comptime Environment.isLinux) { - return linux.get_total_memory(); - } else if (comptime Environment.isMac) { - return darwin.get_total_memory(); - } else { - return -1; - } -} - -pub fn getSystemUptime() u64 { - if (comptime Environment.isLinux) { - return linux.get_system_uptime(); - } else { - return darwin.get_system_uptime(); - } -} - -pub fn getSystemLoadavg() [3]f64 { - if (comptime Environment.isLinux) { - return linux.get_system_loadavg(); - } else { - return darwin.get_system_loadavg(); - } -} - pub fn getProcessPriority(pid_: i32) i32 { const pid = @as(c_uint, @intCast(pid_)); return get_process_priority(pid); @@ -374,21 +361,21 @@ pub fn setProcessPriority(pid_: i32, priority_: i32) std.c.E { pub fn getVersion(buf: []u8) []const u8 { if (comptime Environment.isLinux) { - return linux.get_version(buf.ptr[0..std.os.HOST_NAME_MAX]); + return linux.get_version(buf.ptr[0..bun.HOST_NAME_MAX]); } else if (comptime Environment.isMac) { return darwin.get_version(buf); } else { - return "unknown"; + return bun.todo(@src(), "unknown"); } } pub fn getRelease(buf: []u8) []const u8 { if (comptime Environment.isLinux) { - return linux.get_release(buf.ptr[0..std.os.HOST_NAME_MAX]); + return linux.get_release(buf.ptr[0..bun.HOST_NAME_MAX]); } else if (comptime Environment.isMac) { return darwin.get_release(buf); } else { - return "unknown"; + return bun.todo(@src(), "unknown"); } } diff --git a/src/cache.zig b/src/cache.zig index 6a33211d5..4585860fa 100644 --- a/src/cache.zig +++ b/src/cache.zig @@ -158,7 +158,7 @@ pub const Fs = struct { ) !Entry { var rfs = _fs.fs; - var file_handle: std.fs.File = if (_file_handle) |__file| std.fs.File{ .handle = __file } else undefined; + var file_handle: std.fs.File = if (_file_handle) |__file| std.fs.File{ .handle = bun.fdcast(__file) } else undefined; if (_file_handle == null) { if (FeatureFlags.store_file_descriptors and dirname_fd != bun.invalid_fd and dirname_fd > 0) { diff --git a/src/cli.zig b/src/cli.zig index 156f9e48d..68ae7e4c2 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -114,8 +114,8 @@ pub const Arguments = struct { defer allocator.free(outpath); var file = try std.fs.openFileAbsolute(outpath, std.fs.File.OpenFlags{ .mode = .read_only }); defer file.close(); - const stats = try file.stat(); - return try file.readToEndAlloc(allocator, stats.size); + const size = try file.getEndPos(); + return try file.readToEndAlloc(allocator, size); } pub fn resolve_jsx_runtime(str: string) !Api.JsxRuntime { @@ -1076,7 +1076,7 @@ pub const Command = struct { }; pub fn which() Tag { - var args_iter = ArgsIterator{ .buf = std.os.argv }; + var args_iter = ArgsIterator{ .buf = bun.argv() }; // first one is the executable name const argv0 = args_iter.next() orelse return .HelpCommand; @@ -1130,7 +1130,10 @@ pub const Command = struct { RootCommandMatcher.case("r"), RootCommandMatcher.case("remove"), RootCommandMatcher.case("rm"), RootCommandMatcher.case("uninstall") => .RemoveCommand, RootCommandMatcher.case("run") => .RunCommand, - RootCommandMatcher.case("d"), RootCommandMatcher.case("dev") => .DevCommand, + RootCommandMatcher.case("d"), RootCommandMatcher.case("dev") => if (comptime Environment.isWindows) { + Output.prettyErrorln("<r><red>error:<r> bun dev is not supported on Windows.", .{}); + Global.exit(1); + } else .DevCommand, RootCommandMatcher.case("help") => .HelpCommand, else => .AutoCommand, @@ -1210,9 +1213,9 @@ pub const Command = struct { }; ctx.args.target = Api.Target.bun; - var argv = try bun.default_allocator.alloc(string, std.os.argv.len -| 1); - if (std.os.argv.len > 1) { - for (argv, std.os.argv[1..]) |*dest, src| { + var argv = try bun.default_allocator.alloc(string, bun.argv().len -| 1); + if (bun.argv().len > 1) { + for (argv, bun.argv()[1..]) |*dest, src| { dest.* = bun.span(src); } } @@ -1231,7 +1234,7 @@ pub const Command = struct { switch (tag) { .DiscordCommand => return try DiscordCommand.exec(allocator), .HelpCommand => return try HelpCommand.exec(allocator), - .InitCommand => return try InitCommand.exec(allocator, std.os.argv), + .InitCommand => return try InitCommand.exec(allocator, bun.argv()), else => {}, } @@ -1243,6 +1246,7 @@ pub const Command = struct { try BuildCommand.exec(ctx); }, .DevCommand => { + if (comptime Environment.isWindows) unreachable; if (comptime bun.fast_debug_build_mode and bun.fast_debug_build_cmd != .DevCommand) unreachable; const ctx = try Command.Context.create(allocator, log, .DevCommand); @@ -1465,7 +1469,7 @@ pub const Command = struct { // KEYWORDS: open file argv argv0 if (ctx.args.entry_points.len == 1) { if (strings.eqlComptime(extension, ".lockb")) { - for (std.os.argv) |arg| { + for (bun.argv()) |arg| { if (strings.eqlComptime(std.mem.span(arg), "--hash")) { try PackageManagerCommand.printHash(ctx, ctx.args.entry_points[0]); return; diff --git a/src/cli/build_command.zig b/src/cli/build_command.zig index f87d88930..cb7d1ce94 100644 --- a/src/cli/build_command.zig +++ b/src/cli/build_command.zig @@ -411,7 +411,7 @@ pub const BuildCommand = struct { }, .encoding = .buffer, .mode = if (f.is_executable) 0o755 else 0o644, - .dirfd = @as(bun.FileDescriptor, @intCast(root_dir.dir.fd)), + .dirfd = bun.toFD(root_dir.dir.fd), .file = .{ .path = JSC.Node.PathLike{ .string = JSC.PathString.init(rel_path), @@ -431,12 +431,12 @@ pub const BuildCommand = struct { rel_path = filepath_buf[0 .. primary.len + 2]; rel_path = value.pathname; - try f.moveTo(root_path, bun.constStrToU8(rel_path), root_dir.dir.fd); + try f.moveTo(root_path, bun.constStrToU8(rel_path), bun.toFD(root_dir.dir.fd)); }, .copy => |value| { rel_path = value.pathname; - try f.copyTo(root_path, bun.constStrToU8(rel_path), root_dir.dir.fd); + try f.copyTo(root_path, bun.constStrToU8(rel_path), bun.toFD(root_dir.dir.fd)); }, .noop => {}, .pending => unreachable, diff --git a/src/cli/bunx_command.zig b/src/cli/bunx_command.zig index 84c7e1bba..9bf7e1d11 100644 --- a/src/cli/bunx_command.zig +++ b/src/cli/bunx_command.zig @@ -97,7 +97,7 @@ pub const BunxCommand = struct { "{s}/node_modules/{s}/package.json", .{ tempdir_name, package_name }, ) catch unreachable; - return try getBinNameFromSubpath(bundler, std.os.AT.FDCWD, subpath_z); + return try getBinNameFromSubpath(bundler, std.fs.cwd().fd, subpath_z); } /// Check the enclosing package.json for a matching "bin" @@ -141,10 +141,10 @@ pub const BunxCommand = struct { var requests_buf = bun.PackageManager.UpdateRequest.Array.init(0) catch unreachable; var run_in_bun = ctx.debug.run_in_bun; - var passthrough_list = try std.ArrayList(string).initCapacity(ctx.allocator, std.os.argv.len -| 1); + var passthrough_list = try std.ArrayList(string).initCapacity(ctx.allocator, bun.argv().len -| 1); var package_name_for_update_request = [1]string{""}; { - var argv = std.os.argv[1..]; + var argv = bun.argv()[1..]; var found_subcommand_name = false; @@ -286,7 +286,7 @@ pub const BunxCommand = struct { } // 2. The "bin" is possibly not the same as the package name, so we load the package.json to figure out what "bin" to use - if (getBinName(&this_bundler, root_dir_info.getFileDescriptor(), bunx_cache_dir, initial_bin_name)) |package_name_for_bin| { + if (getBinName(&this_bundler, bun.fdcast(root_dir_info.getFileDescriptor()), bunx_cache_dir, initial_bin_name)) |package_name_for_bin| { // if we check the bin name and its actually the same, we don't need to check $PATH here again if (!strings.eqlLong(package_name_for_bin, initial_bin_name, true)) { absolute_in_cache_dir = std.fmt.bufPrint(&absolute_in_cache_dir_buf, "{s}/node_modules/.bin/{s}", .{ bunx_cache_dir, package_name_for_bin }) catch unreachable; diff --git a/src/cli/create_command.zig b/src/cli/create_command.zig index 284de1fd5..8264bf771 100644 --- a/src/cli/create_command.zig +++ b/src/cli/create_command.zig @@ -554,7 +554,7 @@ pub const CreateCommand = struct { progress.refresh(); package_json_contents = plucker.contents; - package_json_file = std.fs.File{ .handle = plucker.fd }; + package_json_file = std.fs.File{ .handle = bun.fdcast(plucker.fd) }; } } }, @@ -615,9 +615,13 @@ pub const CreateCommand = struct { var infile = try entry.dir.dir.openFile(entry.basename, .{ .mode = .read_only }); defer infile.close(); - // Assumption: you only really care about making sure something that was executable is still executable - const stat = infile.stat() catch continue; - _ = C.fchmod(outfile.handle, stat.mode); + if (comptime Environment.isPosix) { + // Assumption: you only really care about making sure something that was executable is still executable + const stat = infile.stat() catch continue; + _ = C.fchmod(outfile.handle, stat.mode); + } else { + bun.todo(@src(), void{}); + } CopyFile.copyFile(infile.handle, outfile.handle) catch |err| { Output.prettyErrorln("<r><red>{s}<r>: copying file {s}", .{ @errorName(err), entry.path }); @@ -633,24 +637,33 @@ pub const CreateCommand = struct { read_package_json: { if (package_json_file) |pkg| { - const stat = pkg.stat() catch |err| { - node.end(); + const size = brk: { + if (comptime Environment.isWindows) { + break :brk try pkg.getEndPos(); + } - progress.refresh(); + const stat = pkg.stat() catch |err| { + node.end(); - package_json_file = null; - Output.prettyErrorln("Error reading package.json: <r><red>{s}", .{@errorName(err)}); - break :read_package_json; - }; + progress.refresh(); - if (stat.kind != .file or stat.size == 0) { - package_json_file = null; - node.end(); + package_json_file = null; + Output.prettyErrorln("Error reading package.json: <r><red>{s}", .{@errorName(err)}); + break :read_package_json; + }; - progress.refresh(); - break :read_package_json; - } - package_json_contents = try MutableString.init(ctx.allocator, stat.size); + if (stat.kind != .file or stat.size == 0) { + package_json_file = null; + node.end(); + + progress.refresh(); + break :read_package_json; + } + + break :brk stat.size; + }; + + package_json_contents = try MutableString.init(ctx.allocator, size); package_json_contents.list.expandToCapacity(); _ = pkg.preadAll(package_json_contents.list.items, 0) catch |err| { @@ -1717,36 +1730,36 @@ pub const Example = struct { { var folders = [3]std.fs.IterableDir{ .{ - .dir = .{ .fd = 0 }, + .dir = .{ .fd = bun.fdcast(bun.invalid_fd) }, }, .{ - .dir = .{ .fd = 0 }, + .dir = .{ .fd = bun.fdcast(bun.invalid_fd) }, }, - .{ .dir = .{ .fd = 0 } }, + .{ .dir = .{ .fd = bun.fdcast(bun.invalid_fd) } }, }; if (env_loader.map.get("BUN_CREATE_DIR")) |home_dir| { var parts = [_]string{home_dir}; var outdir_path = filesystem.absBuf(&parts, &home_dir_buf); - folders[0] = std.fs.cwd().openIterableDir(outdir_path, .{}) catch .{ .dir = .{ .fd = 0 } }; + folders[0] = std.fs.cwd().openIterableDir(outdir_path, .{}) catch .{ .dir = .{ .fd = bun.fdcast(bun.invalid_fd) } }; } { var parts = [_]string{ filesystem.top_level_dir, BUN_CREATE_DIR }; var outdir_path = filesystem.absBuf(&parts, &home_dir_buf); - folders[1] = std.fs.cwd().openIterableDir(outdir_path, .{}) catch .{ .dir = .{ .fd = 0 } }; + folders[1] = std.fs.cwd().openIterableDir(outdir_path, .{}) catch .{ .dir = .{ .fd = bun.fdcast(bun.invalid_fd) } }; } if (env_loader.map.get("HOME")) |home_dir| { var parts = [_]string{ home_dir, BUN_CREATE_DIR }; var outdir_path = filesystem.absBuf(&parts, &home_dir_buf); - folders[2] = std.fs.cwd().openIterableDir(outdir_path, .{}) catch .{ .dir = .{ .fd = 0 } }; + folders[2] = std.fs.cwd().openIterableDir(outdir_path, .{}) catch .{ .dir = .{ .fd = bun.fdcast(bun.invalid_fd) } }; } // subfolders with package.json for (folders) |folder__| { const folder_ = folder__.dir; - if (folder_.fd != 0) { + if (folder_.fd != bun.fdcast(bun.invalid_fd)) { const folder: std.fs.Dir = folder_; var iter = (std.fs.IterableDir{ .dir = folder }).iterate(); diff --git a/src/cli/dev_command.zig b/src/cli/dev_command.zig index 9fb846fe7..91c9fda3d 100644 --- a/src/cli/dev_command.zig +++ b/src/cli/dev_command.zig @@ -1,8 +1,11 @@ -const Server = @import("../http.zig").Server; const Command = @import("../cli.zig").Command; -const Global = @import("root").bun.Global; + pub const DevCommand = struct { pub fn exec(ctx: Command.Context) !void { + if (comptime @import("root").bun.Environment.isWindows) unreachable; + + const Server = @import("../bun_dev_http_server.zig").Server; + const Global = @import("root").bun.Global; Global.configureAllocator(.{ .long_running = true }); try Server.start(ctx.allocator, ctx.args, @TypeOf(ctx.debug), ctx.debug); } diff --git a/src/cli/init_command.zig b/src/cli/init_command.zig index 6f1fced54..8d65461a7 100644 --- a/src/cli/init_command.zig +++ b/src/cli/init_command.zig @@ -110,12 +110,25 @@ pub const InitCommand = struct { initializeStore(); read_package_json: { if (package_json_file) |pkg| { - const stat = pkg.stat() catch break :read_package_json; + const size = brk: { + if (comptime bun.Environment.isWindows) { + const end = pkg.getEndPos() catch break :read_package_json; + if (end == 0) { + break :read_package_json; + } + + break :brk end; + } + const stat = pkg.stat() catch break :read_package_json; - if (stat.kind != .file or stat.size == 0) { - break :read_package_json; - } - package_json_contents = try MutableString.init(alloc, stat.size); + if (stat.kind != .file or stat.size == 0) { + break :read_package_json; + } + + break :brk stat.size; + }; + + package_json_contents = try MutableString.init(alloc, size); package_json_contents.list.expandToCapacity(); _ = pkg.preadAll(package_json_contents.list.items, 0) catch { diff --git a/src/cli/install_completions_command.zig b/src/cli/install_completions_command.zig index 7e19d12f1..1d67a7b39 100644 --- a/src/cli/install_completions_command.zig +++ b/src/cli/install_completions_command.zig @@ -45,6 +45,11 @@ pub const InstallCompletionsCommand = struct { pub fn testPath(_: string) !std.fs.Dir {} fn installBunxSymlink(allocator: std.mem.Allocator, cwd: []const u8) !void { + if (comptime Environment.isWindows) { + bun.todo(@src(), {}); + return; + } + var buf: [bun.MAX_PATH_BYTES]u8 = undefined; const bunx_name = if (Environment.isDebug) "bunx-debug" else "bunx"; @@ -133,10 +138,10 @@ pub const InstallCompletionsCommand = struct { var completions_dir: string = ""; var output_dir: std.fs.IterableDir = found: { - for (std.os.argv, 0..) |arg, i| { + for (bun.argv(), 0..) |arg, i| { if (strings.eqlComptime(std.mem.span(arg), "completions")) { - if (std.os.argv.len > i + 1) { - const input = std.mem.span(std.os.argv[i + 1]); + if (bun.argv().len > i + 1) { + const input = std.mem.span(bun.argv()[i + 1]); if (!std.fs.path.isAbsolute(input)) { completions_dir = resolve_path.joinAbs( diff --git a/src/cli/run_command.zig b/src/cli/run_command.zig index ba05e1ddf..17eb13dcb 100644 --- a/src/cli/run_command.zig +++ b/src/cli/run_command.zig @@ -50,6 +50,10 @@ pub const RunCommand = struct { }; pub fn findShell(PATH: string, cwd: string) ?string { + if (comptime Environment.isWindows) { + return "C:\\Windows\\System32\\cmd.exe"; + } + inline for (shells_to_search) |shell| { if (which(&path_buf, PATH, cwd, shell)) |shell_| { return shell_; @@ -58,8 +62,7 @@ pub const RunCommand = struct { const Try = struct { pub fn shell(str: stringZ) bool { - std.os.accessZ(str, std.os.X_OK) catch return false; - return true; + return bun.sys.isExecutableFilePath(str); } }; @@ -341,7 +344,7 @@ pub const RunCommand = struct { const result = child_process.spawnAndWait() catch |err| { if (err == error.AccessDenied) { - { + if (comptime Environment.isPosix) { var stat = std.mem.zeroes(std.c.Stat); const rc = bun.C.stat(executable[0.. :0].ptr, &stat); if (rc == 0) { @@ -408,16 +411,21 @@ pub const RunCommand = struct { var self_exe_bin_path_buf: [bun.MAX_PATH_BYTES + 1]u8 = undefined; fn createFakeTemporaryNodeExecutable(PATH: *std.ArrayList(u8), optional_bun_path: *string) !void { + if (comptime Environment.isWindows) { + bun.todo(@src(), {}); + return; + } + var retried = false; - if (!strings.endsWithComptime(std.mem.span(std.os.argv[0]), "node")) { + if (!strings.endsWithComptime(std.mem.span(bun.argv()[0]), "node")) { var argv0 = @as([*:0]const u8, @ptrCast(optional_bun_path.ptr)); // if we are already an absolute path, use that // if the user started the application via a shebang, it's likely that the path is absolute already - if (std.os.argv[0][0] == '/') { - optional_bun_path.* = bun.span(std.os.argv[0]); - argv0 = std.os.argv[0]; + if (bun.argv()[0][0] == '/') { + optional_bun_path.* = bun.span(bun.argv()[0]); + argv0 = bun.argv()[0]; } else if (optional_bun_path.len == 0) { // otherwise, ask the OS for the absolute path var self = std.fs.selfExePath(&self_exe_bin_path_buf) catch unreachable; @@ -429,7 +437,7 @@ pub const RunCommand = struct { } if (optional_bun_path.len == 0) { - argv0 = std.os.argv[0]; + argv0 = bun.argv()[0]; } while (true) { @@ -445,7 +453,8 @@ pub const RunCommand = struct { continue; }; } - _ = bun.C.chmod(bun_node_dir ++ "/node", 0o777); + if (comptime Environment.isPosix) + _ = bun.C.chmod(bun_node_dir ++ "/node", 0o777); break; } } @@ -723,7 +732,7 @@ pub const RunCommand = struct { bun.copy(u8, path_buf[dir_slice.len..], base); path_buf[dir_slice.len + base.len] = 0; var slice = path_buf[0 .. dir_slice.len + base.len :0]; - std.os.accessZ(slice, std.os.X_OK) catch continue; + if (!(bun.sys.isExecutableFilePath(slice))) continue; // we need to dupe because the string pay point to a pointer that only exists in the current scope _ = try results.getOrPut(this_bundler.fs.filename_store.append(@TypeOf(base), base) catch continue); } @@ -953,7 +962,7 @@ pub const RunCommand = struct { shebang = std.mem.trim(u8, shebang, " \r\n\t"); if (shebang.len == 0) break :possibly_open_with_bun_js; if (strings.hasPrefixComptime(shebang, "#!")) { - const first_arg: string = if (std.os.argv.len > 0) bun.span(std.os.argv[0]) else ""; + const first_arg: string = if (bun.argv().len > 0) bun.span(bun.argv()[0]) else ""; const filename = std.fs.path.basename(first_arg); // are we attempting to run the script with bun? if (!strings.contains(shebang, filename)) { diff --git a/src/cli/test_command.zig b/src/cli/test_command.zig index 53dd4c3c5..0af54f61b 100644 --- a/src/cli/test_command.zig +++ b/src/cli/test_command.zig @@ -401,7 +401,7 @@ const Scanner = struct { if (@as(FileSystem.RealFS.EntriesOption.Tag, root.*) == .entries) { var iter = root.entries.data.iterator(); const fd = root.entries.fd; - std.debug.assert(fd != 0); + std.debug.assert(fd != bun.invalid_fd); while (iter.next()) |entry| { this.next(entry.value_ptr.*, fd); } @@ -409,8 +409,8 @@ const Scanner = struct { } while (this.dirs_to_scan.readItem()) |entry| { - var dir = std.fs.Dir{ .fd = entry.relative_dir }; - std.debug.assert(dir.fd != 0); + var dir = std.fs.Dir{ .fd = bun.fdcast(entry.relative_dir) }; + std.debug.assert(bun.toFD(dir.fd) != bun.invalid_fd); var parts2 = &[_]string{ entry.dir_path, entry.name.slice() }; var path2 = this.fs.absBuf(parts2, &this.open_dir_buf); diff --git a/src/cli/upgrade_command.zig b/src/cli/upgrade_command.zig index 79a7777f3..c48e32aca 100644 --- a/src/cli/upgrade_command.zig +++ b/src/cli/upgrade_command.zig @@ -408,14 +408,14 @@ pub const UpgradeCommand = struct { const use_canary = brk: { const default_use_canary = Environment.is_canary; - if (default_use_canary and strings.containsAny(bun.span(std.os.argv), "--stable")) + if (default_use_canary and strings.containsAny(bun.span(bun.argv()), "--stable")) break :brk false; break :brk strings.eqlComptime(env_loader.map.get("BUN_CANARY") orelse "0", "1") or - strings.containsAny(bun.span(std.os.argv), "--canary") or default_use_canary; + strings.containsAny(bun.span(bun.argv()), "--canary") or default_use_canary; }; - const use_profile = strings.containsAny(bun.span(std.os.argv), "--profile"); + const use_profile = strings.containsAny(bun.span(bun.argv()), "--profile"); if (!use_canary) { var refresher = std.Progress{}; @@ -532,7 +532,7 @@ pub const UpgradeCommand = struct { tmpdir_path_buf[tmpdir_path.len] = 0; var tmpdir_z = tmpdir_path_buf[0..tmpdir_path.len :0]; - std.os.chdirZ(tmpdir_z) catch {}; + _ = bun.sys.chdir(tmpdir_z); const tmpname = "bun.zip"; const exe = diff --git a/src/crash_reporter.zig b/src/crash_reporter.zig index 882ec0ba6..8eb73d4c5 100644 --- a/src/crash_reporter.zig +++ b/src/crash_reporter.zig @@ -33,6 +33,9 @@ noinline fn sigpipe_handler(_: i32, _: *const std.os.siginfo_t, _: ?*const anyop } pub fn reloadHandlers() !void { + if (comptime @import("root").bun.Environment.isWindows) { + return @import("root").bun.todo(@src(), {}); + } try os.sigaction(os.SIG.PIPE, null, null); try setup_sigactions(null); diff --git a/src/css_scanner.zig b/src/css_scanner.zig index d8e827d03..45651d849 100644 --- a/src/css_scanner.zig +++ b/src/css_scanner.zig @@ -1255,8 +1255,13 @@ pub fn NewBundler( pub fn getSource(this: *CSSBundler, url: string, input_fd: ?StoredFileDescriptorType) !logger.Source { const entry = try this.fs_reader.readFile(this.fs, url, 0, true, input_fd); - const file = Fs.File{ .path = Fs.Path.init(url), .contents = entry.contents }; - return logger.Source.initFile(file, this.allocator); + return logger.Source.initFile( + .{ + .path = Fs.Path.init(url), + .contents = entry.contents, + }, + this.allocator, + ); } pub fn addCSSImport(this: *CSSBundler, absolute_path: string) anyerror!void { diff --git a/src/darwin_c.zig b/src/darwin_c.zig index 88fd4f8bd..4b140560d 100644 --- a/src/darwin_c.zig +++ b/src/darwin_c.zig @@ -482,12 +482,12 @@ pub const kFSEventStreamEventFlagRootChanged: c_int = 32; pub const kFSEventStreamEventFlagUnmount: c_int = 128; pub const kFSEventStreamEventFlagUserDropped: c_int = 2; -pub fn get_free_memory() u64 { +pub fn getFreeMemory() u64 { // NOT IMPLEMENTED YET return 1024 * 1024; } -pub fn get_total_memory() u64 { +pub fn getTotalMemory() u64 { var memory_: [32]c_ulonglong = undefined; var size: usize = memory_.len; @@ -507,7 +507,7 @@ pub fn get_total_memory() u64 { pub const struct_BootTime = struct { sec: u32, }; -pub fn get_system_uptime() u64 { +pub fn getSystemUptime() u64 { var uptime_: [16]struct_BootTime = undefined; var size: usize = uptime_.len; @@ -528,7 +528,7 @@ pub const struct_LoadAvg = struct { ldavg: [3]u32, fscale: c_long, }; -pub fn get_system_loadavg() [3]f64 { +pub fn getSystemLoadavg() [3]f64 { var loadavg_: [24]struct_LoadAvg = undefined; var size: usize = loadavg_.len; @@ -793,3 +793,10 @@ pub usingnamespace @cImport({ // it turns out preallocating on APFS on an M1 is slower. // so this is a linux-only optimization for now. pub const preallocate_length = std.math.maxInt(u51); + +pub const Mode = std.os.mode_t; + +pub const E = std.os.E; +pub fn getErrno(rc: anytype) E { + return std.c.getErrno(rc); +} diff --git a/src/deps/boringssl.translated.zig b/src/deps/boringssl.translated.zig index 68d4215b4..bc92a9981 100644 --- a/src/deps/boringssl.translated.zig +++ b/src/deps/boringssl.translated.zig @@ -1,6 +1,6 @@ const std = @import("std"); const C = @import("std").zig.c_builtins; -const pthread_rwlock_t = @import("../sync.zig").RwLock.pthread_rwlock_t; +const pthread_rwlock_t = if (@import("root").bun.Environment.isPosix) @import("../sync.zig").RwLock.pthread_rwlock_t else *anyopaque; const time_t = C.time_t; const va_list = C.va_list; const struct_timeval = C.struct_timeval; diff --git a/src/deps/c_ares.zig b/src/deps/c_ares.zig index 777827662..dc92e0cde 100644 --- a/src/deps/c_ares.zig +++ b/src/deps/c_ares.zig @@ -1197,6 +1197,10 @@ pub const Error = enum(i32) { ESERVICE = ARES_ESERVICE, pub fn initEAI(rc: i32) ?Error { + if (comptime bun.Environment.isWindows) { + return bun.todo(@src(), Error.ENOTIMP); + } + return switch (@as(std.os.system.EAI, @enumFromInt(rc))) { @as(std.os.system.EAI, @enumFromInt(0)) => return null, .ADDRFAMILY => Error.EBADFAMILY, diff --git a/src/deps/uws.zig b/src/deps/uws.zig index 3f1fb276c..88c649747 100644 --- a/src/deps/uws.zig +++ b/src/deps/uws.zig @@ -748,7 +748,14 @@ pub const Loop = extern struct { /// The list of ready polls ready_polls: [1024]EventType align(16), - const EventType = if (Environment.isLinux) std.os.linux.epoll_event else if (Environment.isMac) std.os.system.kevent64_s; + const EventType = switch (Environment.os) { + .linux => std.os.linux.epoll_event, + .mac => std.os.system.kevent64_s, + // TODO: + .windows => *anyopaque, + else => @compileError("Unsupported OS"), + }; + const log = bun.Output.scoped(.Loop, false); pub const InternalLoopData = extern struct { diff --git a/src/deps/zig-clap/clap/args.zig b/src/deps/zig-clap/clap/args.zig index d315582bb..045ae9540 100644 --- a/src/deps/zig-clap/clap/args.zig +++ b/src/deps/zig-clap/clap/args.zig @@ -43,13 +43,14 @@ test "SliceIterator" { } } +const bun = @import("root").bun; /// An argument iterator which wraps the ArgIterator in ::std. /// On windows, this iterator allocates. pub const OsIterator = struct { const Error = process.ArgIterator.InitError; arena: @import("root").bun.ArenaAllocator, - args: process.ArgIterator, + remain: [][*:0]u8, /// The executable path (this is the first argument passed to the program) /// TODO: Is it the right choice for this to be null? Maybe `init` should @@ -59,8 +60,8 @@ pub const OsIterator = struct { pub fn init(allocator: mem.Allocator) OsIterator { var res = OsIterator{ .arena = @import("root").bun.ArenaAllocator.init(allocator), - .args = process.args(), .exe_arg = undefined, + .remain = bun.argv(), }; res.exe_arg = res.next(); return res; @@ -71,7 +72,13 @@ pub const OsIterator = struct { } pub fn next(iter: *OsIterator) ?[:0]const u8 { - return iter.args.next(); + if (iter.remain.len > 0) { + const res = bun.sliceTo(iter.remain[0], 0); + iter.remain = iter.remain[1..]; + return res; + } + + return null; } }; diff --git a/src/deps/zig-clap/clap/comptime.zig b/src/deps/zig-clap/clap/comptime.zig index 71e0d1b54..d32a60f11 100644 --- a/src/deps/zig-clap/clap/comptime.zig +++ b/src/deps/zig-clap/clap/comptime.zig @@ -1,4 +1,5 @@ const clap = @import("../clap.zig"); +const bun = @import("root").bun; const std = @import("std"); const debug = std.debug; @@ -76,12 +77,7 @@ pub fn ComptimeClap( if (param.names.long == null and param.names.short == null) { try pos.append(arg.value.?); if (opt.stop_after_positional_at > 0 and pos.items.len >= opt.stop_after_positional_at) { - const bun = @import("root").bun; - if (comptime bun.Environment.isWindows) @compileError( - "TODO: implement stop_after_positional_at on windows", - ); - - var remaining_ = std.os.argv[@min(std.os.argv.len, stream.iter.args.inner.index)..]; + var remaining_ = stream.iter.remain; const first: []const u8 = if (remaining_.len > 0) bun.span(remaining_[0]) else ""; if (first.len > 0 and std.mem.eql(u8, first, "--")) { remaining_ = remaining_[1..]; diff --git a/src/enums.zig b/src/enums.zig new file mode 100644 index 000000000..2d261526b --- /dev/null +++ b/src/enums.zig @@ -0,0 +1,1439 @@ +// This is a copy-paste of the same file from Zig's standard library. +// This exists mostly as a workaround for https://github.com/ziglang/zig/issues/16980 + +const std = @import("std"); +const assert = std.debug.assert; +const testing = std.testing; +const EnumField = std.builtin.Type.EnumField; + +/// Returns a struct with a field matching each unique named enum element. +/// If the enum is extern and has multiple names for the same value, only +/// the first name is used. Each field is of type Data and has the provided +/// default, which may be undefined. +pub fn EnumFieldStruct(comptime E: type, comptime Data: type, comptime field_default: ?Data) type { + const StructField = std.builtin.Type.StructField; + var fields: []const StructField = &[_]StructField{}; + for (std.meta.fields(E)) |field| { + fields = fields ++ &[_]StructField{.{ + .name = field.name, + .type = Data, + .default_value = if (field_default) |d| @as(?*const anyopaque, @ptrCast(&d)) else null, + .is_comptime = false, + .alignment = if (@sizeOf(Data) > 0) @alignOf(Data) else 0, + }}; + } + return @Type(.{ .Struct = .{ + .layout = .Auto, + .fields = fields, + .decls = &.{}, + .is_tuple = false, + } }); +} + +/// Looks up the supplied fields in the given enum type. +/// Uses only the field names, field values are ignored. +/// The result array is in the same order as the input. +pub inline fn valuesFromFields(comptime E: type, comptime fields: []const EnumField) []const E { + comptime { + var result: [fields.len]E = undefined; + for (fields, 0..) |f, i| { + result[i] = @field(E, f.name); + } + return &result; + } +} + +/// Returns the set of all named values in the given enum, in +/// declaration order. +pub fn values(comptime E: type) []const E { + return comptime valuesFromFields(E, @typeInfo(E).Enum.fields); +} + +/// A safe alternative to @tagName() for non-exhaustive enums that doesn't +/// panic when `e` has no tagged value. +/// Returns the tag name for `e` or null if no tag exists. +pub fn tagName(comptime E: type, e: E) ?[]const u8 { + return inline for (@typeInfo(E).Enum.fields) |f| { + if (@intFromEnum(e) == f.value) break f.name; + } else null; +} + +test tagName { + const E = enum(u8) { a, b, _ }; + try testing.expect(tagName(E, .a) != null); + try testing.expectEqualStrings("a", tagName(E, .a).?); + try testing.expect(tagName(E, @as(E, @enumFromInt(42))) == null); +} + +/// Determines the length of a direct-mapped enum array, indexed by +/// @intCast(usize, @intFromEnum(enum_value)). +/// If the enum is non-exhaustive, the resulting length will only be enough +/// to hold all explicit fields. +/// If the enum contains any fields with values that cannot be represented +/// by usize, a compile error is issued. The max_unused_slots parameter limits +/// the total number of items which have no matching enum key (holes in the enum +/// numbering). So for example, if an enum has values 1, 2, 5, and 6, max_unused_slots +/// must be at least 3, to allow unused slots 0, 3, and 4. +pub fn directEnumArrayLen(comptime E: type, comptime max_unused_slots: comptime_int) comptime_int { + var max_value: comptime_int = -1; + const max_usize: comptime_int = ~@as(usize, 0); + const fields = std.meta.fields(E); + for (fields) |f| { + if (f.value < 0) { + @compileError("Cannot create a direct enum array for " ++ @typeName(E) ++ ", field ." ++ f.name ++ " has a negative value."); + } + if (f.value > max_value) { + if (f.value > max_usize) { + @compileError("Cannot create a direct enum array for " ++ @typeName(E) ++ ", field ." ++ f.name ++ " is larger than the max value of usize."); + } + max_value = f.value; + } + } + + const unused_slots = max_value + 1 - fields.len; + if (unused_slots > max_unused_slots) { + const unused_str = std.fmt.comptimePrint("{d}", .{unused_slots}); + const allowed_str = std.fmt.comptimePrint("{d}", .{max_unused_slots}); + @compileError("Cannot create a direct enum array for " ++ @typeName(E) ++ ". It would have " ++ unused_str ++ " unused slots, but only " ++ allowed_str ++ " are allowed."); + } + + return max_value + 1; +} + +/// Initializes an array of Data which can be indexed by +/// @intCast(usize, @intFromEnum(enum_value)). +/// If the enum is non-exhaustive, the resulting array will only be large enough +/// to hold all explicit fields. +/// If the enum contains any fields with values that cannot be represented +/// by usize, a compile error is issued. The max_unused_slots parameter limits +/// the total number of items which have no matching enum key (holes in the enum +/// numbering). So for example, if an enum has values 1, 2, 5, and 6, max_unused_slots +/// must be at least 3, to allow unused slots 0, 3, and 4. +/// The init_values parameter must be a struct with field names that match the enum values. +/// If the enum has multiple fields with the same value, the name of the first one must +/// be used. +pub fn directEnumArray( + comptime E: type, + comptime Data: type, + comptime max_unused_slots: comptime_int, + init_values: EnumFieldStruct(E, Data, null), +) [directEnumArrayLen(E, max_unused_slots)]Data { + return directEnumArrayDefault(E, Data, null, max_unused_slots, init_values); +} + +test "std.enums.directEnumArray" { + const E = enum(i4) { a = 4, b = 6, c = 2 }; + var runtime_false: bool = false; + const array = directEnumArray(E, bool, 4, .{ + .a = true, + .b = runtime_false, + .c = true, + }); + + try testing.expectEqual([7]bool, @TypeOf(array)); + try testing.expectEqual(true, array[4]); + try testing.expectEqual(false, array[6]); + try testing.expectEqual(true, array[2]); +} + +/// Initializes an array of Data which can be indexed by +/// @intCast(usize, @intFromEnum(enum_value)). The enum must be exhaustive. +/// If the enum contains any fields with values that cannot be represented +/// by usize, a compile error is issued. The max_unused_slots parameter limits +/// the total number of items which have no matching enum key (holes in the enum +/// numbering). So for example, if an enum has values 1, 2, 5, and 6, max_unused_slots +/// must be at least 3, to allow unused slots 0, 3, and 4. +/// The init_values parameter must be a struct with field names that match the enum values. +/// If the enum has multiple fields with the same value, the name of the first one must +/// be used. +pub fn directEnumArrayDefault( + comptime E: type, + comptime Data: type, + comptime default: ?Data, + comptime max_unused_slots: comptime_int, + init_values: EnumFieldStruct(E, Data, default), +) [directEnumArrayLen(E, max_unused_slots)]Data { + const len = comptime directEnumArrayLen(E, max_unused_slots); + var result: [len]Data = if (default) |d| [_]Data{d} ** len else undefined; + inline for (@typeInfo(@TypeOf(init_values)).Struct.fields) |f| { + const enum_value = @field(E, f.name); + const index = @as(usize, @intCast(@intFromEnum(enum_value))); + result[index] = @field(init_values, f.name); + } + return result; +} + +test "std.enums.directEnumArrayDefault" { + const E = enum(i4) { a = 4, b = 6, c = 2 }; + var runtime_false: bool = false; + const array = directEnumArrayDefault(E, bool, false, 4, .{ + .a = true, + .b = runtime_false, + }); + + try testing.expectEqual([7]bool, @TypeOf(array)); + try testing.expectEqual(true, array[4]); + try testing.expectEqual(false, array[6]); + try testing.expectEqual(false, array[2]); +} + +test "std.enums.directEnumArrayDefault slice" { + const E = enum(i4) { a = 4, b = 6, c = 2 }; + var runtime_b = "b"; + const array = directEnumArrayDefault(E, []const u8, "default", 4, .{ + .a = "a", + .b = runtime_b, + }); + + try testing.expectEqual([7][]const u8, @TypeOf(array)); + try testing.expectEqualSlices(u8, "a", array[4]); + try testing.expectEqualSlices(u8, "b", array[6]); + try testing.expectEqualSlices(u8, "default", array[2]); +} + +/// Cast an enum literal, value, or string to the enum value of type E +/// with the same name. +pub fn nameCast(comptime E: type, comptime value: anytype) E { + return comptime blk: { + const V = @TypeOf(value); + if (V == E) break :blk value; + var name: ?[]const u8 = switch (@typeInfo(V)) { + .EnumLiteral, .Enum => @tagName(value), + .Pointer => if (std.meta.trait.isZigString(V)) value else null, + else => null, + }; + if (name) |n| { + if (@hasField(E, n)) { + break :blk @field(E, n); + } + @compileError("Enum " ++ @typeName(E) ++ " has no field named " ++ n); + } + @compileError("Cannot cast from " ++ @typeName(@TypeOf(value)) ++ " to " ++ @typeName(E)); + }; +} + +test "std.enums.nameCast" { + const A = enum(u1) { a = 0, b = 1 }; + const B = enum(u1) { a = 1, b = 0 }; + try testing.expectEqual(A.a, nameCast(A, .a)); + try testing.expectEqual(A.a, nameCast(A, A.a)); + try testing.expectEqual(A.a, nameCast(A, B.a)); + try testing.expectEqual(A.a, nameCast(A, "a")); + try testing.expectEqual(A.a, nameCast(A, @as(*const [1]u8, "a"))); + try testing.expectEqual(A.a, nameCast(A, @as([:0]const u8, "a"))); + try testing.expectEqual(A.a, nameCast(A, @as([]const u8, "a"))); + + try testing.expectEqual(B.a, nameCast(B, .a)); + try testing.expectEqual(B.a, nameCast(B, A.a)); + try testing.expectEqual(B.a, nameCast(B, B.a)); + try testing.expectEqual(B.a, nameCast(B, "a")); + + try testing.expectEqual(B.b, nameCast(B, .b)); + try testing.expectEqual(B.b, nameCast(B, A.b)); + try testing.expectEqual(B.b, nameCast(B, B.b)); + try testing.expectEqual(B.b, nameCast(B, "b")); +} + +/// A set of enum elements, backed by a bitfield. If the enum +/// is not dense, a mapping will be constructed from enum values +/// to dense indices. This type does no dynamic allocation and +/// can be copied by value. +pub fn EnumSet(comptime E: type) type { + const mixin = struct { + fn EnumSetExt(comptime Self: type) type { + const Indexer = Self.Indexer; + return struct { + /// Initializes the set using a struct of bools + pub fn init(init_values: EnumFieldStruct(E, bool, false)) Self { + var result = Self{}; + comptime var i: usize = 0; + inline while (i < Self.len) : (i += 1) { + const key = comptime Indexer.keyForIndex(i); + const tag = comptime @tagName(key); + if (@field(init_values, tag)) { + result.bits.set(i); + } + } + return result; + } + }; + } + }; + return IndexedSet(EnumIndexer(E), mixin.EnumSetExt); +} + +/// A map keyed by an enum, backed by a bitfield and a dense array. +/// If the enum is not dense, a mapping will be constructed from +/// enum values to dense indices. This type does no dynamic +/// allocation and can be copied by value. +pub fn EnumMap(comptime E: type, comptime V: type) type { + const mixin = struct { + fn EnumMapExt(comptime Self: type) type { + const Indexer = Self.Indexer; + return struct { + /// Initializes the map using a sparse struct of optionals + pub fn init(init_values: EnumFieldStruct(E, ?V, @as(?V, null))) Self { + var result = Self{}; + comptime var i: usize = 0; + inline while (i < Self.len) : (i += 1) { + const key = comptime Indexer.keyForIndex(i); + const tag = comptime @tagName(key); + if (@field(init_values, tag)) |*v| { + result.bits.set(i); + result.values[i] = v.*; + } + } + return result; + } + /// Initializes a full mapping with all keys set to value. + /// Consider using EnumArray instead if the map will remain full. + pub fn initFull(value: V) Self { + var result = Self{ + .bits = Self.BitSet.initFull(), + .values = undefined, + }; + @memset(&result.values, value); + return result; + } + /// Initializes a full mapping with supplied values. + /// Consider using EnumArray instead if the map will remain full. + pub fn initFullWith(init_values: EnumFieldStruct(E, V, @as(?V, null))) Self { + return initFullWithDefault(@as(?V, null), init_values); + } + /// Initializes a full mapping with a provided default. + /// Consider using EnumArray instead if the map will remain full. + pub fn initFullWithDefault(comptime default: ?V, init_values: EnumFieldStruct(E, V, default)) Self { + var result = Self{ + .bits = Self.BitSet.initFull(), + .values = undefined, + }; + comptime var i: usize = 0; + inline while (i < Self.len) : (i += 1) { + const key = comptime Indexer.keyForIndex(i); + const tag = comptime @tagName(key); + result.values[i] = @field(init_values, tag); + } + return result; + } + }; + } + }; + return IndexedMap(EnumIndexer(E), V, mixin.EnumMapExt); +} + +/// A multiset of enum elements up to a count of usize. Backed +/// by an EnumArray. This type does no dynamic allocation and can +/// be copied by value. +pub fn EnumMultiset(comptime E: type) type { + return BoundedEnumMultiset(E, usize); +} + +/// A multiset of enum elements up to CountSize. Backed by an +/// EnumArray. This type does no dynamic allocation and can be +/// copied by value. +pub fn BoundedEnumMultiset(comptime E: type, comptime CountSize: type) type { + return struct { + const Self = @This(); + + counts: EnumArray(E, CountSize), + + /// Initializes the multiset using a struct of counts. + pub fn init(init_counts: EnumFieldStruct(E, CountSize, 0)) Self { + var self = initWithCount(0); + inline for (@typeInfo(E).Enum.fields) |field| { + const c = @field(init_counts, field.name); + const key = @as(E, @enumFromInt(field.value)); + self.counts.set(key, c); + } + return self; + } + + /// Initializes the multiset with a count of zero. + pub fn initEmpty() Self { + return initWithCount(0); + } + + /// Initializes the multiset with all keys at the + /// same count. + pub fn initWithCount(comptime c: CountSize) Self { + return .{ + .counts = EnumArray(E, CountSize).initDefault(c, .{}), + }; + } + + /// Returns the total number of key counts in the multiset. + pub fn count(self: Self) usize { + var sum: usize = 0; + for (self.counts.values) |c| { + sum += c; + } + return sum; + } + + /// Checks if at least one key in multiset. + pub fn contains(self: Self, key: E) bool { + return self.counts.get(key) > 0; + } + + /// Removes all instance of a key from multiset. Same as + /// setCount(key, 0). + pub fn removeAll(self: *Self, key: E) void { + return self.counts.set(key, 0); + } + + /// Increases the key count by given amount. Caller asserts + /// operation will not overflow. + pub fn addAssertSafe(self: *Self, key: E, c: CountSize) void { + self.counts.getPtr(key).* += c; + } + + /// Increases the key count by given amount. + pub fn add(self: *Self, key: E, c: CountSize) error{Overflow}!void { + self.counts.set(key, try std.math.add(CountSize, self.counts.get(key), c)); + } + + /// Decreases the key count by given amount. If amount is + /// greater than the number of keys in multset, then key count + /// will be set to zero. + pub fn remove(self: *Self, key: E, c: CountSize) void { + self.counts.getPtr(key).* -= @min(self.getCount(key), c); + } + + /// Returns the count for a key. + pub fn getCount(self: Self, key: E) CountSize { + return self.counts.get(key); + } + + /// Set the count for a key. + pub fn setCount(self: *Self, key: E, c: CountSize) void { + self.counts.set(key, c); + } + + /// Increases the all key counts by given multiset. Caller + /// asserts operation will not overflow any key. + pub fn addSetAssertSafe(self: *Self, other: Self) void { + inline for (@typeInfo(E).Enum.fields) |field| { + const key = @as(E, @enumFromInt(field.value)); + self.addAssertSafe(key, other.getCount(key)); + } + } + + /// Increases the all key counts by given multiset. + pub fn addSet(self: *Self, other: Self) error{Overflow}!void { + inline for (@typeInfo(E).Enum.fields) |field| { + const key = @as(E, @enumFromInt(field.value)); + try self.add(key, other.getCount(key)); + } + } + + /// Deccreases the all key counts by given multiset. If + /// the given multiset has more key counts than this, + /// then that key will have a key count of zero. + pub fn removeSet(self: *Self, other: Self) void { + inline for (@typeInfo(E).Enum.fields) |field| { + const key = @as(E, @enumFromInt(field.value)); + self.remove(key, other.getCount(key)); + } + } + + /// Returns true iff all key counts are the same as + /// given multiset. + pub fn eql(self: Self, other: Self) bool { + inline for (@typeInfo(E).Enum.fields) |field| { + const key = @as(E, @enumFromInt(field.value)); + if (self.getCount(key) != other.getCount(key)) { + return false; + } + } + return true; + } + + /// Returns true iff all key counts less than or + /// equal to the given multiset. + pub fn subsetOf(self: Self, other: Self) bool { + inline for (@typeInfo(E).Enum.fields) |field| { + const key = @as(E, @enumFromInt(field.value)); + if (self.getCount(key) > other.getCount(key)) { + return false; + } + } + return true; + } + + /// Returns true iff all key counts greater than or + /// equal to the given multiset. + pub fn supersetOf(self: Self, other: Self) bool { + inline for (@typeInfo(E).Enum.fields) |field| { + const key = @as(E, @enumFromInt(field.value)); + if (self.getCount(key) < other.getCount(key)) { + return false; + } + } + return true; + } + + /// Returns a multiset with the total key count of this + /// multiset and the other multiset. Caller asserts + /// operation will not overflow any key. + pub fn plusAssertSafe(self: Self, other: Self) Self { + var result = self; + result.addSetAssertSafe(other); + return result; + } + + /// Returns a multiset with the total key count of this + /// multiset and the other multiset. + pub fn plus(self: Self, other: Self) error{Overflow}!Self { + var result = self; + try result.addSet(other); + return result; + } + + /// Returns a multiset with the key count of this + /// multiset minus the corresponding key count in the + /// other multiset. If the other multiset contains + /// more key count than this set, that key will have + /// a count of zero. + pub fn minus(self: Self, other: Self) Self { + var result = self; + result.removeSet(other); + return result; + } + + pub const Entry = EnumArray(E, CountSize).Entry; + pub const Iterator = EnumArray(E, CountSize).Iterator; + + /// Returns an iterator over this multiset. Keys with zero + /// counts are included. Modifications to the set during + /// iteration may or may not be observed by the iterator, + /// but will not invalidate it. + pub fn iterator(self: *Self) Iterator { + return self.counts.iterator(); + } + }; +} + +test "EnumMultiset" { + const Ball = enum { red, green, blue }; + + const empty = EnumMultiset(Ball).initEmpty(); + const r0_g1_b2 = EnumMultiset(Ball).init(.{ + .red = 0, + .green = 1, + .blue = 2, + }); + const ten_of_each = EnumMultiset(Ball).initWithCount(10); + + try testing.expectEqual(empty.count(), 0); + try testing.expectEqual(r0_g1_b2.count(), 3); + try testing.expectEqual(ten_of_each.count(), 30); + + try testing.expect(!empty.contains(.red)); + try testing.expect(!empty.contains(.green)); + try testing.expect(!empty.contains(.blue)); + + try testing.expect(!r0_g1_b2.contains(.red)); + try testing.expect(r0_g1_b2.contains(.green)); + try testing.expect(r0_g1_b2.contains(.blue)); + + try testing.expect(ten_of_each.contains(.red)); + try testing.expect(ten_of_each.contains(.green)); + try testing.expect(ten_of_each.contains(.blue)); + + { + var copy = ten_of_each; + copy.removeAll(.red); + try testing.expect(!copy.contains(.red)); + + // removeAll second time does nothing + copy.removeAll(.red); + try testing.expect(!copy.contains(.red)); + } + + { + var copy = ten_of_each; + copy.addAssertSafe(.red, 6); + try testing.expectEqual(copy.getCount(.red), 16); + } + + { + var copy = ten_of_each; + try copy.add(.red, 6); + try testing.expectEqual(copy.getCount(.red), 16); + + try testing.expectError(error.Overflow, copy.add(.red, std.math.maxInt(usize))); + } + + { + var copy = ten_of_each; + copy.remove(.red, 4); + try testing.expectEqual(copy.getCount(.red), 6); + + // subtracting more it contains does not underflow + copy.remove(.green, 14); + try testing.expectEqual(copy.getCount(.green), 0); + } + + try testing.expectEqual(empty.getCount(.green), 0); + try testing.expectEqual(r0_g1_b2.getCount(.green), 1); + try testing.expectEqual(ten_of_each.getCount(.green), 10); + + { + var copy = empty; + copy.setCount(.red, 6); + try testing.expectEqual(copy.getCount(.red), 6); + } + + { + var copy = r0_g1_b2; + copy.addSetAssertSafe(ten_of_each); + try testing.expectEqual(copy.getCount(.red), 10); + try testing.expectEqual(copy.getCount(.green), 11); + try testing.expectEqual(copy.getCount(.blue), 12); + } + + { + var copy = r0_g1_b2; + try copy.addSet(ten_of_each); + try testing.expectEqual(copy.getCount(.red), 10); + try testing.expectEqual(copy.getCount(.green), 11); + try testing.expectEqual(copy.getCount(.blue), 12); + + const full = EnumMultiset(Ball).initWithCount(std.math.maxInt(usize)); + try testing.expectError(error.Overflow, copy.addSet(full)); + } + + { + var copy = ten_of_each; + copy.removeSet(r0_g1_b2); + try testing.expectEqual(copy.getCount(.red), 10); + try testing.expectEqual(copy.getCount(.green), 9); + try testing.expectEqual(copy.getCount(.blue), 8); + + copy.removeSet(ten_of_each); + try testing.expectEqual(copy.getCount(.red), 0); + try testing.expectEqual(copy.getCount(.green), 0); + try testing.expectEqual(copy.getCount(.blue), 0); + } + + try testing.expect(empty.eql(empty)); + try testing.expect(r0_g1_b2.eql(r0_g1_b2)); + try testing.expect(ten_of_each.eql(ten_of_each)); + try testing.expect(!empty.eql(r0_g1_b2)); + try testing.expect(!r0_g1_b2.eql(ten_of_each)); + try testing.expect(!ten_of_each.eql(empty)); + + try testing.expect(empty.subsetOf(empty)); + try testing.expect(r0_g1_b2.subsetOf(r0_g1_b2)); + try testing.expect(empty.subsetOf(r0_g1_b2)); + try testing.expect(r0_g1_b2.subsetOf(ten_of_each)); + try testing.expect(!ten_of_each.subsetOf(r0_g1_b2)); + try testing.expect(!r0_g1_b2.subsetOf(empty)); + + try testing.expect(empty.supersetOf(empty)); + try testing.expect(r0_g1_b2.supersetOf(r0_g1_b2)); + try testing.expect(r0_g1_b2.supersetOf(empty)); + try testing.expect(ten_of_each.supersetOf(r0_g1_b2)); + try testing.expect(!r0_g1_b2.supersetOf(ten_of_each)); + try testing.expect(!empty.supersetOf(r0_g1_b2)); + + { + // with multisets it could be the case where two + // multisets are neither subset nor superset of each + // other. + + const r10 = EnumMultiset(Ball).init(.{ + .red = 10, + }); + const b10 = EnumMultiset(Ball).init(.{ + .blue = 10, + }); + + try testing.expect(!r10.subsetOf(b10)); + try testing.expect(!b10.subsetOf(r10)); + try testing.expect(!r10.supersetOf(b10)); + try testing.expect(!b10.supersetOf(r10)); + } + + { + const result = r0_g1_b2.plusAssertSafe(ten_of_each); + try testing.expectEqual(result.getCount(.red), 10); + try testing.expectEqual(result.getCount(.green), 11); + try testing.expectEqual(result.getCount(.blue), 12); + } + + { + const result = try r0_g1_b2.plus(ten_of_each); + try testing.expectEqual(result.getCount(.red), 10); + try testing.expectEqual(result.getCount(.green), 11); + try testing.expectEqual(result.getCount(.blue), 12); + + const full = EnumMultiset(Ball).initWithCount(std.math.maxInt(usize)); + try testing.expectError(error.Overflow, result.plus(full)); + } + + { + const result = ten_of_each.minus(r0_g1_b2); + try testing.expectEqual(result.getCount(.red), 10); + try testing.expectEqual(result.getCount(.green), 9); + try testing.expectEqual(result.getCount(.blue), 8); + } + + { + const result = ten_of_each.minus(r0_g1_b2).minus(ten_of_each); + try testing.expectEqual(result.getCount(.red), 0); + try testing.expectEqual(result.getCount(.green), 0); + try testing.expectEqual(result.getCount(.blue), 0); + } + + { + var copy = empty; + var it = copy.iterator(); + var entry = it.next().?; + try testing.expectEqual(entry.key, .red); + try testing.expectEqual(entry.value.*, 0); + entry = it.next().?; + try testing.expectEqual(entry.key, .green); + try testing.expectEqual(entry.value.*, 0); + entry = it.next().?; + try testing.expectEqual(entry.key, .blue); + try testing.expectEqual(entry.value.*, 0); + try testing.expectEqual(it.next(), null); + } + + { + var copy = r0_g1_b2; + var it = copy.iterator(); + var entry = it.next().?; + try testing.expectEqual(entry.key, .red); + try testing.expectEqual(entry.value.*, 0); + entry = it.next().?; + try testing.expectEqual(entry.key, .green); + try testing.expectEqual(entry.value.*, 1); + entry = it.next().?; + try testing.expectEqual(entry.key, .blue); + try testing.expectEqual(entry.value.*, 2); + try testing.expectEqual(it.next(), null); + } +} + +/// An array keyed by an enum, backed by a dense array. +/// If the enum is not dense, a mapping will be constructed from +/// enum values to dense indices. This type does no dynamic +/// allocation and can be copied by value. +pub fn EnumArray(comptime E: type, comptime V: type) type { + const mixin = struct { + fn EnumArrayExt(comptime Self: type) type { + const Indexer = Self.Indexer; + return struct { + /// Initializes all values in the enum array + pub fn init(init_values: EnumFieldStruct(E, V, @as(?V, null))) Self { + return initDefault(@as(?V, null), init_values); + } + + /// Initializes values in the enum array, with the specified default. + pub fn initDefault(comptime default: ?V, init_values: EnumFieldStruct(E, V, default)) Self { + var result = Self{ .values = undefined }; + comptime var i: usize = 0; + inline while (i < Self.len) : (i += 1) { + const key = comptime Indexer.keyForIndex(i); + const tag = @tagName(key); + result.values[i] = @field(init_values, tag); + } + return result; + } + }; + } + }; + return IndexedArray(EnumIndexer(E), V, mixin.EnumArrayExt); +} + +fn NoExtension(comptime Self: type) type { + _ = Self; + return NoExt; +} +const NoExt = struct {}; + +/// A set type with an Indexer mapping from keys to indices. +/// Presence or absence is stored as a dense bitfield. This +/// type does no allocation and can be copied by value. +pub fn IndexedSet(comptime I: type, comptime Ext: ?fn (type) type) type { + comptime ensureIndexer(I); + return struct { + const Self = @This(); + + pub usingnamespace (Ext orelse NoExtension)(Self); + + /// The indexing rules for converting between keys and indices. + pub const Indexer = I; + /// The element type for this set. + pub const Key = Indexer.Key; + + const BitSet = std.StaticBitSet(Indexer.count); + + /// The maximum number of items in this set. + pub const len = Indexer.count; + + bits: BitSet = BitSet.initEmpty(), + + /// Returns a set containing no keys. + pub fn initEmpty() Self { + return .{ .bits = BitSet.initEmpty() }; + } + + /// Returns a set containing all possible keys. + pub fn initFull() Self { + return .{ .bits = BitSet.initFull() }; + } + + /// Returns a set containing multiple keys. + pub fn initMany(keys: []const Key) Self { + var set = initEmpty(); + for (keys) |key| set.insert(key); + return set; + } + + /// Returns a set containing a single key. + pub fn initOne(key: Key) Self { + return initMany(&[_]Key{key}); + } + + /// Returns the number of keys in the set. + pub fn count(self: Self) usize { + return self.bits.count(); + } + + /// Checks if a key is in the set. + pub fn contains(self: Self, key: Key) bool { + return self.bits.isSet(Indexer.indexOf(key)); + } + + /// Puts a key in the set. + pub fn insert(self: *Self, key: Key) void { + self.bits.set(Indexer.indexOf(key)); + } + + /// Removes a key from the set. + pub fn remove(self: *Self, key: Key) void { + self.bits.unset(Indexer.indexOf(key)); + } + + /// Changes the presence of a key in the set to match the passed bool. + pub fn setPresent(self: *Self, key: Key, present: bool) void { + self.bits.setValue(Indexer.indexOf(key), present); + } + + /// Toggles the presence of a key in the set. If the key is in + /// the set, removes it. Otherwise adds it. + pub fn toggle(self: *Self, key: Key) void { + self.bits.toggle(Indexer.indexOf(key)); + } + + /// Toggles the presence of all keys in the passed set. + pub fn toggleSet(self: *Self, other: Self) void { + self.bits.toggleSet(other.bits); + } + + /// Toggles all possible keys in the set. + pub fn toggleAll(self: *Self) void { + self.bits.toggleAll(); + } + + /// Adds all keys in the passed set to this set. + pub fn setUnion(self: *Self, other: Self) void { + self.bits.setUnion(other.bits); + } + + /// Removes all keys which are not in the passed set. + pub fn setIntersection(self: *Self, other: Self) void { + self.bits.setIntersection(other.bits); + } + + /// Returns true iff both sets have the same keys. + pub fn eql(self: Self, other: Self) bool { + return self.bits.eql(other.bits); + } + + /// Returns true iff all the keys in this set are + /// in the other set. The other set may have keys + /// not found in this set. + pub fn subsetOf(self: Self, other: Self) bool { + return self.bits.subsetOf(other.bits); + } + + /// Returns true iff this set contains all the keys + /// in the other set. This set may have keys not + /// found in the other set. + pub fn supersetOf(self: Self, other: Self) bool { + return self.bits.supersetOf(other.bits); + } + + /// Returns a set with all the keys not in this set. + pub fn complement(self: Self) Self { + return .{ .bits = self.bits.complement() }; + } + + /// Returns a set with keys that are in either this + /// set or the other set. + pub fn unionWith(self: Self, other: Self) Self { + return .{ .bits = self.bits.unionWith(other.bits) }; + } + + /// Returns a set with keys that are in both this + /// set and the other set. + pub fn intersectWith(self: Self, other: Self) Self { + return .{ .bits = self.bits.intersectWith(other.bits) }; + } + + /// Returns a set with keys that are in either this + /// set or the other set, but not both. + pub fn xorWith(self: Self, other: Self) Self { + return .{ .bits = self.bits.xorWith(other.bits) }; + } + + /// Returns a set with keys that are in this set + /// except for keys in the other set. + pub fn differenceWith(self: Self, other: Self) Self { + return .{ .bits = self.bits.differenceWith(other.bits) }; + } + + /// Returns an iterator over this set, which iterates in + /// index order. Modifications to the set during iteration + /// may or may not be observed by the iterator, but will + /// not invalidate it. + pub fn iterator(self: *const Self) Iterator { + return .{ .inner = self.bits.iterator(.{}) }; + } + + pub const Iterator = struct { + inner: BitSet.Iterator(.{}), + + pub fn next(self: *Iterator) ?Key { + return if (self.inner.next()) |index| + Indexer.keyForIndex(index) + else + null; + } + }; + }; +} + +test "pure EnumSet fns" { + const Suit = enum { spades, hearts, clubs, diamonds }; + + const empty = EnumSet(Suit).initEmpty(); + const full = EnumSet(Suit).initFull(); + const black = EnumSet(Suit).initMany(&[_]Suit{ .spades, .clubs }); + const red = EnumSet(Suit).initMany(&[_]Suit{ .hearts, .diamonds }); + + try testing.expect(empty.eql(empty)); + try testing.expect(full.eql(full)); + try testing.expect(!empty.eql(full)); + try testing.expect(!full.eql(empty)); + try testing.expect(!empty.eql(black)); + try testing.expect(!full.eql(red)); + try testing.expect(!red.eql(empty)); + try testing.expect(!black.eql(full)); + + try testing.expect(empty.subsetOf(empty)); + try testing.expect(empty.subsetOf(full)); + try testing.expect(full.subsetOf(full)); + try testing.expect(!black.subsetOf(red)); + try testing.expect(!red.subsetOf(black)); + + try testing.expect(full.supersetOf(full)); + try testing.expect(full.supersetOf(empty)); + try testing.expect(empty.supersetOf(empty)); + try testing.expect(!black.supersetOf(red)); + try testing.expect(!red.supersetOf(black)); + + try testing.expect(empty.complement().eql(full)); + try testing.expect(full.complement().eql(empty)); + try testing.expect(black.complement().eql(red)); + try testing.expect(red.complement().eql(black)); + + try testing.expect(empty.unionWith(empty).eql(empty)); + try testing.expect(empty.unionWith(full).eql(full)); + try testing.expect(full.unionWith(full).eql(full)); + try testing.expect(full.unionWith(empty).eql(full)); + try testing.expect(black.unionWith(red).eql(full)); + try testing.expect(red.unionWith(black).eql(full)); + + try testing.expect(empty.intersectWith(empty).eql(empty)); + try testing.expect(empty.intersectWith(full).eql(empty)); + try testing.expect(full.intersectWith(full).eql(full)); + try testing.expect(full.intersectWith(empty).eql(empty)); + try testing.expect(black.intersectWith(red).eql(empty)); + try testing.expect(red.intersectWith(black).eql(empty)); + + try testing.expect(empty.xorWith(empty).eql(empty)); + try testing.expect(empty.xorWith(full).eql(full)); + try testing.expect(full.xorWith(full).eql(empty)); + try testing.expect(full.xorWith(empty).eql(full)); + try testing.expect(black.xorWith(red).eql(full)); + try testing.expect(red.xorWith(black).eql(full)); + + try testing.expect(empty.differenceWith(empty).eql(empty)); + try testing.expect(empty.differenceWith(full).eql(empty)); + try testing.expect(full.differenceWith(full).eql(empty)); + try testing.expect(full.differenceWith(empty).eql(full)); + try testing.expect(full.differenceWith(red).eql(black)); + try testing.expect(full.differenceWith(black).eql(red)); +} + +test "std.enums.EnumSet const iterator" { + const Direction = enum { up, down, left, right }; + const diag_move = init: { + var move = EnumSet(Direction).initEmpty(); + move.insert(.right); + move.insert(.up); + break :init move; + }; + + var result = EnumSet(Direction).initEmpty(); + var it = diag_move.iterator(); + while (it.next()) |dir| { + result.insert(dir); + } + + try testing.expect(result.eql(diag_move)); +} + +/// A map from keys to values, using an index lookup. Uses a +/// bitfield to track presence and a dense array of values. +/// This type does no allocation and can be copied by value. +pub fn IndexedMap(comptime I: type, comptime V: type, comptime Ext: ?fn (type) type) type { + comptime ensureIndexer(I); + return struct { + const Self = @This(); + + pub usingnamespace (Ext orelse NoExtension)(Self); + + /// The index mapping for this map + pub const Indexer = I; + /// The key type used to index this map + pub const Key = Indexer.Key; + /// The value type stored in this map + pub const Value = V; + /// The number of possible keys in the map + pub const len = Indexer.count; + + const BitSet = std.StaticBitSet(Indexer.count); + + /// Bits determining whether items are in the map + bits: BitSet = BitSet.initEmpty(), + /// Values of items in the map. If the associated + /// bit is zero, the value is undefined. + values: [Indexer.count]Value = undefined, + + /// The number of items in the map. + pub fn count(self: Self) usize { + return self.bits.count(); + } + + /// Checks if the map contains an item. + pub fn contains(self: Self, key: Key) bool { + return self.bits.isSet(Indexer.indexOf(key)); + } + + /// Gets the value associated with a key. + /// If the key is not in the map, returns null. + pub fn get(self: Self, key: Key) ?Value { + const index = Indexer.indexOf(key); + return if (self.bits.isSet(index)) self.values[index] else null; + } + + /// Gets the value associated with a key, which must + /// exist in the map. + pub fn getAssertContains(self: Self, key: Key) Value { + const index = Indexer.indexOf(key); + assert(self.bits.isSet(index)); + return self.values[index]; + } + + /// Gets the address of the value associated with a key. + /// If the key is not in the map, returns null. + pub fn getPtr(self: *Self, key: Key) ?*Value { + const index = Indexer.indexOf(key); + return if (self.bits.isSet(index)) &self.values[index] else null; + } + + /// Gets the address of the const value associated with a key. + /// If the key is not in the map, returns null. + pub fn getPtrConst(self: *const Self, key: Key) ?*const Value { + const index = Indexer.indexOf(key); + return if (self.bits.isSet(index)) &self.values[index] else null; + } + + /// Gets the address of the value associated with a key. + /// The key must be present in the map. + pub fn getPtrAssertContains(self: *Self, key: Key) *Value { + const index = Indexer.indexOf(key); + assert(self.bits.isSet(index)); + return &self.values[index]; + } + + /// Adds the key to the map with the supplied value. + /// If the key is already in the map, overwrites the value. + pub fn put(self: *Self, key: Key, value: Value) void { + const index = Indexer.indexOf(key); + self.bits.set(index); + self.values[index] = value; + } + + /// Adds the key to the map with an undefined value. + /// If the key is already in the map, the value becomes undefined. + /// A pointer to the value is returned, which should be + /// used to initialize the value. + pub fn putUninitialized(self: *Self, key: Key) *Value { + const index = Indexer.indexOf(key); + self.bits.set(index); + self.values[index] = undefined; + return &self.values[index]; + } + + /// Sets the value associated with the key in the map, + /// and returns the old value. If the key was not in + /// the map, returns null. + pub fn fetchPut(self: *Self, key: Key, value: Value) ?Value { + const index = Indexer.indexOf(key); + const result: ?Value = if (self.bits.isSet(index)) self.values[index] else null; + self.bits.set(index); + self.values[index] = value; + return result; + } + + /// Removes a key from the map. If the key was not in the map, + /// does nothing. + pub fn remove(self: *Self, key: Key) void { + const index = Indexer.indexOf(key); + self.bits.unset(index); + self.values[index] = undefined; + } + + /// Removes a key from the map, and returns the old value. + /// If the key was not in the map, returns null. + pub fn fetchRemove(self: *Self, key: Key) ?Value { + const index = Indexer.indexOf(key); + const result: ?Value = if (self.bits.isSet(index)) self.values[index] else null; + self.bits.unset(index); + self.values[index] = undefined; + return result; + } + + /// Returns an iterator over the map, which visits items in index order. + /// Modifications to the underlying map may or may not be observed by + /// the iterator, but will not invalidate it. + pub fn iterator(self: *Self) Iterator { + return .{ + .inner = self.bits.iterator(.{}), + .values = &self.values, + }; + } + + /// An entry in the map. + pub const Entry = struct { + /// The key associated with this entry. + /// Modifying this key will not change the map. + key: Key, + + /// A pointer to the value in the map associated + /// with this key. Modifications through this + /// pointer will modify the underlying data. + value: *Value, + }; + + pub const Iterator = struct { + inner: BitSet.Iterator(.{}), + values: *[Indexer.count]Value, + + pub fn next(self: *Iterator) ?Entry { + return if (self.inner.next()) |index| + Entry{ + .key = Indexer.keyForIndex(index), + .value = &self.values[index], + } + else + null; + } + }; + }; +} + +/// A dense array of values, using an indexed lookup. +/// This type does no allocation and can be copied by value. +pub fn IndexedArray(comptime I: type, comptime V: type, comptime Ext: ?fn (type) type) type { + comptime ensureIndexer(I); + return struct { + const Self = @This(); + + pub usingnamespace (Ext orelse NoExtension)(Self); + + /// The index mapping for this map + pub const Indexer = I; + /// The key type used to index this map + pub const Key = Indexer.Key; + /// The value type stored in this map + pub const Value = V; + /// The number of possible keys in the map + pub const len = Indexer.count; + + values: [Indexer.count]Value, + + pub fn initUndefined() Self { + return Self{ .values = undefined }; + } + + pub fn initFill(v: Value) Self { + var self: Self = undefined; + @memset(&self.values, v); + return self; + } + + /// Returns the value in the array associated with a key. + pub fn get(self: Self, key: Key) Value { + return self.values[Indexer.indexOf(key)]; + } + + /// Returns a pointer to the slot in the array associated with a key. + pub fn getPtr(self: *Self, key: Key) *Value { + return &self.values[Indexer.indexOf(key)]; + } + + /// Returns a const pointer to the slot in the array associated with a key. + pub fn getPtrConst(self: *const Self, key: Key) *const Value { + return &self.values[Indexer.indexOf(key)]; + } + + /// Sets the value in the slot associated with a key. + pub fn set(self: *Self, key: Key, value: Value) void { + self.values[Indexer.indexOf(key)] = value; + } + + /// Iterates over the items in the array, in index order. + pub fn iterator(self: *Self) Iterator { + return .{ + .values = &self.values, + }; + } + + /// An entry in the array. + pub const Entry = struct { + /// The key associated with this entry. + /// Modifying this key will not change the array. + key: Key, + + /// A pointer to the value in the array associated + /// with this key. Modifications through this + /// pointer will modify the underlying data. + value: *Value, + }; + + pub const Iterator = struct { + index: usize = 0, + values: *[Indexer.count]Value, + + pub fn next(self: *Iterator) ?Entry { + const index = self.index; + if (index < Indexer.count) { + self.index += 1; + return Entry{ + .key = Indexer.keyForIndex(index), + .value = &self.values[index], + }; + } + return null; + } + }; + }; +} + +/// Verifies that a type is a valid Indexer, providing a helpful +/// compile error if not. An Indexer maps a comptime-known set +/// of keys to a dense set of zero-based indices. +/// The indexer interface must look like this: +/// ``` +/// struct { +/// /// The key type which this indexer converts to indices +/// pub const Key: type, +/// /// The number of indexes in the dense mapping +/// pub const count: usize, +/// /// Converts from a key to an index +/// pub fn indexOf(Key) usize; +/// /// Converts from an index to a key +/// pub fn keyForIndex(usize) Key; +/// } +/// ``` +pub fn ensureIndexer(comptime T: type) void { + comptime { + if (!@hasDecl(T, "Key")) @compileError("Indexer must have decl Key: type."); + if (@TypeOf(T.Key) != type) @compileError("Indexer.Key must be a type."); + if (!@hasDecl(T, "count")) @compileError("Indexer must have decl count: usize."); + if (@TypeOf(T.count) != usize) @compileError("Indexer.count must be a usize."); + if (!@hasDecl(T, "indexOf")) @compileError("Indexer.indexOf must be a fn(Key)usize."); + if (@TypeOf(T.indexOf) != fn (T.Key) usize) @compileError("Indexer must have decl indexOf: fn(Key)usize."); + if (!@hasDecl(T, "keyForIndex")) @compileError("Indexer must have decl keyForIndex: fn(usize)Key."); + if (@TypeOf(T.keyForIndex) != fn (usize) T.Key) @compileError("Indexer.keyForIndex must be a fn(usize)Key."); + } +} + +test "std.enums.ensureIndexer" { + ensureIndexer(struct { + pub const Key = u32; + pub const count: usize = 8; + pub fn indexOf(k: Key) usize { + return @as(usize, @intCast(k)); + } + pub fn keyForIndex(index: usize) Key { + return @as(Key, @intCast(index)); + } + }); +} + +pub fn EnumIndexer(comptime E: type) type { + if (!@typeInfo(E).Enum.is_exhaustive) { + @compileError("Cannot create an enum indexer for a non-exhaustive enum."); + } + + const const_fields = std.meta.fields(E); + var fields = const_fields[0..const_fields.len].*; + const min = fields[0].value; + const max = fields[fields.len - 1].value; + const fields_len = fields.len; + if (fields_len == 0) { + return struct { + pub const Key = E; + pub const count: usize = 0; + pub fn indexOf(e: E) usize { + _ = e; + unreachable; + } + pub fn keyForIndex(i: usize) E { + _ = i; + unreachable; + } + }; + } + + const SortContext = struct { + fields: []EnumField, + + pub fn lessThan(comptime ctx: @This(), comptime a: usize, comptime b: usize) bool { + return ctx.fields[a].value < ctx.fields[b].value; + } + + pub fn swap(comptime ctx: @This(), comptime a: usize, comptime b: usize) void { + return std.mem.swap(EnumField, &ctx.fields[a], &ctx.fields[b]); + } + }; + { + const a: usize = 0; + const b = fields_len; + var i = a + 1; + const context = SortContext{ .fields = &fields }; + @setEvalBranchQuota(999999999); + while (i < b) : (i += 1) { + var j = i; + while (j > a and context.lessThan(j, j - 1)) : (j -= 1) { + context.swap(j, j - 1); + } + } + } + + if (max - min == fields.len - 1) { + return struct { + pub const Key = E; + pub const count = fields_len; + pub fn indexOf(e: E) usize { + return @as(usize, @intCast(@intFromEnum(e) - min)); + } + pub fn keyForIndex(i: usize) E { + // TODO fix addition semantics. This calculation + // gives up some safety to avoid artificially limiting + // the range of signed enum values to max_isize. + const enum_value = if (min < 0) @as(isize, @bitCast(i)) +% min else i + min; + return @as(E, @enumFromInt(@as(std.meta.Tag(E), @intCast(enum_value)))); + } + }; + } + + const keys = valuesFromFields(E, &fields); + + return struct { + pub const Key = E; + pub const count = fields_len; + pub fn indexOf(e: E) usize { + for (keys, 0..) |k, i| { + if (k == e) return i; + } + unreachable; + } + pub fn keyForIndex(i: usize) E { + return keys[i]; + } + }; +} + +test "std.enums.EnumIndexer dense zeroed" { + const E = enum(u2) { b = 1, a = 0, c = 2 }; + const Indexer = EnumIndexer(E); + ensureIndexer(Indexer); + try testing.expectEqual(E, Indexer.Key); + try testing.expectEqual(@as(usize, 3), Indexer.count); + + try testing.expectEqual(@as(usize, 0), Indexer.indexOf(.a)); + try testing.expectEqual(@as(usize, 1), Indexer.indexOf(.b)); + try testing.expectEqual(@as(usize, 2), Indexer.indexOf(.c)); + + try testing.expectEqual(E.a, Indexer.keyForIndex(0)); + try testing.expectEqual(E.b, Indexer.keyForIndex(1)); + try testing.expectEqual(E.c, Indexer.keyForIndex(2)); +} + +test "std.enums.EnumIndexer dense positive" { + const E = enum(u4) { c = 6, a = 4, b = 5 }; + const Indexer = EnumIndexer(E); + ensureIndexer(Indexer); + try testing.expectEqual(E, Indexer.Key); + try testing.expectEqual(@as(usize, 3), Indexer.count); + + try testing.expectEqual(@as(usize, 0), Indexer.indexOf(.a)); + try testing.expectEqual(@as(usize, 1), Indexer.indexOf(.b)); + try testing.expectEqual(@as(usize, 2), Indexer.indexOf(.c)); + + try testing.expectEqual(E.a, Indexer.keyForIndex(0)); + try testing.expectEqual(E.b, Indexer.keyForIndex(1)); + try testing.expectEqual(E.c, Indexer.keyForIndex(2)); +} + +test "std.enums.EnumIndexer dense negative" { + const E = enum(i4) { a = -6, c = -4, b = -5 }; + const Indexer = EnumIndexer(E); + ensureIndexer(Indexer); + try testing.expectEqual(E, Indexer.Key); + try testing.expectEqual(@as(usize, 3), Indexer.count); + + try testing.expectEqual(@as(usize, 0), Indexer.indexOf(.a)); + try testing.expectEqual(@as(usize, 1), Indexer.indexOf(.b)); + try testing.expectEqual(@as(usize, 2), Indexer.indexOf(.c)); + + try testing.expectEqual(E.a, Indexer.keyForIndex(0)); + try testing.expectEqual(E.b, Indexer.keyForIndex(1)); + try testing.expectEqual(E.c, Indexer.keyForIndex(2)); +} + +test "std.enums.EnumIndexer sparse" { + const E = enum(i4) { a = -2, c = 6, b = 4 }; + const Indexer = EnumIndexer(E); + ensureIndexer(Indexer); + try testing.expectEqual(E, Indexer.Key); + try testing.expectEqual(@as(usize, 3), Indexer.count); + + try testing.expectEqual(@as(usize, 0), Indexer.indexOf(.a)); + try testing.expectEqual(@as(usize, 1), Indexer.indexOf(.b)); + try testing.expectEqual(@as(usize, 2), Indexer.indexOf(.c)); + + try testing.expectEqual(E.a, Indexer.keyForIndex(0)); + try testing.expectEqual(E.b, Indexer.keyForIndex(1)); + try testing.expectEqual(E.c, Indexer.keyForIndex(2)); +} diff --git a/src/env.zig b/src/env.zig index bdbb75131..65b49b18a 100644 --- a/src/env.zig +++ b/src/env.zig @@ -16,6 +16,7 @@ pub const isWasi = build_target == .wasi; pub const isMac = build_target == .native and @import("builtin").target.os.tag == .macos; pub const isBrowser = !isWasi and isWasm; pub const isWindows = @import("builtin").target.os.tag == .windows; +pub const isPosix = !isWindows and !isWasm; pub const isDebug = std.builtin.Mode.Debug == @import("builtin").mode; pub const isRelease = std.builtin.Mode.Debug != @import("builtin").mode and !isTest; pub const isTest = @import("builtin").is_test; @@ -45,3 +46,21 @@ pub inline fn onlyMac() void { unreachable; } } +pub const OperatingSystem = enum { + mac, + linux, + windows, + // wAsM is nOt aN oPeRaTiNg SyStEm + wasm, +}; + +pub const os: OperatingSystem = if (isMac) + OperatingSystem.mac +else if (isLinux) + OperatingSystem.linux +else if (isWindows) + OperatingSystem.windows +else if (isWasm) + OperatingSystem.wasm +else + @compileError("Please add your OS to the OperatingSystem enum"); diff --git a/src/env_loader.zig b/src/env_loader.zig index 0da985793..7c2c38a99 100644 --- a/src/env_loader.zig +++ b/src/env_loader.zig @@ -516,13 +516,26 @@ pub const Loader = struct { }; defer file.close(); - const stat = try file.stat(); - const end = stat.size; + const end = brk: { + if (comptime Environment.isWindows) { + const pos = try file.getEndPos(); + if (pos == 0) { + @field(this, base) = logger.Source.initPathString(base, ""); + return; + } - if (end == 0 or stat.kind != .file) { - @field(this, base) = logger.Source.initPathString(base, ""); - return; - } + break :brk pos; + } + + const stat = try file.stat(); + + if (stat.size == 0 or stat.kind != .file) { + @field(this, base) = logger.Source.initPathString(base, ""); + return; + } + + break :brk stat.size; + }; var buf = try this.allocator.alloc(u8, end + 1); errdefer this.allocator.free(buf); diff --git a/src/fs.zig b/src/fs.zig index 3c35d068b..2f59e09e2 100644 --- a/src/fs.zig +++ b/src/fs.zig @@ -602,38 +602,39 @@ pub const FileSystem = struct { } pub const Tmpfile = struct { - fd: std.os.fd_t = 0, - dir_fd: std.os.fd_t = 0, + fd: bun.FileDescriptor = bun.invalid_fd, + dir_fd: bun.FileDescriptor = bun.invalid_fd, pub inline fn dir(this: *Tmpfile) std.fs.Dir { return std.fs.Dir{ - .fd = this.dir_fd, + .fd = bun.fdcast(this.dir_fd), }; } pub inline fn file(this: *Tmpfile) std.fs.File { return std.fs.File{ - .handle = this.fd, + .handle = bun.fdcast(this.fd), }; } pub fn close(this: *Tmpfile) void { - if (this.fd != 0) std.os.close(this.fd); + if (this.fd != bun.invalid_fd) _ = bun.sys.close(this.fd); } pub fn create(this: *Tmpfile, rfs: *RealFS, name: [*:0]const u8) !void { var tmpdir_ = try rfs.openTmpDir(); const flags = std.os.O.CREAT | std.os.O.RDWR | std.os.O.CLOEXEC; - this.dir_fd = tmpdir_.fd; - this.fd = try std.os.openatZ(tmpdir_.fd, name, flags, std.os.S.IRWXU); + this.dir_fd = bun.toFD(tmpdir_.fd); + + this.fd = bun.toFD(try std.os.openatZ(tmpdir_.fd, name, flags, if (comptime Environment.isPosix) std.os.S.IRWXU else 0)); } pub fn promote(this: *Tmpfile, from_name: [*:0]const u8, destination_fd: std.os.fd_t, name: [*:0]const u8) !void { - std.debug.assert(this.fd != 0); - std.debug.assert(this.dir_fd != 0); + std.debug.assert(this.fd != bun.invalid_fd); + std.debug.assert(this.dir_fd != bun.invalid_fd); - try C.moveFileZWithHandle(this.fd, this.dir_fd, from_name, destination_fd, name); + try C.moveFileZWithHandle(bun.fdcast(this.fd), bun.fdcast(this.dir_fd), from_name, destination_fd, name); this.close(); } @@ -641,7 +642,7 @@ pub const FileSystem = struct { this.close(); if (comptime !Environment.isLinux) { - if (this.dir_fd == 0) return; + if (this.dir_fd == bun.invalid_fd) return; this.dir().deleteFileZ(name) catch {}; } @@ -682,6 +683,10 @@ pub const FileSystem = struct { // Always try to max out how many files we can keep open pub fn adjustUlimit() !usize { + if (comptime !Environment.isPosix) { + return std.math.maxInt(usize); + } + const LIMITS = [_]std.os.rlimit_resource{ std.os.rlimit_resource.STACK, std.os.rlimit_resource.NOFILE }; inline for (LIMITS, 0..) |limit_type, i| { const limit = try std.os.getrlimit(limit_type); @@ -853,7 +858,7 @@ pub const FileSystem = struct { if (store_fd) { FileSystem.setMaxFd(handle.fd); - dir.fd = handle.fd; + dir.fd = bun.toFD(handle.fd); } while (try iter.next()) |_entry| { @@ -966,7 +971,7 @@ pub const FileSystem = struct { original.data.clearAndFree(bun.fs_allocator); } if (store_fd and entries.fd == 0) - entries.fd = handle.fd; + entries.fd = bun.toFD(handle.fd); entries_ptr.* = entries; const result = EntriesOption{ @@ -993,7 +998,7 @@ pub const FileSystem = struct { comptime use_shared_buffer: bool, shared_buffer: *MutableString, comptime stream: bool, - ) !File { + ) !PathContentsPair { return readFileWithHandleAndAllocator( fs, bun.fs_allocator, @@ -1015,7 +1020,7 @@ pub const FileSystem = struct { comptime use_shared_buffer: bool, shared_buffer: *MutableString, comptime stream: bool, - ) !File { + ) !PathContentsPair { FileSystem.setMaxFd(file.handle); // Skip the extra file.stat() call when possible @@ -1031,9 +1036,9 @@ pub const FileSystem = struct { if (size == 0) { if (comptime use_shared_buffer) { shared_buffer.reset(); - return File{ .path = Path.init(path), .contents = shared_buffer.list.items }; + return PathContentsPair{ .path = Path.init(path), .contents = shared_buffer.list.items }; } else { - return File{ .path = Path.init(path), .contents = "" }; + return PathContentsPair{ .path = Path.init(path), .contents = "" }; } } @@ -1105,7 +1110,7 @@ pub const FileSystem = struct { debug("pread({d}, {d}) = {d}", .{ file.handle, size, read_count }); } - return File{ .path = Path.init(path), .contents = file_contents }; + return PathContentsPair{ .path = Path.init(path), .contents = file_contents }; } pub fn kindFromAbsolute( @@ -1169,6 +1174,11 @@ pub const FileSystem = struct { existing_fd: StoredFileDescriptorType, store_fd: bool, ) !Entry.Cache { + var cache = Entry.Cache{ + .kind = Entry.Kind.file, + .symlink = PathString.empty, + }; + var dir = _dir; var combo = [2]string{ dir, base }; var outpath: [bun.MAX_PATH_BYTES]u8 = undefined; @@ -1179,13 +1189,22 @@ pub const FileSystem = struct { const absolute_path_c: [:0]const u8 = outpath[0..entry_path.len :0]; + if (comptime bun.Environment.isWindows) { + var file = try std.fs.openFileAbsoluteZ(absolute_path_c, .{ .mode = .read_only }); + defer file.close(); + const metadata = try file.metadata(); + cache.kind = switch (metadata.kind()) { + .directory => .dir, + .sym_link => .file, + else => .file, + }; + return cache; + } + var stat = try C.lstat_absolute(absolute_path_c); const is_symlink = stat.kind == std.fs.File.Kind.sym_link; var _kind = stat.kind; - var cache = Entry.Cache{ - .kind = Entry.Kind.file, - .symlink = PathString.empty, - }; + var symlink: []const u8 = ""; if (is_symlink) { @@ -1240,8 +1259,7 @@ pub const FileSystem = struct { // }; }; -pub const Directory = struct { path: Path, contents: []string }; -pub const File = struct { path: Path, contents: string }; +pub const PathContentsPair = struct { path: Path, contents: string }; pub const NodeJSPathName = struct { base: string, diff --git a/src/http_client_async.zig b/src/http_client_async.zig index 09319966e..3b1982d9a 100644 --- a/src/http_client_async.zig +++ b/src/http_client_async.zig @@ -146,7 +146,7 @@ pub const Sendfile = struct { return .{ .err = AsyncIO.asError(errcode) }; } - } else { + } else if (Environment.isPosix) { var sbytes: std.os.off_t = adjusted_count; const signed_offset = @as(i64, @bitCast(@as(u64, this.offset))); const errcode = std.c.getErrno(std.c.sendfile( diff --git a/src/install/bin.zig b/src/install/bin.zig index adbd5f4d3..b559f4f53 100644 --- a/src/install/bin.zig +++ b/src/install/bin.zig @@ -172,7 +172,7 @@ pub const Bin = extern struct { done: bool = false, dir_iterator: ?std.fs.IterableDir.Iterator = null, package_name: String, - package_installed_node_modules: std.fs.Dir = std.fs.Dir{ .fd = std.math.maxInt(std.os.fd_t) }, + package_installed_node_modules: std.fs.Dir = std.fs.Dir{ .fd = bun.fdcast(bun.invalid_fd) }, buf: [bun.MAX_PATH_BYTES]u8 = undefined, string_buffer: []const u8, extern_string_buf: []const ExternalString, @@ -257,8 +257,8 @@ pub const Bin = extern struct { pub const Linker = struct { bin: Bin, - package_installed_node_modules: std.os.fd_t = std.math.maxInt(std.os.fd_t), - root_node_modules_folder: std.os.fd_t = std.math.maxInt(std.os.fd_t), + package_installed_node_modules: bun.FileDescriptor = bun.invalid_fd, + root_node_modules_folder: bun.FileDescriptor = bun.invalid_fd, /// Used for generating relative paths package_name: strings.StringOrTinyString, @@ -290,6 +290,10 @@ pub const Bin = extern struct { } fn setSimlinkAndPermissions(this: *Linker, target_path: [:0]const u8, dest_path: [:0]const u8) void { + if (comptime Environment.isWindows) { + bun.todo(@src(), {}); + return; + } std.os.symlinkatZ(target_path, this.root_node_modules_folder, dest_path) catch |err| { // Silently ignore PathAlreadyExists // Most likely, the symlink was already created by another package @@ -320,7 +324,7 @@ pub const Bin = extern struct { var remain: []u8 = &dest_buf; if (!link_global) { - const root_dir = std.fs.Dir{ .fd = this.root_node_modules_folder }; + const root_dir = std.fs.Dir{ .fd = bun.fdcast(this.root_node_modules_folder) }; const from = root_dir.realpath(dot_bin, &target_buf) catch |err| { this.err = err; return; @@ -337,7 +341,7 @@ pub const Bin = extern struct { from_remain[0..dot_bin.len].* = dot_bin.*; from_remain = from_remain[dot_bin.len..]; } else { - if (this.global_bin_dir.fd >= std.math.maxInt(std.os.fd_t)) { + if (bun.toFD(this.global_bin_dir.fd) == bun.invalid_fd) { this.err = error.MissingGlobalBinDir; return; } @@ -354,7 +358,7 @@ pub const Bin = extern struct { remain[0] = std.fs.path.sep; remain = remain[1..]; - this.root_node_modules_folder = this.global_bin_dir.fd; + this.root_node_modules_folder = bun.toFD(this.global_bin_dir.fd); } const name = this.package_name.slice(); @@ -364,7 +368,9 @@ pub const Bin = extern struct { remain = remain[1..]; if (comptime Environment.isWindows) { - @compileError("Bin.Linker.link() needs to be updated to generate .cmd files on Windows"); + // TODO: Bin.Linker.link() needs to be updated to generate .cmd files on Windows + bun.todo(@src(), {}); + return; } switch (this.bin.tag) { @@ -458,7 +464,7 @@ pub const Bin = extern struct { bun.copy(u8, remain, target); remain = remain[target.len..]; - var dir = std.fs.Dir{ .fd = this.package_installed_node_modules }; + var dir = std.fs.Dir{ .fd = bun.fdcast(this.package_installed_node_modules) }; var joined = Path.joinStringBuf(&target_buf, &parts, .auto); @as([*]u8, @ptrFromInt(@intFromPtr(joined.ptr)))[joined.len] = 0; @@ -514,7 +520,7 @@ pub const Bin = extern struct { dest_buf[0.."../".len].* = "../".*; remain = dest_buf["../".len..]; } else { - if (this.global_bin_dir.fd >= std.math.maxInt(std.os.fd_t)) { + if (this.global_bin_dir.fd >= bun.invalid_fd) { this.err = error.MissingGlobalBinDir; return; } @@ -610,7 +616,7 @@ pub const Bin = extern struct { bun.copy(u8, remain, target); remain = remain[target.len..]; - var dir = std.fs.Dir{ .fd = this.package_installed_node_modules }; + var dir = std.fs.Dir{ .fd = bun.fdcast(this.package_installed_node_modules) }; var joined = Path.joinStringBuf(&target_buf, &parts, .auto); @as([*]u8, @ptrFromInt(@intFromPtr(joined.ptr)))[joined.len] = 0; diff --git a/src/install/extract_tarball.zig b/src/install/extract_tarball.zig index a533a92a7..2bcad3a53 100644 --- a/src/install/extract_tarball.zig +++ b/src/install/extract_tarball.zig @@ -354,8 +354,8 @@ fn extract(this: *const ExtractTarball, tgz_bytes: []const u8) !Install.ExtractD return error.InstallFailed; }; defer json_file.close(); - const json_stat = try json_file.stat(); - json_buf = try this.package_manager.allocator.alloc(u8, json_stat.size + 64); + const json_stat_size = try json_file.getEndPos(); + json_buf = try this.package_manager.allocator.alloc(u8, json_stat_size + 64); json_len = try json_file.preadAll(json_buf, 0); json_path = bun.getFdPath( diff --git a/src/install/install.zig b/src/install/install.zig index 868204ed6..ee23fa427 100644 --- a/src/install/install.zig +++ b/src/install/install.zig @@ -46,7 +46,7 @@ const ExtractTarball = @import("./extract_tarball.zig"); const Npm = @import("./npm.zig"); const Bitset = bun.bit_set.DynamicBitSetUnmanaged; const z_allocator = @import("../memory_allocator.zig").z_allocator; -const Syscall = bun.JSC.Node.Syscall; +const Syscall = bun.sys; const RunCommand = @import("../cli/run_command.zig").RunCommand; threadlocal var initialized_store = false; const Futex = @import("../futex.zig"); @@ -684,14 +684,14 @@ const Task = struct { ) catch |err| { this.err = err; this.status = Status.fail; - this.data = .{ .git_clone = std.math.maxInt(std.os.fd_t) }; + this.data = .{ .git_clone = bun.invalid_fd }; manager.resolve_tasks.writeItem(this.*) catch unreachable; return; }; - manager.git_repositories.put(manager.allocator, this.id, dir.fd) catch unreachable; + manager.git_repositories.put(manager.allocator, this.id, bun.toFD(dir.fd)) catch unreachable; this.data = .{ - .git_clone = dir.fd, + .git_clone = bun.toFD(dir.fd), }; this.status = Status.success; manager.resolve_tasks.writeItem(this.*) catch unreachable; @@ -703,7 +703,7 @@ const Task = struct { manager.env, manager.log, manager.getCacheDirectory().dir, - .{ .fd = this.request.git_checkout.repo_dir }, + .{ .fd = bun.fdcast(this.request.git_checkout.repo_dir) }, this.request.git_checkout.name.slice(), this.request.git_checkout.url.slice(), this.request.git_checkout.resolved.slice(), @@ -771,7 +771,7 @@ const Task = struct { pub const Data = union { package_manifest: Npm.PackageManifest, extract: ExtractData, - git_clone: std.os.fd_t, + git_clone: bun.FileDescriptor, git_checkout: ExtractData, }; @@ -791,7 +791,7 @@ const Task = struct { url: strings.StringOrTinyString, }, git_checkout: struct { - repo_dir: std.os.fd_t, + repo_dir: bun.FileDescriptor, dependency_id: DependencyID, name: strings.StringOrTinyString, url: strings.StringOrTinyString, @@ -1211,8 +1211,12 @@ const PackageInstall = struct { var infile = try entry.dir.dir.openFile(entry.basename, .{ .mode = .read_only }); defer infile.close(); - const stat = infile.stat() catch continue; - _ = C.fchmod(outfile.handle, stat.mode); + if (comptime Environment.isPosix) { + const stat = infile.stat() catch continue; + _ = C.fchmod(outfile.handle, stat.mode); + } else { + bun.todo(@src(), {}); + } bun.copyFile(infile.handle, outfile.handle) catch |err| { progress_.root.end(); @@ -1323,8 +1327,8 @@ const PackageInstall = struct { const FileCopier = struct { pub fn copy( - dest_dir_fd: std.os.fd_t, - cache_dir_fd: std.os.fd_t, + dest_dir_fd: bun.FileDescriptor, + cache_dir_fd: bun.FileDescriptor, walker: *Walker, ) !u32 { var real_file_count: u32 = 0; @@ -1352,7 +1356,7 @@ const PackageInstall = struct { switch (entry.kind) { // directories are created .directory => { - std.os.mkdirat(dest_dir_fd, entry.path, 0o755) catch {}; + std.os.mkdirat(bun.fdcast(dest_dir_fd), entry.path, 0o755) catch {}; }, // but each file in the directory is a symlink .file => { @@ -1383,8 +1387,8 @@ const PackageInstall = struct { defer subdir.close(); this.file_count = FileCopier.copy( - subdir.dir.fd, - cached_package_dir.dir.fd, + bun.toFD(subdir.dir.fd), + bun.toFD(cached_package_dir.dir.fd), &walker_, ) catch |err| return Result{ @@ -1408,7 +1412,7 @@ const PackageInstall = struct { const rc = Syscall.system.open(path, @as(u32, std.os.O.PATH | 0), @as(u32, 0)); switch (Syscall.getErrno(rc)) { .SUCCESS => { - const fd = @as(std.os.fd_t, @intCast(rc)); + const fd = @as(bun.FileDescriptor, @intCast(rc)); _ = Syscall.system.close(fd); return false; }, @@ -1462,7 +1466,17 @@ const PackageInstall = struct { }, }; const target = Path.relative(dest_dir_path, to_path); - + if (comptime Environment.isWindows) { + return bun.todo( + @src(), + Result{ + .fail = .{ + .err = error.NotImplementedYetOnWindows, + .step = .linking, + }, + }, + ); + } std.os.symlinkat(target, dest_dir.fd, std.fs.path.basename(dest_path)) catch |err| return Result{ .fail = .{ .err = err, @@ -1556,16 +1570,20 @@ const PackageInstall = struct { } }, .symlink => { - if (this.installWithSymlink()) |result| { - return result; - } else |err| { - switch (err) { - error.FileNotFound => return Result{ - .fail = .{ .err = error.FileNotFound, .step = .opening_cache_dir }, - }, - else => return Result{ - .fail = .{ .err = err, .step = .copying_files }, - }, + if (comptime Environment.isWindows) { + supported_method_to_use = .copyfile; + } else { + if (this.installWithSymlink()) |result| { + return result; + } else |err| { + switch (err) { + error.FileNotFound => return Result{ + .fail = .{ .err = error.FileNotFound, .step = .opening_cache_dir }, + }, + else => return Result{ + .fail = .{ .err = err, .step = .copying_files }, + }, + } } } }, @@ -1586,7 +1604,7 @@ const Progress = std.Progress; const TaggedPointer = @import("../tagged_pointer.zig"); const TaskCallbackContext = union(Tag) { dependency: DependencyID, - node_modules_folder: std.os.fd_t, + node_modules_folder: bun.FileDescriptor, root_dependency: DependencyID, root_request_id: PackageID, pub const Tag = enum { @@ -1603,7 +1621,7 @@ const TaskChannel = sync.Channel(Task, .{ .Static = 4096 }); const NetworkChannel = sync.Channel(*NetworkTask, .{ .Static = 8192 }); const ThreadPool = bun.ThreadPool; const PackageManifestMap = std.HashMapUnmanaged(PackageNameHash, Npm.PackageManifest, IdentityContext(PackageNameHash), 80); -const RepositoryMap = std.HashMapUnmanaged(u64, std.os.fd_t, IdentityContext(u64), 80); +const RepositoryMap = std.HashMapUnmanaged(u64, bun.FileDescriptor, IdentityContext(u64), 80); pub const CacheLevel = struct { use_cache_control_headers: bool, @@ -2726,7 +2744,7 @@ pub const PackageManager = struct { fn enqueueGitCheckout( this: *PackageManager, task_id: u64, - dir: std.os.fd_t, + dir: bun.FileDescriptor, dependency_id: DependencyID, name: string, resolution: Resolution, @@ -2837,11 +2855,13 @@ pub const PackageManager = struct { try Lockfile.Printer.Yarn.print(&printer, @TypeOf(writer), writer); try buffered_writer.flush(); - _ = C.fchmod( - tmpfile.fd, - // chmod 666, - 0o0000040 | 0o0000004 | 0o0000002 | 0o0000400 | 0o0000200 | 0o0000020, - ); + if (comptime Environment.isPosix) { + _ = C.fchmod( + tmpfile.fd, + // chmod 666, + 0o0000040 | 0o0000004 | 0o0000002 | 0o0000400 | 0o0000200 | 0o0000020, + ); + } try tmpfile.promote(tmpname, std.fs.cwd().fd, "yarn.lock"); } @@ -3102,7 +3122,7 @@ pub const PackageManager = struct { this.allocator, this.env, this.log, - .{ .fd = repo_fd }, + .{ .fd = bun.fdcast(repo_fd) }, alias, this.lockfile.str(&dep.committish), ); @@ -4304,7 +4324,7 @@ pub const PackageManager = struct { log_level: LogLevel = .default, global: bool = false, - global_bin_dir: std.fs.IterableDir = .{ .dir = .{ .fd = std.math.maxInt(std.os.fd_t) } }, + global_bin_dir: std.fs.IterableDir = .{ .dir = .{ .fd = bun.fdcast(bun.invalid_fd) } }, explicit_global_directory: string = "", /// destination directory to link bins into // must be a variable due to global installs and bunx @@ -5165,8 +5185,8 @@ pub const PackageManager = struct { continue; }; defer if (!found) json_file.close(); - const json_stat = try json_file.stat(); - const json_buf = try ctx.allocator.alloc(u8, json_stat.size + 64); + const json_stat_size = try json_file.getEndPos(); + const json_buf = try ctx.allocator.alloc(u8, json_stat_size + 64); defer ctx.allocator.free(json_buf); const json_len = try json_file.preadAll(json_buf, 0); const json_path = try bun.getFdPath(json_file.handle, &package_json_cwd_buf); @@ -5215,7 +5235,7 @@ pub const PackageManager = struct { break :brk child_json; }; - try std.os.chdir(fs.top_level_dir); + try bun.sys.chdir(fs.top_level_dir).throw(); try BunArguments.loadConfig(ctx.allocator, cli.config, ctx, .InstallCommand); bun.copy(u8, &cwd_buf, fs.top_level_dir); cwd_buf[fs.top_level_dir.len] = '/'; @@ -5454,6 +5474,11 @@ pub const PackageManager = struct { } pub inline fn link(ctx: Command.Context) !void { + if (comptime Environment.isWindows) { + Output.prettyErrorln("<r><red>error:<r> bun link is not supported on Windows yet", .{}); + Global.crash(); + } + var manager = PackageManager.init(ctx, .link) catch |err| brk: { if (err == error.MissingPackageJSON) { try attemptToCreatePackageJSON(); @@ -5477,8 +5502,8 @@ pub const PackageManager = struct { // Step 1. parse the nearest package.json file { - var current_package_json_stat = try manager.root_package_json_file.stat(); - var current_package_json_buf = try ctx.allocator.alloc(u8, current_package_json_stat.size + 64); + var current_package_json_stat_size = try manager.root_package_json_file.getEndPos(); + var current_package_json_buf = try ctx.allocator.alloc(u8, current_package_json_stat_size + 64); const current_package_json_contents_len = try manager.root_package_json_file.preadAll( current_package_json_buf, 0, @@ -5604,6 +5629,11 @@ pub const PackageManager = struct { } pub inline fn unlink(ctx: Command.Context) !void { + if (comptime Environment.isWindows) { + Output.prettyErrorln("<r><red>error:<r> bun unlink is not supported on Windows yet", .{}); + Global.crash(); + } + var manager = PackageManager.init(ctx, .unlink) catch |err| brk: { if (err == error.MissingPackageJSON) { try attemptToCreatePackageJSON(); @@ -5627,8 +5657,8 @@ pub const PackageManager = struct { // Step 1. parse the nearest package.json file { - var current_package_json_stat = try manager.root_package_json_file.stat(); - var current_package_json_buf = try ctx.allocator.alloc(u8, current_package_json_stat.size + 64); + var current_package_json_stat_size = try manager.root_package_json_file.getEndPos(); + var current_package_json_buf = try ctx.allocator.alloc(u8, current_package_json_stat_size + 64); const current_package_json_contents_len = try manager.root_package_json_file.preadAll( current_package_json_buf, 0, @@ -5943,7 +5973,7 @@ pub const PackageManager = struct { buf[cwd_.len] = 0; final_path = buf[0..cwd_.len :0]; } - try std.os.chdirZ(final_path); + try bun.sys.chdir(final_path).throw(); } const specified_backend: ?PackageInstall.Method = brk: { @@ -6244,8 +6274,8 @@ pub const PackageManager = struct { Global.crash(); } - var current_package_json_stat = try manager.root_package_json_file.stat(); - var current_package_json_buf = try ctx.allocator.alloc(u8, current_package_json_stat.size + 64); + var current_package_json_stat_size = try manager.root_package_json_file.getEndPos(); + var current_package_json_buf = try ctx.allocator.alloc(u8, current_package_json_stat_size + 64); const current_package_json_contents_len = try manager.root_package_json_file.preadAll( current_package_json_buf, 0, @@ -6593,7 +6623,7 @@ pub const PackageManager = struct { const prev_node_modules_folder = this.node_modules_folder; defer this.node_modules_folder = prev_node_modules_folder; for (callbacks.items) |cb| { - this.node_modules_folder = .{ .dir = .{ .fd = cb.node_modules_folder } }; + this.node_modules_folder = .{ .dir = .{ .fd = bun.fdcast(cb.node_modules_folder) } }; this.installPackageWithNameAndResolution(dependency_id, package_id, log_level, name, resolution); } } @@ -6753,9 +6783,14 @@ pub const PackageManager = struct { if (bin.tag != .none) { if (!this.has_created_bin) { if (!this.options.global) { - this.root_node_modules_folder.dir.makeDirZ(".bin") catch {}; + if (comptime Environment.isWindows) { + std.os.mkdiratW(this.root_node_modules_folder.dir.fd, strings.w(".bin"), 0) catch {}; + } else { + this.root_node_modules_folder.dir.makeDirZ(".bin") catch {}; + } } - Bin.Linker.umask = C.umask(0); + if (comptime Environment.isPosix) + Bin.Linker.umask = C.umask(0); this.has_created_bin = true; } @@ -6773,12 +6808,12 @@ pub const PackageManager = struct { var bin_linker = Bin.Linker{ .bin = bin, - .package_installed_node_modules = this.node_modules_folder.dir.fd, + .package_installed_node_modules = bun.toFD(this.node_modules_folder.dir.fd), .global_bin_path = this.options.bin_path, .global_bin_dir = this.options.global_bin_dir.dir, // .destination_dir_subpath = destination_dir_subpath, - .root_node_modules_folder = this.root_node_modules_folder.dir.fd, + .root_node_modules_folder = bun.toFD(this.root_node_modules_folder.dir.fd), .package_name = strings.StringOrTinyString.init(alias), .string_buf = buf, .extern_string_buf = extern_string_buf, @@ -6815,7 +6850,7 @@ pub const PackageManager = struct { if (scripts.hasAny()) { var path_buf: [bun.MAX_PATH_BYTES]u8 = undefined; const path_str = Path.joinAbsString( - bun.getFdPath(this.node_modules_folder.dir.fd, &path_buf) catch unreachable, + bun.getFdPath(bun.toFD(this.node_modules_folder.dir.fd), &path_buf) catch unreachable, &[_]string{destination_dir_subpath}, .posix, ); @@ -6824,7 +6859,7 @@ pub const PackageManager = struct { } else if (!scripts.filled) { var path_buf: [bun.MAX_PATH_BYTES]u8 = undefined; const path_str = Path.joinAbsString( - bun.getFdPath(this.node_modules_folder.dir.fd, &path_buf) catch unreachable, + bun.getFdPath(bun.toFD(this.node_modules_folder.dir.fd), &path_buf) catch unreachable, &[_]string{destination_dir_subpath}, .posix, ); @@ -6870,7 +6905,7 @@ pub const PackageManager = struct { dependency_id, alias, resolution, - .{ .node_modules_folder = this.node_modules_folder.dir.fd }, + .{ .node_modules_folder = bun.toFD(this.node_modules_folder.dir.fd) }, ); }, .github => { @@ -6880,7 +6915,7 @@ pub const PackageManager = struct { dependency_id, package_id, url, - .{ .node_modules_folder = this.node_modules_folder.dir.fd }, + .{ .node_modules_folder = bun.toFD(this.node_modules_folder.dir.fd) }, ); }, .local_tarball => { @@ -6888,7 +6923,7 @@ pub const PackageManager = struct { dependency_id, alias, resolution, - .{ .node_modules_folder = this.node_modules_folder.dir.fd }, + .{ .node_modules_folder = bun.toFD(this.node_modules_folder.dir.fd) }, ); }, .remote_tarball => { @@ -6896,7 +6931,7 @@ pub const PackageManager = struct { dependency_id, package_id, resolution.value.remote_tarball.slice(buf), - .{ .node_modules_folder = this.node_modules_folder.dir.fd }, + .{ .node_modules_folder = bun.toFD(this.node_modules_folder.dir.fd) }, ); }, .npm => { @@ -6907,7 +6942,7 @@ pub const PackageManager = struct { package_id, resolution.value.npm.version, resolution.value.npm.url.slice(buf), - .{ .node_modules_folder = this.node_modules_folder.dir.fd }, + .{ .node_modules_folder = bun.toFD(this.node_modules_folder.dir.fd) }, ); }, else => { @@ -7149,13 +7184,14 @@ pub const PackageManager = struct { // we want to check lazily though // no need to download packages you've already installed!! var skip_verify_installed_version_number = false; - var node_modules_folder = std.fs.cwd().openIterableDir("node_modules", .{}) catch brk: { + const cwd = std.fs.cwd(); + var node_modules_folder = cwd.openIterableDir("node_modules", .{}) catch brk: { skip_verify_installed_version_number = true; - std.fs.cwd().makeDirZ("node_modules") catch |err| { + (if (comptime Environment.isWindows) std.os.mkdiratW(cwd.fd, bun.strings.w("node_modules"), 0) else cwd.makeDirZ("node_modules")) catch |err| { Output.prettyErrorln("<r><red>error<r>: <b><red>{s}<r> creating <b>node_modules<r> folder", .{@errorName(err)}); Global.crash(); }; - break :brk std.fs.cwd().openIterableDir("node_modules", .{}) catch |err| { + break :brk cwd.openIterableDir("node_modules", .{}) catch |err| { Output.prettyErrorln("<r><red>error<r>: <b><red>{s}<r> opening <b>node_modules<r> folder", .{@errorName(err)}); Global.crash(); }; @@ -7204,8 +7240,6 @@ pub const PackageManager = struct { ), }; - const cwd = std.fs.cwd(); - while (iterator.nextNodeModulesFolder()) |node_modules| { // We deliberately do not close this folder. // If the package hasn't been downloaded, we will need to install it later @@ -7305,16 +7339,21 @@ pub const PackageManager = struct { if (!installer.has_created_bin) { if (!this.options.global) { - node_modules_folder.dir.makeDirZ(".bin") catch {}; + if (comptime Environment.isWindows) { + std.os.mkdiratW(node_modules_folder.dir.fd, bun.strings.w(".bin"), 0) catch {}; + } else { + node_modules_folder.dir.makeDirZ(".bin") catch {}; + } } - Bin.Linker.umask = C.umask(0); + if (comptime Environment.isPosix) + Bin.Linker.umask = C.umask(0); installer.has_created_bin = true; } var bin_linker = Bin.Linker{ .bin = original_bin, - .package_installed_node_modules = folder.dir.fd, - .root_node_modules_folder = node_modules_folder.dir.fd, + .package_installed_node_modules = bun.toFD(folder.dir.fd), + .root_node_modules_folder = bun.toFD(node_modules_folder.dir.fd), .global_bin_path = this.options.bin_path, .global_bin_dir = this.options.global_bin_dir.dir, diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig index 5a085d92b..753d22857 100644 --- a/src/install/lockfile.zig +++ b/src/install/lockfile.zig @@ -915,7 +915,7 @@ pub const Printer = struct { } if (lockfile_path.len > 0 and lockfile_path[0] == std.fs.path.sep) - std.os.chdir(std.fs.path.dirname(lockfile_path) orelse "/") catch {}; + _ = bun.sys.chdir(std.fs.path.dirname(lockfile_path) orelse std.fs.path.sep_str); _ = try FileSystem.init(null); @@ -1473,11 +1473,16 @@ pub fn saveToDisk(this: *Lockfile, filename: stringZ) void { Global.crash(); }; - _ = C.fchmod( - tmpfile.fd, - // chmod 777 - 0o0000010 | 0o0000100 | 0o0000001 | 0o0001000 | 0o0000040 | 0o0000004 | 0o0000002 | 0o0000400 | 0o0000200 | 0o0000020, - ); + if (comptime Environment.isWindows) { + // TODO: make this executable + bun.todo(@src(), {}); + } else { + _ = C.fchmod( + tmpfile.fd, + // chmod 777 + 0o0000010 | 0o0000100 | 0o0000001 | 0o0001000 | 0o0000040 | 0o0000004 | 0o0000002 | 0o0000400 | 0o0000200 | 0o0000020, + ); + } tmpfile.promote(tmpname, std.fs.cwd().fd, filename) catch |err| { tmpfile.dir().deleteFileZ(tmpname) catch {}; @@ -1898,8 +1903,8 @@ pub const Package = extern struct { defer pkg_dir.close(); const json_file = try pkg_dir.dir.openFileZ("package.json", .{ .mode = .read_only }); defer json_file.close(); - const json_stat = try json_file.stat(); - const json_buf = try lockfile.allocator.alloc(u8, json_stat.size + 64); + const json_stat_size = try json_file.getEndPos(); + const json_buf = try lockfile.allocator.alloc(u8, json_stat_size + 64); const json_len = try json_file.preadAll(json_buf, 0); const json_src = logger.Source.initPathString(cwd, json_buf[0..json_len]); initializeStore(); @@ -3065,12 +3070,12 @@ pub const Package = extern struct { ); if (entry.cache.fd == 0) { - entry.cache.fd = std.os.openatZ( - std.os.AT.FDCWD, + entry.cache.fd = bun.toFD(std.os.openatZ( + std.fs.cwd().fd, entry_path, std.os.O.DIRECTORY | std.os.O.CLOEXEC | std.os.O.NOCTTY, 0, - ) catch continue; + ) catch continue); } const dir_fd = entry.cache.fd; @@ -3081,7 +3086,7 @@ pub const Package = extern struct { allocator, workspace_allocator, std.fs.Dir{ - .fd = dir_fd, + .fd = bun.fdcast(dir_fd), }, "", filepath_buf, diff --git a/src/install/repository.zig b/src/install/repository.zig index 6546481e9..564306733 100644 --- a/src/install/repository.zig +++ b/src/install/repository.zig @@ -284,8 +284,8 @@ pub const Repository = extern struct { return error.InstallFailed; }; defer json_file.close(); - const json_stat = try json_file.stat(); - var json_buf = try allocator.alloc(u8, json_stat.size + 64); + const size = try json_file.getEndPos(); + var json_buf = try allocator.alloc(u8, size + 64); const json_len = try json_file.preadAll(json_buf, 0); const json_path = bun.getFdPath( diff --git a/src/io/io_darwin.zig b/src/io/io_darwin.zig index c44b285c2..226a4d284 100644 --- a/src/io/io_darwin.zig +++ b/src/io/io_darwin.zig @@ -241,7 +241,7 @@ pub const errno_map: [108]Errno = brk: { const socket_t = os.socket_t; const sockaddr = darwin.sockaddr; const socklen_t = darwin.socklen_t; -const system = darwin; +pub const system = darwin; pub fn asError(err: anytype) Errno { const int = if (@typeInfo(@TypeOf(err)) == .Enum) diff --git a/src/io/io_windows.zig b/src/io/io_windows.zig new file mode 100644 index 000000000..55803d7ea --- /dev/null +++ b/src/io/io_windows.zig @@ -0,0 +1,1331 @@ +/// Thanks to Tigerbeetle - https://github.com/tigerbeetle/tigerbeetle/blob/532c8b70b9142c17e07737ab6d3da68d7500cbca/src/io/windows.zig#L1 +/// Apache2 license - https://github.com/tigerbeetle/tigerbeetle/blob/532c8b70b9142c17e07737ab6d3da68d7500cbca/LICENSE +const std = @import("std"); +const os = std.os; +const assert = std.debug.assert; +const log = std.log.scoped(.io); +const bun = @import("root").bun; +const FIFO = @import("./fifo.zig").FIFO; +const windows = bun.windows; + +const Time = struct { + const Self = @This(); + + /// Hardware and/or software bugs can mean that the monotonic clock may regress. + /// One example (of many): https://bugzilla.redhat.com/show_bug.cgi?id=448449 + /// We crash the process for safety if this ever happens, to protect against infinite loops. + /// It's better to crash and come back with a valid monotonic clock than get stuck forever. + monotonic_guard: u64 = 0, + + /// A timestamp to measure elapsed time, meaningful only on the same system, not across reboots. + /// Always use a monotonic timestamp if the goal is to measure elapsed time. + /// This clock is not affected by discontinuous jumps in the system time, for example if the + /// system administrator manually changes the clock. + pub fn monotonic(self: *Self) u64 { + const m = blk: { + // Uses QueryPerformanceCounter() on windows due to it being the highest precision timer + // available while also accounting for time spent suspended by default: + // https://docs.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryunbiasedinterrupttime#remarks + + // QPF need not be globally cached either as it ends up being a load from read-only + // memory mapped to all processed by the kernel called KUSER_SHARED_DATA (See "QpcFrequency") + // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data + // https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm + const qpc = os.windows.QueryPerformanceCounter(); + const qpf = os.windows.QueryPerformanceFrequency(); + + // 10Mhz (1 qpc tick every 100ns) is a common QPF on modern systems. + // We can optimize towards this by converting to ns via a single multiply. + // https://github.com/microsoft/STL/blob/785143a0c73f030238ef618890fd4d6ae2b3a3a0/stl/inc/chrono#L694-L701 + const common_qpf = 10_000_000; + if (qpf == common_qpf) break :blk qpc * (std.time.ns_per_s / common_qpf); + + // Convert qpc to nanos using fixed point to avoid expensive extra divs and overflow. + const scale = (std.time.ns_per_s << 32) / qpf; + break :blk @as(u64, @truncate((@as(u96, qpc) * scale) >> 32)); + }; + + // "Oops!...I Did It Again" + if (m < self.monotonic_guard) @panic("a hardware/kernel bug regressed the monotonic clock"); + self.monotonic_guard = m; + return m; + } + + /// A timestamp to measure real (i.e. wall clock) time, meaningful across systems, and reboots. + /// This clock is affected by discontinuous jumps in the system time. + pub fn realtime(_: *Self) i64 { + const kernel32 = struct { + extern "kernel32" fn GetSystemTimePreciseAsFileTime( + lpFileTime: *os.windows.FILETIME, + ) callconv(os.windows.WINAPI) void; + }; + + var ft: os.windows.FILETIME = undefined; + kernel32.GetSystemTimePreciseAsFileTime(&ft); + const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // FileTime is in units of 100 nanoseconds + // and uses the NTFS/Windows epoch of 1601-01-01 instead of Unix Epoch 1970-01-01. + const epoch_adjust = std.time.epoch.windows * (std.time.ns_per_s / 100); + return (@as(i64, @bitCast(ft64)) + epoch_adjust) * 100; + } + + pub fn tick(_: *Self) void {} +}; +pub const system = os.windows; + +pub const CloseError = error{ + FileDescriptorInvalid, + DiskQuota, + InputOutput, + NoSpaceLeft, +} || os.UnexpectedError; +pub const WriteError = os.PWriteError; +pub const ConnectError = os.ConnectError || error{FileDescriptorNotASocket}; + +pub const Errno = bun.C.SystemErrno.Error; + +pub fn asError(err: anytype) Errno { + if (bun.C.SystemErrno.init(err)) |e| { + return e.toError(); + } else { + return error.Unexpected; + } +} + +pub const Waker = struct { + iocp: os.windows.HANDLE, + + pub const completion_key = std.math.maxInt(isize) - 24; + + const kernel32 = os.windows.kernel32; + pub fn init(_: std.mem.Allocator) !Waker { + _ = try os.windows.WSAStartup(2, 2); + errdefer os.windows.WSACleanup() catch unreachable; + + const iocp = try os.windows.CreateIoCompletionPort(os.windows.INVALID_HANDLE_VALUE, null, completion_key, 0); + return Waker{ + .iocp = iocp, + }; + } + + pub fn initWithFileDescriptor(_: std.mem.Allocator, fd: bun.FileDescriptor) Waker { + return Waker{ + .iocp = bun.fdcast(fd), + }; + } + + pub fn wait(this: Waker) !u64 { + var overlapped = [_]os.windows.OVERLAPPED_ENTRY{std.mem.zeroes(os.windows.OVERLAPPED_ENTRY)} ** 1; + var removed: u32 = 0; + _ = kernel32.GetQueuedCompletionStatusEx(this.iocp, &overlapped, 1, &removed, 0, 1); + return 0; + } + + pub fn wake(this: Waker) !void { + var overlapped: os.windows.OVERLAPPED = std.mem.zeroes(os.windows.OVERLAPPED); + _ = kernel32.PostQueuedCompletionStatus(this.iocp, 1, completion_key, &overlapped); + } +}; + +pub fn wait(this: *IO, context: anytype, comptime function: anytype) void { + this.flush(.blocking) catch unreachable; + function(context); +} + +/// This struct holds the data needed for a single IO operation +pub const Completion = struct { + next: ?*Completion, + context: ?*anyopaque, + callback: *const fn (Context) void, + operation: Operation, + + const Context = struct { + io: *IO, + completion: *Completion, + }; + + const Overlapped = struct { + raw: os.windows.OVERLAPPED, + completion: *Completion, + }; + + const Transfer = struct { + socket: os.socket_t, + buf: os.windows.ws2_32.WSABUF, + overlapped: Overlapped, + pending: bool, + }; + + const Operation = union(enum) { + accept: struct { + overlapped: Overlapped, + listen_socket: os.socket_t, + client_socket: os.socket_t, + addr_buffer: [(@sizeOf(std.net.Address) + 16) * 2]u8 align(4), + }, + open: struct { + path: [:0]const u8, + flags: bun.JSC.Node.Mode, + }, + connect: struct { + socket: os.socket_t, + address: std.net.Address, + overlapped: Overlapped, + pending: bool, + }, + send: Transfer, + recv: Transfer, + read: struct { + fd: bun.FileDescriptor, + buf: [*]u8, + len: u32, + offset: ?u64, + }, + write: struct { + fd: bun.FileDescriptor, + buf: [*]const u8, + len: u32, + offset: ?u64, + }, + close: struct { + fd: bun.FileDescriptor, + }, + timeout: struct { + deadline: u64, + }, + }; +}; + +fn buffer_limit(buffer_len: usize) usize { + + // Linux limits how much may be written in a `pwrite()/pread()` call, which is `0x7ffff000` on + // both 64-bit and 32-bit systems, due to using a signed C int as the return value, as well as + // stuffing the errno codes into the last `4096` values. + // Darwin limits writes to `0x7fffffff` bytes, more than that returns `EINVAL`. + // The corresponding POSIX limit is `std.math.maxInt(isize)`. + const limit = switch (@import("builtin").target.os.tag) { + .linux => 0x7ffff000, + .macos, .ios, .watchos, .tvos => std.math.maxInt(i32), + else => std.math.maxInt(isize), + }; + return @min(limit, buffer_len); +} + +iocp: os.windows.HANDLE, +timer: Time = .{}, +io_pending: usize = 0, +timeouts: FIFO(Completion) = .{}, +completed: FIFO(Completion) = .{}, + +pub const IO = @This(); + +pub fn init(_: u12, _: u32, waker: Waker) !IO { + return IO{ .iocp = waker.iocp }; +} + +pub fn deinit(self: *IO) void { + assert(self.iocp != os.windows.INVALID_HANDLE_VALUE); + os.windows.CloseHandle(self.iocp); + self.iocp = os.windows.INVALID_HANDLE_VALUE; + + os.windows.WSACleanup() catch unreachable; +} + +pub fn tick(self: *IO) !void { + return self.flush(.non_blocking); +} + +pub fn run_for_ns(self: *IO, nanoseconds: u63) !void { + const Callback = struct { + fn on_timeout(timed_out: *bool, completion: *Completion, result: TimeoutError!void) void { + _ = result catch unreachable; + _ = completion; + timed_out.* = true; + } + }; + + var timed_out = false; + var completion: Completion = undefined; + self.timeout(*bool, &timed_out, Callback.on_timeout, &completion, nanoseconds); + + while (!timed_out) { + try self.flush(.blocking); + } +} + +const FlushMode = enum { + blocking, + non_blocking, +}; + +fn flush(self: *IO, comptime mode: FlushMode) anyerror!void { + if (self.completed.peek() == null) { + // Compute how long to poll by flushing timeout completions. + // NOTE: this may push to completed queue + var timeout_ms: ?os.windows.DWORD = null; + if (self.flush_timeouts()) |expires_ns| { + // 0ns expires should have been completed not returned + assert(expires_ns != 0); + // Round up sub-millisecond expire times to the next millisecond + const expires_ms = (expires_ns + (std.time.ns_per_ms / 2)) / std.time.ns_per_ms; + // Saturating cast to DWORD milliseconds + const expires = std.math.cast(os.windows.DWORD, expires_ms) orelse std.math.maxInt(os.windows.DWORD); + // max DWORD is reserved for INFINITE so cap the cast at max - 1 + timeout_ms = if (expires == os.windows.INFINITE) expires - 1 else expires; + } + + // Poll for IO iff theres IO pending and flush_timeouts() found no ready completions + if (self.io_pending > 0 and self.completed.peek() == null) { + // In blocking mode, we're always waiting at least until the timeout by run_for_ns. + // In non-blocking mode, we shouldn't wait at all. + const io_timeout = switch (mode) { + .blocking => timeout_ms orelse 0, + .non_blocking => 0, + }; + + var events: [64]os.windows.OVERLAPPED_ENTRY = undefined; + const num_events = try os.windows.GetQueuedCompletionStatusEx( + self.iocp, + &events, + io_timeout, + false, // non-alertable wait + ); + + assert(self.io_pending >= num_events); + self.io_pending -= num_events; + + for (events[0..num_events]) |event| { + const raw_overlapped = event.lpOverlapped; + const overlapped = @fieldParentPtr(Completion.Overlapped, "raw", raw_overlapped); + const completion = overlapped.completion; + completion.next = null; + self.completed.push(completion); + } + } + } + + // Dequeue and invoke all the completions currently ready. + // Must read all `completions` before invoking the callbacks + // as the callbacks could potentially submit more completions. + var completed = self.completed; + self.completed = .{}; + while (completed.pop()) |completion| { + (completion.callback)(Completion.Context{ + .io = self, + .completion = completion, + }); + } +} + +fn flush_timeouts(self: *IO) ?u64 { + var min_expires: ?u64 = null; + var current_time: ?u64 = null; + var timeouts: ?*Completion = self.timeouts.peek(); + + // iterate through the timeouts, returning min_expires at the end + while (timeouts) |completion| { + timeouts = completion.next; + + // lazily get the current time + const now = current_time orelse self.timer.monotonic(); + current_time = now; + + // move the completion to completed if it expired + if (now >= completion.operation.timeout.deadline) { + self.timeouts.remove(completion); + self.completed.push(completion); + continue; + } + + // if it's still waiting, update min_timeout + const expires = completion.operation.timeout.deadline - now; + if (min_expires) |current_min_expires| { + min_expires = @min(expires, current_min_expires); + } else { + min_expires = expires; + } + } + + return min_expires; +} + +fn submit( + self: *IO, + context: anytype, + comptime callback: anytype, + completion: *Completion, + comptime op_tag: std.meta.Tag(Completion.Operation), + op_data: anytype, + comptime OperationImpl: type, +) void { + const Context = @TypeOf(context); + const Callback = struct { + fn onComplete(ctx: Completion.Context) void { + // Perform the operation and get the result + const data = &@field(ctx.completion.operation, @tagName(op_tag)); + const result = OperationImpl.do_operation(ctx, data); + + // For OVERLAPPED IO, error.WouldBlock assumes that it will be completed by IOCP. + switch (op_tag) { + .accept, .read, .recv, .connect, .write, .send => { + _ = result catch |err| switch (err) { + error.WouldBlock => { + ctx.io.io_pending += 1; + return; + }, + else => {}, + }; + }, + else => {}, + } + + // The completion is finally ready to invoke the callback + callback( + @as(Context, @ptrFromInt(@intFromPtr(ctx.completion.context))), + ctx.completion, + result, + ); + } + }; + + // Setup the completion with the callback wrapper above + completion.* = .{ + .next = null, + .context = @as(?*anyopaque, @ptrCast(context)), + .callback = Callback.onComplete, + .operation = @unionInit(Completion.Operation, @tagName(op_tag), op_data), + }; + + // Submit the completion onto the right queue + switch (op_tag) { + .timeout => self.timeouts.push(completion), + else => self.completed.push(completion), + } +} + +pub const OpenError = bun.C.SystemErrno.Error; + +pub fn open( + self: *IO, + comptime Context: type, + context: Context, + comptime callback: *const fn ( + context: Context, + completion: *Completion, + result: OpenError!bun.FileDescriptor, + ) void, + completion: *Completion, + path: [:0]const u8, + flags: bun.JSC.Node.Mode, + _: bun.JSC.Node.Mode, +) void { + self.submit( + context, + callback, + completion, + .open, + .{ + .path = path, + .flags = flags, + }, + struct { + fn do_operation(ctx: Completion.Context, op: anytype) OpenError!bun.FileDescriptor { + _ = ctx; + const result = bun.sys.openat(bun.invalid_fd, op.path, op.flags, 0); + try result.throw(); + return result.result; + } + }, + ); +} + +pub fn accept( + self: *IO, + comptime Context: type, + context: Context, + comptime callback: fn ( + context: Context, + completion: *Completion, + result: AcceptError!os.socket_t, + ) void, + completion: *Completion, + socket: os.socket_t, +) void { + self.submit( + context, + callback, + completion, + .accept, + .{ + .overlapped = undefined, + .listen_socket = socket, + .client_socket = INVALID_SOCKET, + .addr_buffer = undefined, + }, + struct { + fn do_operation(ctx: Completion.Context, op: anytype) AcceptError!os.socket_t { + var flags: os.windows.DWORD = undefined; + var transferred: os.windows.DWORD = undefined; + + const rc = switch (op.client_socket) { + // When first called, the client_socket is invalid so we start the op. + INVALID_SOCKET => blk: { + // Create the socket that will be used for accept. + op.client_socket = ctx.io.open_socket( + os.AF.INET, + os.SOCK.STREAM, + os.IPPROTO.TCP, + ) catch |err| switch (err) { + error.AddressFamilyNotSupported, error.ProtocolNotSupported => unreachable, + else => |e| return e, + }; + + var sync_bytes_read: os.windows.DWORD = undefined; + op.overlapped = .{ + .raw = std.mem.zeroes(os.windows.OVERLAPPED), + .completion = ctx.completion, + }; + + // Start the asynchronous accept with the created socket. + break :blk os.windows.ws2_32.AcceptEx( + op.listen_socket, + op.client_socket, + &op.addr_buffer, + 0, + @sizeOf(std.net.Address) + 16, + @sizeOf(std.net.Address) + 16, + &sync_bytes_read, + &op.overlapped.raw, + ); + }, + // Called after accept was started, so get the result + else => os.windows.ws2_32.WSAGetOverlappedResult( + op.listen_socket, + &op.overlapped.raw, + &transferred, + os.windows.FALSE, // dont wait + &flags, + ), + }; + + // return the socket if we succeed in accepting. + if (rc != os.windows.FALSE) { + // enables getsockopt, setsockopt, getsockname, getpeername + _ = os.windows.ws2_32.setsockopt( + op.client_socket, + os.windows.ws2_32.SOL.SOCKET, + os.windows.ws2_32.SO.UPDATE_ACCEPT_CONTEXT, + null, + 0, + ); + + return op.client_socket; + } + + // destroy the client_socket we created if we get a non WouldBlock error + errdefer |result| { + _ = result catch |err| switch (err) { + error.WouldBlock => {}, + else => { + os.closeSocket(op.client_socket); + op.client_socket = INVALID_SOCKET; + }, + }; + } + + return switch (os.windows.ws2_32.WSAGetLastError()) { + .WSA_IO_PENDING, .WSAEWOULDBLOCK, .WSA_IO_INCOMPLETE => error.WouldBlock, + .WSANOTINITIALISED => unreachable, // WSAStartup() was called + .WSAENETDOWN => unreachable, // WinSock error + .WSAENOTSOCK => error.FileDescriptorNotASocket, + .WSAEOPNOTSUPP => error.OperationNotSupported, + .WSA_INVALID_HANDLE => unreachable, // we dont use hEvent in OVERLAPPED + .WSAEFAULT, .WSA_INVALID_PARAMETER => unreachable, // params should be ok + .WSAECONNRESET => error.ConnectionAborted, + .WSAEMFILE => unreachable, // we create our own descriptor so its available + .WSAENOBUFS => error.SystemResources, + .WSAEINTR, .WSAEINPROGRESS => unreachable, // no blocking calls + else => |err| os.windows.unexpectedWSAError(err), + }; + } + }, + ); +} + +pub fn connect( + self: *IO, + comptime Context: type, + context: Context, + comptime callback: fn ( + context: Context, + completion: *Completion, + result: ConnectError!void, + ) void, + completion: *Completion, + socket: os.socket_t, + address: std.net.Address, +) void { + self.submit( + context, + callback, + completion, + .connect, + .{ + .socket = socket, + .address = address, + .overlapped = undefined, + .pending = false, + }, + struct { + fn do_operation(ctx: Completion.Context, op: anytype) ConnectError!void { + var flags: os.windows.DWORD = undefined; + var transferred: os.windows.DWORD = undefined; + + const rc = blk: { + // Poll for the result if we've already started the connect op. + if (op.pending) { + break :blk os.windows.ws2_32.WSAGetOverlappedResult( + op.socket, + &op.overlapped.raw, + &transferred, + os.windows.FALSE, // dont wait + &flags, + ); + } + + // ConnectEx requires the socket to be initially bound (INADDR_ANY) + const inaddr_any = std.mem.zeroes([4]u8); + const bind_addr = std.net.Address.initIp4(inaddr_any, 0); + os.bind( + op.socket, + &bind_addr.any, + bind_addr.getOsSockLen(), + ) catch |err| switch (err) { + error.AccessDenied => unreachable, + error.SymLinkLoop => unreachable, + error.NameTooLong => unreachable, + error.NotDir => unreachable, + error.ReadOnlyFileSystem => unreachable, + error.NetworkSubsystemFailed => unreachable, + error.AlreadyBound => unreachable, + else => |e| return e, + }; + + const LPFN_CONNECTEX = fn ( + Socket: os.windows.ws2_32.SOCKET, + SockAddr: *const os.windows.ws2_32.sockaddr, + SockLen: os.socklen_t, + SendBuf: ?*const anyopaque, + SendBufLen: os.windows.DWORD, + BytesSent: *os.windows.DWORD, + Overlapped: *os.windows.OVERLAPPED, + ) callconv(os.windows.WINAPI) os.windows.BOOL; + + // Find the ConnectEx function by dynamically looking it up on the socket. + const connect_ex = os.windows.loadWinsockExtensionFunction( + LPFN_CONNECTEX, + op.socket, + os.windows.ws2_32.WSAID_CONNECTEX, + ) catch |err| switch (err) { + error.OperationNotSupported => unreachable, + error.ShortRead => unreachable, + else => |e| return e, + }; + + op.pending = true; + op.overlapped = .{ + .raw = std.mem.zeroes(os.windows.OVERLAPPED), + .completion = ctx.completion, + }; + + // Start the connect operation. + break :blk (connect_ex)( + op.socket, + &op.address.any, + op.address.getOsSockLen(), + null, + 0, + &transferred, + &op.overlapped.raw, + ); + }; + + // return if we succeeded in connecting + if (rc != os.windows.FALSE) { + // enables getsockopt, setsockopt, getsockname, getpeername + _ = os.windows.ws2_32.setsockopt( + op.socket, + os.windows.ws2_32.SOL.SOCKET, + os.windows.ws2_32.SO.UPDATE_CONNECT_CONTEXT, + null, + 0, + ); + + return; + } + + return switch (os.windows.ws2_32.WSAGetLastError()) { + .WSA_IO_PENDING, .WSAEWOULDBLOCK, .WSA_IO_INCOMPLETE, .WSAEALREADY => error.WouldBlock, + .WSANOTINITIALISED => unreachable, // WSAStartup() was called + .WSAENETDOWN => unreachable, // network subsystem is down + .WSAEADDRNOTAVAIL => error.AddressNotAvailable, + .WSAEAFNOSUPPORT => error.AddressFamilyNotSupported, + .WSAECONNREFUSED => error.ConnectionRefused, + .WSAEFAULT => unreachable, // all addresses should be valid + .WSAEINVAL => unreachable, // invalid socket type + .WSAEHOSTUNREACH, .WSAENETUNREACH => error.NetworkUnreachable, + .WSAENOBUFS => error.SystemResources, + .WSAENOTSOCK => unreachable, // socket is not bound or is listening + .WSAETIMEDOUT => error.ConnectionTimedOut, + .WSA_INVALID_HANDLE => unreachable, // we dont use hEvent in OVERLAPPED + else => |err| os.windows.unexpectedWSAError(err), + }; + } + }, + ); +} + +pub const SendError = os.SendError; + +pub fn send( + self: *IO, + comptime Context: type, + context: Context, + comptime callback: fn ( + context: Context, + completion: *Completion, + result: SendError!usize, + ) void, + completion: *Completion, + socket: os.socket_t, + buffer: []const u8, +) void { + const transfer = Completion.Transfer{ + .socket = socket, + .buf = os.windows.ws2_32.WSABUF{ + .len = @as(u32, @intCast(buffer_limit(buffer.len))), + .buf = @as([*]u8, @ptrFromInt(@intFromPtr(buffer.ptr))), + }, + .overlapped = undefined, + .pending = false, + }; + + self.submit( + context, + callback, + completion, + .send, + transfer, + struct { + fn do_operation(ctx: Completion.Context, op: anytype) SendError!usize { + var flags: os.windows.DWORD = undefined; + var transferred: os.windows.DWORD = undefined; + + const rc = blk: { + // Poll for the result if we've already started the send op. + if (op.pending) { + break :blk os.windows.ws2_32.WSAGetOverlappedResult( + op.socket, + &op.overlapped.raw, + &transferred, + os.windows.FALSE, // dont wait + &flags, + ); + } + + op.pending = true; + op.overlapped = .{ + .raw = std.mem.zeroes(os.windows.OVERLAPPED), + .completion = ctx.completion, + }; + + // Start the send operation. + break :blk switch (os.windows.ws2_32.WSASend( + op.socket, + @as([*]os.windows.ws2_32.WSABUF, @ptrCast(&op.buf)), + 1, // one buffer + &transferred, + 0, // no flags + &op.overlapped.raw, + null, + )) { + os.windows.ws2_32.SOCKET_ERROR => @as(os.windows.BOOL, os.windows.FALSE), + 0 => os.windows.TRUE, + else => unreachable, + }; + }; + + // Return bytes transferred on success. + if (rc != os.windows.FALSE) + return transferred; + + return switch (os.windows.ws2_32.WSAGetLastError()) { + .WSA_IO_PENDING, .WSAEWOULDBLOCK, .WSA_IO_INCOMPLETE => error.WouldBlock, + .WSANOTINITIALISED => unreachable, // WSAStartup() was called + .WSA_INVALID_HANDLE => unreachable, // we dont use OVERLAPPED.hEvent + .WSA_INVALID_PARAMETER => unreachable, // parameters are fine + .WSAECONNABORTED => error.ConnectionResetByPeer, + .WSAECONNRESET => error.ConnectionResetByPeer, + .WSAEFAULT => unreachable, // invalid buffer + .WSAEINTR => unreachable, // this is non blocking + .WSAEINPROGRESS => unreachable, // this is non blocking + .WSAEINVAL => unreachable, // invalid socket type + .WSAEMSGSIZE => error.MessageTooBig, + .WSAENETDOWN => error.NetworkSubsystemFailed, + .WSAENETRESET => error.ConnectionResetByPeer, + .WSAENOBUFS => error.SystemResources, + .WSAENOTCONN => error.FileDescriptorNotASocket, + .WSAEOPNOTSUPP => unreachable, // we dont use MSG_OOB or MSG_PARTIAL + .WSAESHUTDOWN => error.BrokenPipe, + .WSA_OPERATION_ABORTED => unreachable, // operation was cancelled + else => |err| os.windows.unexpectedWSAError(err), + }; + } + }, + ); +} + +pub const RecvError = os.RecvFromError; + +pub fn recv( + self: *IO, + comptime Context: type, + context: Context, + comptime callback: fn ( + context: Context, + completion: *Completion, + result: RecvError!usize, + ) void, + completion: *Completion, + socket: os.socket_t, + buffer: []u8, +) void { + const transfer = Completion.Transfer{ + .socket = socket, + .buf = os.windows.ws2_32.WSABUF{ + .len = @as(u32, @intCast(buffer_limit(buffer.len))), + .buf = buffer.ptr, + }, + .overlapped = undefined, + .pending = false, + }; + + self.submit( + context, + callback, + completion, + .recv, + transfer, + struct { + fn do_operation(ctx: Completion.Context, op: anytype) RecvError!usize { + var flags: os.windows.DWORD = 0; // used both as input and output + var transferred: os.windows.DWORD = undefined; + + const rc = blk: { + // Poll for the result if we've already started the recv op. + if (op.pending) { + break :blk os.windows.ws2_32.WSAGetOverlappedResult( + op.socket, + &op.overlapped.raw, + &transferred, + os.windows.FALSE, // dont wait + &flags, + ); + } + + op.pending = true; + op.overlapped = .{ + .raw = std.mem.zeroes(os.windows.OVERLAPPED), + .completion = ctx.completion, + }; + + // Start the recv operation. + break :blk switch (os.windows.ws2_32.WSARecv( + op.socket, + @as([*]os.windows.ws2_32.WSABUF, @ptrCast(&op.buf)), + 1, // one buffer + &transferred, + &flags, + &op.overlapped.raw, + null, + )) { + os.windows.ws2_32.SOCKET_ERROR => @as(os.windows.BOOL, os.windows.FALSE), + 0 => os.windows.TRUE, + else => unreachable, + }; + }; + + // Return bytes received on success. + if (rc != os.windows.FALSE) + return transferred; + + return switch (os.windows.ws2_32.WSAGetLastError()) { + .WSA_IO_PENDING, .WSAEWOULDBLOCK, .WSA_IO_INCOMPLETE => error.WouldBlock, + .WSANOTINITIALISED => unreachable, // WSAStartup() was called + .WSA_INVALID_HANDLE => unreachable, // we dont use OVERLAPPED.hEvent + .WSA_INVALID_PARAMETER => unreachable, // parameters are fine + .WSAECONNABORTED => error.ConnectionRefused, + .WSAECONNRESET => error.ConnectionResetByPeer, + .WSAEDISCON => unreachable, // we only stream sockets + .WSAEFAULT => unreachable, // invalid buffer + .WSAEINTR => unreachable, // this is non blocking + .WSAEINPROGRESS => unreachable, // this is non blocking + .WSAEINVAL => unreachable, // invalid socket type + .WSAEMSGSIZE => error.MessageTooBig, + .WSAENETDOWN => error.NetworkSubsystemFailed, + .WSAENETRESET => error.ConnectionResetByPeer, + .WSAENOTCONN => error.SocketNotConnected, + .WSAEOPNOTSUPP => unreachable, // we dont use MSG_OOB or MSG_PARTIAL + .WSAESHUTDOWN => error.SocketNotConnected, + .WSAETIMEDOUT => error.ConnectionRefused, + .WSA_OPERATION_ABORTED => unreachable, // operation was cancelled + else => |err| os.windows.unexpectedWSAError(err), + }; + } + }, + ); +} + +pub fn read( + self: *IO, + comptime Context: type, + context: Context, + comptime callback: fn ( + context: Context, + completion: *Completion, + result: ReadError!usize, + ) void, + completion: *Completion, + fd: bun.FileDescriptor, + buffer: []u8, + offset: ?u64, +) void { + self.submit( + context, + callback, + completion, + .read, + .{ + .fd = fd, + .buf = buffer.ptr, + .len = @as(u32, @intCast(buffer_limit(buffer.len))), + .offset = offset, + }, + struct { + fn do_operation(ctx: Completion.Context, op: anytype) ReadError!usize { + // Do a synchronous read for now. + _ = ctx; + if (op.offset) |o| { + return os.pread(bun.fdcast(op.fd), op.buf[0..op.len], o) catch |err| switch (err) { + error.OperationAborted => unreachable, + error.BrokenPipe => unreachable, + error.ConnectionTimedOut => unreachable, + error.AccessDenied => error.InputOutput, + else => |e| e, + }; + } else { + return os.read(bun.fdcast(op.fd), op.buf[0..op.len]) catch |err| switch (err) { + error.OperationAborted => unreachable, + error.BrokenPipe => unreachable, + error.ConnectionTimedOut => unreachable, + error.AccessDenied => error.InputOutput, + else => |e| e, + }; + } + } + }, + ); +} + +pub fn write( + self: *IO, + comptime Context: type, + context: Context, + comptime callback: fn ( + context: Context, + completion: *Completion, + result: WriteError!usize, + ) void, + completion: *Completion, + fd: bun.FileDescriptor, + buffer: []const u8, + offset: u64, +) void { + self.submit( + context, + callback, + completion, + .write, + .{ + .fd = fd, + .buf = buffer.ptr, + .len = @as(u32, @intCast(buffer_limit(buffer.len))), + .offset = offset, + }, + struct { + fn do_operation(ctx: Completion.Context, op: anytype) WriteError!usize { + // Do a synchronous write for now. + _ = ctx; + if (op.offset) |off| { + return os.pwrite(bun.fdcast(op.fd), op.buf[0..op.len], off); + } else { + return os.write(bun.fdcast(op.fd), op.buf[0..op.len]); + } + } + }, + ); +} + +pub fn close( + self: *IO, + comptime Context: type, + context: Context, + comptime callback: fn ( + context: Context, + completion: *Completion, + result: CloseError!void, + ) void, + completion: *Completion, + fd: bun.FileDescriptor, +) void { + self.submit( + context, + callback, + completion, + .close, + .{ .fd = fd }, + struct { + fn do_operation(ctx: Completion.Context, op: anytype) CloseError!void { + _ = ctx; + + // Check if the fd is a SOCKET by seeing if getsockopt() returns ENOTSOCK + // https://stackoverflow.com/a/50981652 + const socket = @as(os.socket_t, @ptrCast(bun.fdcast(op.fd))); + getsockoptError(socket) catch |err| switch (err) { + error.FileDescriptorNotASocket => return os.windows.CloseHandle(bun.fdcast(op.fd)), + else => {}, + }; + + os.closeSocket(socket); + } + }, + ); +} + +pub const TimeoutError = error{Canceled} || os.UnexpectedError; + +pub fn timeout( + self: *IO, + comptime Context: type, + context: Context, + comptime callback: fn ( + context: Context, + completion: *Completion, + result: TimeoutError!void, + ) void, + completion: *Completion, + nanoseconds: u63, +) void { + self.submit( + context, + callback, + completion, + .timeout, + .{ .deadline = self.timer.monotonic() + nanoseconds }, + struct { + fn do_operation(ctx: Completion.Context, op: anytype) TimeoutError!void { + _ = ctx; + _ = op; + return; + } + }, + ); +} + +pub const INVALID_SOCKET = os.windows.ws2_32.INVALID_SOCKET; + +/// Creates a socket that can be used for async operations with the IO instance. +pub fn open_socket(self: *IO, family: u32, sock_type: u32, protocol: u32) !os.socket_t { + // SOCK_NONBLOCK | SOCK_CLOEXEC + var flags: os.windows.DWORD = 0; + flags |= os.windows.ws2_32.WSA_FLAG_OVERLAPPED; + flags |= os.windows.ws2_32.WSA_FLAG_NO_HANDLE_INHERIT; + + const socket = try os.windows.WSASocketW( + @as(i32, @bitCast(family)), + @as(i32, @bitCast(sock_type)), + @as(i32, @bitCast(protocol)), + null, + 0, + flags, + ); + errdefer os.closeSocket(socket); + + const socket_iocp = try os.windows.CreateIoCompletionPort(socket, self.iocp, 0, 0); + assert(socket_iocp == self.iocp); + + // Ensure that synchronous IO completion doesn't queue an unneeded overlapped + // and that the event for the socket (WaitForSingleObject) doesn't need to be set. + var mode: os.windows.BYTE = 0; + mode |= os.windows.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS; + mode |= os.windows.FILE_SKIP_SET_EVENT_ON_HANDLE; + + const handle = @as(os.windows.HANDLE, @ptrCast(socket)); + try os.windows.SetFileCompletionNotificationModes(handle, mode); + + return socket; +} + +/// Opens a directory with read only access. +pub fn open_dir(dir_path: [:0]const u8) !os.fd_t { + const dir = try std.fs.cwd().openDirZ(dir_path, .{}); + return dir.fd; +} + +/// Opens or creates a journal file: +/// - For reading and writing. +/// - For Direct I/O (required on windows). +/// - Obtains an advisory exclusive lock to the file descriptor. +/// - Allocates the file contiguously on disk if this is supported by the file system. +/// - Ensures that the file data is durable on disk. +/// The caller is responsible for ensuring that the parent directory inode is durable. +/// - Verifies that the file size matches the expected file size before returning. +pub fn open_file( + self: *IO, + dir_handle: os.fd_t, + relative_path: [:0]const u8, + size: u64, + must_create: bool, +) !os.fd_t { + _ = size; + _ = self; + + assert(relative_path.len > 0); + + const path_w = try os.windows.sliceToPrefixedFileW(relative_path); + + // FILE_CREATE = O_CREAT | O_EXCL + var creation_disposition: os.windows.DWORD = 0; + if (must_create) { + log.info("creating \"{s}\"...", .{relative_path}); + creation_disposition = os.windows.FILE_CREATE; + } else { + log.info("opening \"{s}\"...", .{relative_path}); + creation_disposition = os.windows.OPEN_EXISTING; + } + + // O_EXCL + var shared_mode: os.windows.DWORD = 0; + + // O_RDWR + var access_mask: os.windows.DWORD = 0; + access_mask |= os.windows.GENERIC_READ; + access_mask |= os.windows.GENERIC_WRITE; + + // O_DIRECT | O_DSYNC + var attributes: os.windows.DWORD = 0; + // attributes |= os.windows.FILE_FLAG_NO_BUFFERING; + // attributes |= os.windows.FILE_FLAG_WRITE_THROUGH; + + // This is critical as we rely on O_DSYNC for fsync() whenever we write to the file: + // assert((attributes & os.windows.FILE_FLAG_WRITE_THROUGH) > 0); + + // TODO: Add ReadFileEx/WriteFileEx support. + // Not currently needed for O_DIRECT disk IO. + attributes |= os.windows.FILE_FLAG_OVERLAPPED; + + const handle = os.windows.kernel32.CreateFileW( + path_w.span(), + access_mask, + shared_mode, + null, // no security attributes required + creation_disposition, + attributes, + null, // no existing template file + ); + + if (handle == os.windows.INVALID_HANDLE_VALUE) { + return switch (os.windows.kernel32.GetLastError()) { + .ACCESS_DENIED => error.AccessDenied, + else => |err| os.windows.unexpectedError(err), + }; + } + + errdefer os.windows.CloseHandle(handle); + + // // Obtain an advisory exclusive lock + // // even when we haven't given shared access to other processes. + // fs_lock(handle, size) catch |err| switch (err) { + // error.WouldBlock => @panic("another process holds the data file lock"), + // else => return err, + // }; + + // // Ask the file system to allocate contiguous sectors for the file (if possible): + // if (must_create) { + // log.info("allocating {}...", .{std.fmt.fmtIntSizeBin(size)}); + // fs_allocate(handle, size) catch { + // log.warn("file system failed to preallocate the file memory", .{}); + // log.info("allocating by writing to the last sector of the file instead...", .{}); + + // const sector_size = config.sector_size; + // const sector: [sector_size]u8 align(sector_size) = [_]u8{0} ** sector_size; + + // // Handle partial writes where the physical sector is less than a logical sector: + // const write_offset = size - sector.len; + // var written: usize = 0; + // while (written < sector.len) { + // written += try os.pwrite(handle, sector[written..], write_offset + written); + // } + // }; + // } + + // // The best fsync strategy is always to fsync before reading because this prevents us from + // // making decisions on data that was never durably written by a previously crashed process. + // // We therefore always fsync when we open the path, also to wait for any pending O_DSYNC. + // // Thanks to Alex Miller from FoundationDB for diving into our source and pointing this out. + // try os.fsync(handle); + + // We cannot fsync the directory handle on Windows. + // We have no way to open a directory with write access. + // + // try os.fsync(dir_handle); + _ = dir_handle; + + return handle; +} + +fn fs_lock(handle: bun.FileDescriptor, size: u64) !void { + // TODO: Look into using SetFileIoOverlappedRange() for better unbuffered async IO perf + // NOTE: Requires SeLockMemoryPrivilege. + + const kernel32 = struct { + const LOCKFILE_EXCLUSIVE_LOCK = 0x2; + const LOCKFILE_FAIL_IMMEDIATELY = 0o01; + + extern "kernel32" fn LockFileEx( + hFile: os.windows.HANDLE, + dwFlags: os.windows.DWORD, + dwReserved: os.windows.DWORD, + nNumberOfBytesToLockLow: os.windows.DWORD, + nNumberOfBytesToLockHigh: os.windows.DWORD, + lpOverlapped: ?*os.windows.OVERLAPPED, + ) callconv(os.windows.WINAPI) os.windows.BOOL; + }; + + // hEvent = null + // Offset & OffsetHigh = 0 + var lock_overlapped = std.mem.zeroes(os.windows.OVERLAPPED); + + // LOCK_EX | LOCK_NB + var lock_flags: os.windows.DWORD = 0; + lock_flags |= kernel32.LOCKFILE_EXCLUSIVE_LOCK; + lock_flags |= kernel32.LOCKFILE_FAIL_IMMEDIATELY; + + const locked = kernel32.LockFileEx( + handle, + lock_flags, + 0, // reserved param is always zero + @as(u32, @truncate(size)), // low bits of size + @as(u32, @truncate(size >> 32)), // high bits of size + &lock_overlapped, + ); + + if (locked == os.windows.FALSE) { + return switch (os.windows.kernel32.GetLastError()) { + .IO_PENDING => error.WouldBlock, + else => |err| os.windows.unexpectedError(err), + }; + } +} + +fn fs_allocate(handle: os.fd_t, size: u64) !void { + // TODO: Look into using SetFileValidData() instead + // NOTE: Requires SE_MANAGE_VOLUME_NAME privilege + + // Move the file pointer to the start + size + const seeked = os.windows.kernel32.SetFilePointerEx( + handle, + @as(i64, @intCast(size)), + null, // no reference to new file pointer + os.windows.FILE_BEGIN, + ); + + if (seeked == os.windows.FALSE) { + return switch (os.windows.kernel32.GetLastError()) { + .INVALID_HANDLE => unreachable, + .INVALID_PARAMETER => unreachable, + else => |err| os.windows.unexpectedError(err), + }; + } + + // Mark the moved file pointer (start + size) as the physical EOF. + const allocated = os.windows.kernel32.SetEndOfFile(handle); + if (allocated == os.windows.FALSE) { + const err = os.windows.kernel32.GetLastError(); + return os.windows.unexpectedError(err); + } +} + +// TODO: use os.getsockoptError when fixed for windows in stdlib +fn getsockoptError(socket: os.socket_t) ConnectError!void { + var err_code: u32 = undefined; + var size: i32 = @sizeOf(u32); + const rc = os.windows.ws2_32.getsockopt( + socket, + os.SOL.SOCKET, + os.SO.ERROR, + std.mem.asBytes(&err_code), + &size, + ); + + if (rc != 0) { + switch (os.windows.ws2_32.WSAGetLastError()) { + .WSAENETDOWN => return error.NetworkUnreachable, + .WSANOTINITIALISED => unreachable, // WSAStartup() was never called + .WSAEFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space. + .WSAEINVAL => unreachable, // The level parameter is unknown or invalid + .WSAENOPROTOOPT => unreachable, // The option is unknown at the level indicated. + .WSAENOTSOCK => return error.FileDescriptorNotASocket, + else => |err| return os.windows.unexpectedWSAError(err), + } + } + + assert(size == 4); + if (err_code == 0) + return; + + const ws_err = @as(os.windows.ws2_32.WinsockError, @enumFromInt(@as(u16, @intCast(err_code)))); + return switch (ws_err) { + .WSAEACCES => error.PermissionDenied, + .WSAEADDRINUSE => error.AddressInUse, + .WSAEADDRNOTAVAIL => error.AddressNotAvailable, + .WSAEAFNOSUPPORT => error.AddressFamilyNotSupported, + .WSAEALREADY => error.ConnectionPending, + .WSAEBADF => unreachable, + .WSAECONNREFUSED => error.ConnectionRefused, + .WSAEFAULT => unreachable, + .WSAEISCONN => unreachable, // error.AlreadyConnected, + .WSAENETUNREACH => error.NetworkUnreachable, + .WSAENOTSOCK => error.FileDescriptorNotASocket, + .WSAEPROTOTYPE => unreachable, + .WSAETIMEDOUT => error.ConnectionTimedOut, + .WSAECONNRESET => error.ConnectionResetByPeer, + else => |e| os.windows.unexpectedWSAError(e), + }; +} + +pub var global: IO = undefined; +pub var global_loaded: bool = false; +pub const AcceptError = os.AcceptError || os.SetSockOptError; + +pub const ReadError = error{ + WouldBlock, + NotOpenForReading, + ConnectionResetByPeer, + Alignment, + InputOutput, + IsDir, + SystemResources, + Unseekable, +} || os.UnexpectedError || os.PReadError; diff --git a/src/libarchive/libarchive.zig b/src/libarchive/libarchive.zig index 69fe43b70..c6276b1cc 100644 --- a/src/libarchive/libarchive.zig +++ b/src/libarchive/libarchive.zig @@ -437,9 +437,10 @@ pub const Archive = struct { const size = @as(usize, @intCast(@max(lib.archive_entry_size(entry), 0))); if (size > 0) { var opened = dir.dir.openFileZ(pathname, .{ .mode = .write_only }) catch continue :loop; - var stat = try opened.stat(); + defer opened.close(); + const stat_size = try opened.getEndPos(); - if (stat.size > 0) { + if (stat_size > 0) { const is_already_top_level = dirname.len == 0; const path_to_use_: string = brk: { const __pathname: string = bun.asByteSlice(pathname); @@ -539,26 +540,37 @@ pub const Archive = struct { if ((mode & 0o4) != 0) mode |= 0o1; - std.os.mkdiratZ(dir_fd, pathname, @as(u32, @intCast(mode))) catch |err| { - if (err == error.PathAlreadyExists or err == error.NotDir) break; - try dir.makePath(std.fs.path.dirname(slice) orelse return err); - try std.os.mkdiratZ(dir_fd, pathname, 0o777); - }; + if (comptime Environment.isWindows) { + std.os.mkdirat(dir_fd, pathname, @as(u32, @intCast(mode))) catch |err| { + if (err == error.PathAlreadyExists or err == error.NotDir) break; + try dir.makePath(std.fs.path.dirname(slice) orelse return err); + try std.os.mkdirat(dir_fd, pathname, 0o777); + }; + } else { + std.os.mkdiratZ(dir_fd, pathname, @as(u32, @intCast(mode))) catch |err| { + if (err == error.PathAlreadyExists or err == error.NotDir) break; + try dir.makePath(std.fs.path.dirname(slice) orelse return err); + try std.os.mkdiratZ(dir_fd, pathname, 0o777); + }; + } }, Kind.sym_link => { const link_target = lib.archive_entry_symlink(entry).?; - - std.os.symlinkatZ(link_target, dir_fd, pathname) catch |err| brk: { - switch (err) { - error.AccessDenied, error.FileNotFound => { - dir.makePath(std.fs.path.dirname(slice) orelse return err) catch {}; - break :brk try std.os.symlinkatZ(link_target, dir_fd, pathname); - }, - else => { - return err; - }, - } - }; + if (comptime Environment.isWindows) { + bun.todo(@src(), {}); + } else { + std.os.symlinkatZ(link_target, dir_fd, pathname) catch |err| brk: { + switch (err) { + error.AccessDenied, error.FileNotFound => { + dir.makePath(std.fs.path.dirname(slice) orelse return err) catch {}; + break :brk try std.os.symlinkatZ(link_target, dir_fd, pathname); + }, + else => { + return err; + }, + } + }; + } }, Kind.file => { const mode = @as(std.os.mode_t, @intCast(lib.archive_entry_perm(entry))); @@ -601,7 +613,7 @@ pub const Archive = struct { var read = lib.archive_read_data(archive, plucker_.contents.list.items.ptr, size); try plucker_.contents.inflate(@as(usize, @intCast(read))); plucker_.found = read > 0; - plucker_.fd = file.handle; + plucker_.fd = bun.toFD(file.handle); continue :loop; } } @@ -618,7 +630,7 @@ pub const Archive = struct { var retries_remaining: u8 = 5; possibly_retry: while (retries_remaining != 0) : (retries_remaining -= 1) { - switch (lib.archive_read_data_into_fd(archive, file.handle)) { + switch (lib.archive_read_data_into_fd(archive, bun.fdi32(file.handle))) { lib.ARCHIVE_EOF => break :loop, lib.ARCHIVE_OK => break :possibly_retry, lib.ARCHIVE_RETRY => { diff --git a/src/linker.zig b/src/linker.zig index 7cf9b9ea1..4fe291d5d 100644 --- a/src/linker.zig +++ b/src/linker.zig @@ -104,7 +104,7 @@ pub const Linker = struct { file_path: Fs.Path, fd: ?FileDescriptorType, ) !Fs.FileSystem.RealFS.ModKey { - var file: std.fs.File = if (fd) |_fd| std.fs.File{ .handle = _fd } else try std.fs.openFileAbsolute(file_path.text, .{ .mode = .read_only }); + var file: std.fs.File = if (fd) |_fd| std.fs.File{ .handle = bun.fdcast(_fd) } else try std.fs.openFileAbsolute(file_path.text, .{ .mode = .read_only }); Fs.FileSystem.setMaxFd(file.handle); const modkey = try Fs.FileSystem.RealFS.ModKey.generate(&this.fs.fs, file_path.text, file); diff --git a/src/linux_c.zig b/src/linux_c.zig index 0c0631738..9ee9ed6ca 100644 --- a/src/linux_c.zig +++ b/src/linux_c.zig @@ -416,25 +416,25 @@ pub const struct_sysinfo = extern struct { }; pub extern fn sysinfo(__info: [*c]struct_sysinfo) c_int; -pub fn get_free_memory() u64 { +pub fn getFreeMemory() u64 { var info: struct_sysinfo = undefined; if (sysinfo(&info) == @as(c_int, 0)) return @as(u64, @bitCast(info.freeram)) *% @as(c_ulong, @bitCast(@as(c_ulong, info.mem_unit))); return 0; } -pub fn get_total_memory() u64 { +pub fn getTotalMemory() u64 { var info: struct_sysinfo = undefined; if (sysinfo(&info) == @as(c_int, 0)) return @as(u64, @bitCast(info.totalram)) *% @as(c_ulong, @bitCast(@as(c_ulong, info.mem_unit))); return 0; } -pub fn get_system_uptime() u64 { +pub fn getSystemUptime() u64 { var info: struct_sysinfo = undefined; if (sysinfo(&info) == @as(c_int, 0)) return @as(u64, @bitCast(info.uptime)); return 0; } -pub fn get_system_loadavg() [3]f64 { +pub fn getSystemLoadavg() [3]f64 { var info: struct_sysinfo = undefined; if (sysinfo(&info) == @as(c_int, 0)) { return [3]f64{ @@ -446,7 +446,7 @@ pub fn get_system_loadavg() [3]f64 { return [3]f64{ 0, 0, 0 }; } -pub fn get_version(name_buffer: *[std.os.HOST_NAME_MAX]u8) []const u8 { +pub fn get_version(name_buffer: *[bun.HOST_NAME_MAX]u8) []const u8 { const uts = std.os.uname(); const result = bun.sliceTo(&uts.version, 0); bun.copy(u8, name_buffer, result); @@ -454,7 +454,7 @@ pub fn get_version(name_buffer: *[std.os.HOST_NAME_MAX]u8) []const u8 { return name_buffer[0..result.len]; } -pub fn get_release(name_buffer: *[std.os.HOST_NAME_MAX]u8) []const u8 { +pub fn get_release(name_buffer: *[bun.HOST_NAME_MAX]u8) []const u8 { const uts = std.os.uname(); const result = bun.sliceTo(&uts.release, 0); bun.copy(u8, name_buffer, result); @@ -571,3 +571,10 @@ pub const freeifaddrs = net_c.freeifaddrs; pub const IFF_RUNNING = net_c.IFF_RUNNING; pub const IFF_UP = net_c.IFF_UP; pub const IFF_LOOPBACK = net_c.IFF_LOOPBACK; + +pub const Mode = u32; +pub const E = std.os.E; + +pub fn getErrno(rc: anytype) E { + return std.c.getErrno(rc); +} diff --git a/src/logger.zig b/src/logger.zig index 9ec2dc7ca..7340efc3d 100644 --- a/src/logger.zig +++ b/src/logger.zig @@ -1283,7 +1283,7 @@ pub const Source = struct { return Source{ .path = path, .key_path = path, .contents = "" }; } - pub fn initFile(file: fs.File, _: std.mem.Allocator) !Source { + pub fn initFile(file: fs.PathContentsPair, _: std.mem.Allocator) !Source { var source = Source{ .path = file.path, .key_path = fs.Path.init(file.path.text), @@ -1293,7 +1293,7 @@ pub const Source = struct { return source; } - pub fn initRecycledFile(file: fs.File, _: std.mem.Allocator) !Source { + pub fn initRecycledFile(file: fs.PathContentsPair, _: std.mem.Allocator) !Source { var source = Source{ .path = file.path, .key_path = fs.Path.init(file.path.text), diff --git a/src/main.zig b/src/main.zig index f4df0814e..52cf33d53 100644 --- a/src/main.zig +++ b/src/main.zig @@ -15,6 +15,9 @@ pub fn main() void { const bun = @import("root").bun; const Output = bun.Output; const Environment = bun.Environment; + if (comptime Environment.isWindows) { + bun.win32.populateArgv(); + } if (comptime Environment.isRelease) CrashReporter.start() catch unreachable; diff --git a/src/network_thread.zig b/src/network_thread.zig index e932bc414..e1c2046a8 100644 --- a/src/network_thread.zig +++ b/src/network_thread.zig @@ -236,7 +236,7 @@ pub fn init() !void { } else if (comptime Environment.isMac) { global.waker = try AsyncIO.Waker.init(@import("root").bun.default_allocator); } else { - @compileLog("TODO: Waker"); + global.waker = try AsyncIO.Waker.init(@import("root").bun.default_allocator); } global.thread = try std.Thread.spawn(.{ .stack_size = 2 * 1024 * 1024 }, onStartIOThread, .{ diff --git a/src/options.zig b/src/options.zig index 8206be31e..c4961228b 100644 --- a/src/options.zig +++ b/src/options.zig @@ -1679,153 +1679,157 @@ pub const BundleOptions = struct { opts.external = ExternalModules.init(allocator, &fs.fs, fs.top_level_dir, transform.external, log, opts.target); opts.out_extensions = opts.target.outExtensions(allocator); - if (transform.serve orelse false) { - opts.preserve_extensions = true; - opts.append_package_version_in_query_string = true; - if (opts.framework == null) - opts.env.behavior = .load_all; - - opts.source_map = SourceMapOption.fromApi(transform.source_map orelse Api.SourceMapMode.external); - - opts.resolve_mode = .lazy; - - var dir_to_use: string = opts.routes.static_dir; - const static_dir_set = opts.routes.static_dir_enabled or dir_to_use.len == 0; - var disabled_static = false; - - var chosen_dir = dir_to_use; - - if (!static_dir_set) { - chosen_dir = choice: { - if (fs.fs.readDirectory(fs.top_level_dir, null, 0, false)) |dir_| { - const dir: *const Fs.FileSystem.RealFS.EntriesOption = dir_; - switch (dir.*) { - .entries => { - if (dir.entries.getComptimeQuery("public")) |q| { - if (q.entry.kind(&fs.fs, true) == .dir) { - break :choice "public"; + if (comptime !bun.Environment.isWindows) { + if (transform.serve orelse false) { + opts.preserve_extensions = true; + opts.append_package_version_in_query_string = true; + if (opts.framework == null) + opts.env.behavior = .load_all; + + opts.source_map = SourceMapOption.fromApi(transform.source_map orelse Api.SourceMapMode.external); + + opts.resolve_mode = .lazy; + + var dir_to_use: string = opts.routes.static_dir; + const static_dir_set = opts.routes.static_dir_enabled or dir_to_use.len == 0; + var disabled_static = false; + + var chosen_dir = dir_to_use; + + if (!static_dir_set) { + chosen_dir = choice: { + if (fs.fs.readDirectory(fs.top_level_dir, null, 0, false)) |dir_| { + const dir: *const Fs.FileSystem.RealFS.EntriesOption = dir_; + switch (dir.*) { + .entries => { + if (dir.entries.getComptimeQuery("public")) |q| { + if (q.entry.kind(&fs.fs, true) == .dir) { + break :choice "public"; + } } - } - if (dir.entries.getComptimeQuery("static")) |q| { - if (q.entry.kind(&fs.fs, true) == .dir) { - break :choice "static"; + if (dir.entries.getComptimeQuery("static")) |q| { + if (q.entry.kind(&fs.fs, true) == .dir) { + break :choice "static"; + } } - } - break :choice "."; - }, - else => { - break :choice ""; - }, + break :choice "."; + }, + else => { + break :choice ""; + }, + } + } else |_| { + break :choice ""; } - } else |_| { - break :choice ""; - } - }; - - if (chosen_dir.len == 0) { - disabled_static = true; - opts.routes.static_dir_enabled = false; - } - } + }; - if (!disabled_static) { - var _dirs = [_]string{chosen_dir}; - opts.routes.static_dir = try fs.absAlloc(allocator, &_dirs); - const static_dir = std.fs.openIterableDirAbsolute(opts.routes.static_dir, .{}) catch |err| brk: { - switch (err) { - error.FileNotFound => { - opts.routes.static_dir_enabled = false; - }, - error.AccessDenied => { - Output.prettyErrorln( - "error: access denied when trying to open directory for static files: \"{s}\".\nPlease re-open bun with access to this folder or pass a different folder via \"--public-dir\". Note: --public-dir is relative to --cwd (or the process' current working directory).\n\nThe public folder is where static assets such as images, fonts, and .html files go.", - .{opts.routes.static_dir}, - ); - std.process.exit(1); - }, - else => { - Output.prettyErrorln( - "error: \"{s}\" when accessing public folder: \"{s}\"", - .{ @errorName(err), opts.routes.static_dir }, - ); - std.process.exit(1); - }, + if (chosen_dir.len == 0) { + disabled_static = true; + opts.routes.static_dir_enabled = false; } - - break :brk null; - }; - if (static_dir) |handle| { - opts.routes.static_dir_handle = handle.dir; } - opts.routes.static_dir_enabled = opts.routes.static_dir_handle != null; - } - - const should_try_to_find_a_index_html_file = (opts.framework == null or !opts.framework.?.server.isEnabled()) and - !opts.routes.routes_enabled; - - if (opts.routes.static_dir_enabled and should_try_to_find_a_index_html_file) { - const dir = opts.routes.static_dir_handle.?; - var index_html_file = dir.openFile("index.html", .{ .mode = .read_only }) catch |err| brk: { - switch (err) { - error.FileNotFound => {}, - else => { - Output.prettyErrorln( - "{s} when trying to open {s}/index.html. single page app routing is disabled.", - .{ @errorName(err), opts.routes.static_dir }, - ); - }, - } - opts.routes.single_page_app_routing = false; - break :brk null; - }; + if (!disabled_static) { + var _dirs = [_]string{chosen_dir}; + opts.routes.static_dir = try fs.absAlloc(allocator, &_dirs); + const static_dir = std.fs.openIterableDirAbsolute(opts.routes.static_dir, .{}) catch |err| brk: { + switch (err) { + error.FileNotFound => { + opts.routes.static_dir_enabled = false; + }, + error.AccessDenied => { + Output.prettyErrorln( + "error: access denied when trying to open directory for static files: \"{s}\".\nPlease re-open bun with access to this folder or pass a different folder via \"--public-dir\". Note: --public-dir is relative to --cwd (or the process' current working directory).\n\nThe public folder is where static assets such as images, fonts, and .html files go.", + .{opts.routes.static_dir}, + ); + std.process.exit(1); + }, + else => { + Output.prettyErrorln( + "error: \"{s}\" when accessing public folder: \"{s}\"", + .{ @errorName(err), opts.routes.static_dir }, + ); + std.process.exit(1); + }, + } - if (index_html_file) |index_dot_html| { - opts.routes.single_page_app_routing = true; - opts.routes.single_page_app_fd = index_dot_html.handle; + break :brk null; + }; + if (static_dir) |handle| { + opts.routes.static_dir_handle = handle.dir; + } + opts.routes.static_dir_enabled = opts.routes.static_dir_handle != null; } - } - if (!opts.routes.single_page_app_routing and should_try_to_find_a_index_html_file) { - attempt: { - var abs_buf: [bun.MAX_PATH_BYTES]u8 = undefined; - // If it's not in static-dir/index.html, check if it's in top level dir/index.html - var parts = [_]string{"index.html"}; - var full_path = resolve_path.joinAbsStringBuf(fs.top_level_dir, &abs_buf, &parts, .auto); - abs_buf[full_path.len] = 0; - var abs_buf_z: [:0]u8 = abs_buf[0..full_path.len :0]; + const should_try_to_find_a_index_html_file = (opts.framework == null or !opts.framework.?.server.isEnabled()) and + !opts.routes.routes_enabled; - const file = std.fs.openFileAbsoluteZ(abs_buf_z, .{ .mode = .read_only }) catch |err| { + if (opts.routes.static_dir_enabled and should_try_to_find_a_index_html_file) { + const dir = opts.routes.static_dir_handle.?; + var index_html_file = dir.openFile("index.html", .{ .mode = .read_only }) catch |err| brk: { switch (err) { error.FileNotFound => {}, else => { Output.prettyErrorln( "{s} when trying to open {s}/index.html. single page app routing is disabled.", - .{ @errorName(err), fs.top_level_dir }, + .{ @errorName(err), opts.routes.static_dir }, ); }, } - break :attempt; + + opts.routes.single_page_app_routing = false; + break :brk null; }; - opts.routes.single_page_app_routing = true; - opts.routes.single_page_app_fd = file.handle; + if (index_html_file) |index_dot_html| { + opts.routes.single_page_app_routing = true; + opts.routes.single_page_app_fd = index_dot_html.handle; + } } - } - // Windows has weird locking rules for file access. - // so it's a bad idea to keep a file handle open for a long time on Windows. - if (Environment.isWindows and opts.routes.static_dir_handle != null) { - opts.routes.static_dir_handle.?.close(); - } - opts.hot_module_reloading = opts.target.isWebLike(); + if (!opts.routes.single_page_app_routing and should_try_to_find_a_index_html_file) { + attempt: { + var abs_buf: [bun.MAX_PATH_BYTES]u8 = undefined; + // If it's not in static-dir/index.html, check if it's in top level dir/index.html + var parts = [_]string{"index.html"}; + var full_path = resolve_path.joinAbsStringBuf(fs.top_level_dir, &abs_buf, &parts, .auto); + abs_buf[full_path.len] = 0; + var abs_buf_z: [:0]u8 = abs_buf[0..full_path.len :0]; + + const file = std.fs.openFileAbsoluteZ(abs_buf_z, .{ .mode = .read_only }) catch |err| { + switch (err) { + error.FileNotFound => {}, + else => { + Output.prettyErrorln( + "{s} when trying to open {s}/index.html. single page app routing is disabled.", + .{ @errorName(err), fs.top_level_dir }, + ); + }, + } + break :attempt; + }; + + opts.routes.single_page_app_routing = true; + opts.routes.single_page_app_fd = file.handle; + } + } + + // Windows has weird locking rules for file access. + // so it's a bad idea to keep a file handle open for a long time on Windows. + if (Environment.isWindows and opts.routes.static_dir_handle != null) { + opts.routes.static_dir_handle.?.close(); + } + opts.hot_module_reloading = opts.target.isWebLike(); - if (transform.disable_hmr orelse false) - opts.hot_module_reloading = false; + if (transform.disable_hmr orelse false) + opts.hot_module_reloading = false; - opts.serve = true; + opts.serve = true; + } else { + opts.source_map = SourceMapOption.fromApi(transform.source_map orelse Api.SourceMapMode._none); + } } else { opts.source_map = SourceMapOption.fromApi(transform.source_map orelse Api.SourceMapMode._none); } @@ -1841,7 +1845,7 @@ pub const BundleOptions = struct { if (opts.write and opts.output_dir.len > 0) { opts.output_dir_handle = try openOutputDir(opts.output_dir); - opts.output_dir = try fs.getFdPath(opts.output_dir_handle.?.fd); + opts.output_dir = try fs.getFdPath(bun.toFD(opts.output_dir_handle.?.fd)); } opts.polyfill_node_globals = opts.target == .browser; @@ -1950,17 +1954,17 @@ pub const OutputFile = struct { // We may use a different system call pub const FileOperation = struct { pathname: string, - fd: FileDescriptorType = 0, - dir: FileDescriptorType = 0, + fd: FileDescriptorType = bun.invalid_fd, + dir: FileDescriptorType = bun.invalid_fd, is_tmpdir: bool = false, is_outdir: bool = false, close_handle_on_complete: bool = false, autowatch: bool = true, - pub fn fromFile(fd: FileDescriptorType, pathname: string) FileOperation { + pub fn fromFile(fd: anytype, pathname: string) FileOperation { return .{ .pathname = pathname, - .fd = fd, + .fd = bun.toFD(fd), }; } @@ -2035,7 +2039,7 @@ pub const OutputFile = struct { pub fn initFileWithDir(file: std.fs.File, pathname: string, size: usize, dir: std.fs.Dir) OutputFile { var res = initFile(file, pathname, size); - res.value.copy.dir_handle = dir.fd; + res.value.copy.dir_handle = bun.toFD(dir.fd); return res; } @@ -2085,7 +2089,7 @@ pub const OutputFile = struct { .file => |file| Value{ .copy = brk: { var op = FileOperation.fromFile(file.file.handle, options.output_path); - op.dir = file.dir.fd; + op.dir = bun.toFD(file.dir.fd); break :brk op; }, }, @@ -2111,11 +2115,11 @@ pub const OutputFile = struct { } pub fn moveTo(file: *const OutputFile, _: string, rel_path: []u8, dir: FileDescriptorType) !void { - try bun.C.moveFileZ(file.value.move.dir, &(try std.os.toPosixPath(file.value.move.getPathname())), dir, &(try std.os.toPosixPath(rel_path))); + try bun.C.moveFileZ(bun.fdcast(file.value.move.dir), &(try std.os.toPosixPath(file.value.move.getPathname())), bun.fdcast(dir), &(try std.os.toPosixPath(rel_path))); } pub fn copyTo(file: *const OutputFile, _: string, rel_path: []u8, dir: FileDescriptorType) !void { - var dir_obj = std.fs.Dir{ .fd = dir }; + var dir_obj = std.fs.Dir{ .fd = bun.fdcast(dir) }; const file_out = (try dir_obj.createFile(rel_path, .{})); const fd_out = file_out.handle; diff --git a/src/report.zig b/src/report.zig index 827f8072d..5bdd5e221 100644 --- a/src/report.zig +++ b/src/report.zig @@ -340,59 +340,67 @@ pub noinline fn globalError(err: anyerror, trace_: @TypeOf(@errorReturnTrace())) Global.exit(1); }, error.SystemFdQuotaExceeded => { - const limit = std.os.getrlimit(.NOFILE) catch std.mem.zeroes(std.os.rlimit); - if (comptime Environment.isMac) { - Output.prettyError( - \\ - \\<r><red>error<r>: Your computer ran out of file descriptors <d>(<red>SystemFdQuotaExceeded<r><d>)<r> - \\ - \\<d>Current limit: {d}<r> - \\ - \\To fix this, try running: - \\ - \\ <cyan>sudo launchctl limit maxfiles 2147483646<r> - \\ <cyan>ulimit -n 2147483646<r> - \\ - \\That will only work until you reboot. - \\ - , - .{ - limit.cur, - }, - ); + if (comptime Environment.isPosix) { + const limit = std.os.getrlimit(.NOFILE) catch std.mem.zeroes(std.os.rlimit); + if (comptime Environment.isMac) { + Output.prettyError( + \\ + \\<r><red>error<r>: Your computer ran out of file descriptors <d>(<red>SystemFdQuotaExceeded<r><d>)<r> + \\ + \\<d>Current limit: {d}<r> + \\ + \\To fix this, try running: + \\ + \\ <cyan>sudo launchctl limit maxfiles 2147483646<r> + \\ <cyan>ulimit -n 2147483646<r> + \\ + \\That will only work until you reboot. + \\ + , + .{ + limit.cur, + }, + ); + } else { + Output.prettyError( + \\ + \\<r><red>error<r>: Your computer ran out of file descriptors <d>(<red>SystemFdQuotaExceeded<r><d>)<r> + \\ + \\<d>Current limit: {d}<r> + \\ + \\To fix this, try running: + \\ + \\ <cyan>sudo echo -e "\nfs.file-max=2147483646\n" >> /etc/sysctl.conf<r> + \\ <cyan>sudo sysctl -p<r> + \\ <cyan>ulimit -n 2147483646<r> + \\ + , + .{ + limit.cur, + }, + ); + + if (bun.getenvZ("USER")) |user| { + if (user.len > 0) { + Output.prettyError( + \\ + \\If that still doesn't work, you may need to add these lines to /etc/security/limits.conf: + \\ + \\ <cyan>{s} soft nofile 2147483646<r> + \\ <cyan>{s} hard nofile 2147483646<r> + \\ + , + .{ user, user }, + ); + } + } + } } else { Output.prettyError( - \\ \\<r><red>error<r>: Your computer ran out of file descriptors <d>(<red>SystemFdQuotaExceeded<r><d>)<r> - \\ - \\<d>Current limit: {d}<r> - \\ - \\To fix this, try running: - \\ - \\ <cyan>sudo echo -e "\nfs.file-max=2147483646\n" >> /etc/sysctl.conf<r> - \\ <cyan>sudo sysctl -p<r> - \\ <cyan>ulimit -n 2147483646<r> - \\ , - .{ - limit.cur, - }, + .{}, ); - - if (bun.getenvZ("USER")) |user| { - if (user.len > 0) { - Output.prettyError( - \\ - \\If that still doesn't work, you may need to add these lines to /etc/security/limits.conf: - \\ - \\ <cyan>{s} soft nofile 2147483646<r> - \\ <cyan>{s} hard nofile 2147483646<r> - \\ - , - .{ user, user }, - ); - } - } } Global.exit(1); @@ -401,71 +409,77 @@ pub noinline fn globalError(err: anyerror, trace_: @TypeOf(@errorReturnTrace())) Global.exit(1); }, error.ProcessFdQuotaExceeded => { - const limit = std.os.getrlimit(.NOFILE) catch std.mem.zeroes(std.os.rlimit); - if (comptime Environment.isMac) { - Output.prettyError( - \\ - \\<r><red>error<r>: bun ran out of file descriptors <d>(<red>ProcessFdQuotaExceeded<r><d>)<r> - \\ - \\<d>Current limit: {d}<r> - \\ - \\To fix this, try running: - \\ - \\ <cyan>ulimit -n 2147483646<r> - \\ - \\You may also need to run: - \\ - \\ <cyan>sudo launchctl limit maxfiles 2147483646<r> - \\ - , - .{ - limit.cur, - }, - ); + if (comptime Environment.isPosix) { + const limit = std.os.getrlimit(.NOFILE) catch std.mem.zeroes(std.os.rlimit); + if (comptime Environment.isMac) { + Output.prettyError( + \\ + \\<r><red>error<r>: bun ran out of file descriptors <d>(<red>ProcessFdQuotaExceeded<r><d>)<r> + \\ + \\<d>Current limit: {d}<r> + \\ + \\To fix this, try running: + \\ + \\ <cyan>ulimit -n 2147483646<r> + \\ + \\You may also need to run: + \\ + \\ <cyan>sudo launchctl limit maxfiles 2147483646<r> + \\ + , + .{ + limit.cur, + }, + ); + } else { + Output.prettyError( + \\ + \\<r><red>error<r>: bun ran out of file descriptors <d>(<red>ProcessFdQuotaExceeded<r><d>)<r> + \\ + \\<d>Current limit: {d}<r> + \\ + \\To fix this, try running: + \\ + \\ <cyan>ulimit -n 2147483646<r> + \\ + \\That will only work for the current shell. To fix this for the entire system, run: + \\ + \\ <cyan>sudo echo -e "\nfs.file-max=2147483646\n" >> /etc/sysctl.conf<r> + \\ <cyan>sudo sysctl -p<r> + \\ + , + .{ + limit.cur, + }, + ); + + if (bun.getenvZ("USER")) |user| { + if (user.len > 0) { + Output.prettyError( + \\ + \\If that still doesn't work, you may need to add these lines to /etc/security/limits.conf: + \\ + \\ <cyan>{s} soft nofile 2147483646<r> + \\ <cyan>{s} hard nofile 2147483646<r> + \\ + , + .{ user, user }, + ); + } + } + } } else { - Output.prettyError( - \\ + Output.prettyErrorln( \\<r><red>error<r>: bun ran out of file descriptors <d>(<red>ProcessFdQuotaExceeded<r><d>)<r> - \\ - \\<d>Current limit: {d}<r> - \\ - \\To fix this, try running: - \\ - \\ <cyan>ulimit -n 2147483646<r> - \\ - \\That will only work for the current shell. To fix this for the entire system, run: - \\ - \\ <cyan>sudo echo -e "\nfs.file-max=2147483646\n" >> /etc/sysctl.conf<r> - \\ <cyan>sudo sysctl -p<r> - \\ , - .{ - limit.cur, - }, + .{}, ); - - if (bun.getenvZ("USER")) |user| { - if (user.len > 0) { - Output.prettyError( - \\ - \\If that still doesn't work, you may need to add these lines to /etc/security/limits.conf: - \\ - \\ <cyan>{s} soft nofile 2147483646<r> - \\ <cyan>{s} hard nofile 2147483646<r> - \\ - , - .{ user, user }, - ); - } - } } Global.exit(1); }, // The usage of `unreachable` in Zig's std.os may cause the file descriptor problem to show up as other errors error.NotOpenForReading, error.Unexpected => { - const limit = std.os.getrlimit(.NOFILE) catch std.mem.zeroes(std.os.rlimit); - if (trace_) |trace| { print_stacktrace: { var debug_info = std.debug.getSelfDebugInfo() catch break :print_stacktrace; @@ -474,48 +488,58 @@ pub noinline fn globalError(err: anyerror, trace_: @TypeOf(@errorReturnTrace())) } } - if (limit.cur > 0 and limit.cur < (8096 * 2)) { - Output.prettyError( - \\ - \\<r><red>error<r>: An unknown error ocurred, possibly due to low max file descriptors <d>(<red>Unexpected<r><d>)<r> - \\ - \\<d>Current limit: {d}<r> - \\ - \\To fix this, try running: - \\ - \\ <cyan>ulimit -n 2147483646<r> - \\ - , - .{ - limit.cur, - }, - ); + if (comptime Environment.isPosix) { + const limit = std.os.getrlimit(.NOFILE) catch std.mem.zeroes(std.os.rlimit); - if (Environment.isLinux) { - if (bun.getenvZ("USER")) |user| { - if (user.len > 0) { - Output.prettyError( - \\ - \\If that still doesn't work, you may need to add these lines to /etc/security/limits.conf: - \\ - \\ <cyan>{s} soft nofile 2147483646<r> - \\ <cyan>{s} hard nofile 2147483646<r> - \\ - , - .{ - user, - user, - }, - ); - } - } - } else if (Environment.isMac) { + if (limit.cur > 0 and limit.cur < (8096 * 2)) { Output.prettyError( \\ - \\If that still doesn't work, you may need to run: + \\<r><red>error<r>: An unknown error ocurred, possibly due to low max file descriptors <d>(<red>Unexpected<r><d>)<r> \\ - \\ <cyan>sudo launchctl limit maxfiles 2147483646<r> + \\<d>Current limit: {d}<r> + \\ + \\To fix this, try running: \\ + \\ <cyan>ulimit -n 2147483646<r> + \\ + , + .{ + limit.cur, + }, + ); + + if (Environment.isLinux) { + if (bun.getenvZ("USER")) |user| { + if (user.len > 0) { + Output.prettyError( + \\ + \\If that still doesn't work, you may need to add these lines to /etc/security/limits.conf: + \\ + \\ <cyan>{s} soft nofile 2147483646<r> + \\ <cyan>{s} hard nofile 2147483646<r> + \\ + , + .{ + user, + user, + }, + ); + } + } + } else if (Environment.isMac) { + Output.prettyError( + \\ + \\If that still doesn't work, you may need to run: + \\ + \\ <cyan>sudo launchctl limit maxfiles 2147483646<r> + \\ + , + .{}, + ); + } + } else { + Output.prettyError( + \\<r><red>error<r>: An unknown error ocurred <d>(<red>Unexpected<r><d>)<r> , .{}, ); diff --git a/src/resolver/package_json.zig b/src/resolver/package_json.zig index 6022e5a6c..165da7b53 100644 --- a/src/resolver/package_json.zig +++ b/src/resolver/package_json.zig @@ -609,7 +609,7 @@ pub const PackageJSON = struct { defer { if (entry.fd != 0) { - _ = bun.JSC.Node.Syscall.close(entry.fd); + _ = bun.sys.close(entry.fd); } } diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig index 08eca8333..d1af1a599 100644 --- a/src/resolver/resolver.zig +++ b/src/resolver/resolver.zig @@ -26,7 +26,7 @@ const BrowserMap = @import("./package_json.zig").BrowserMap; const CacheSet = cache.Set; const DataURL = @import("./data_url.zig").DataURL; pub const DirInfo = @import("./dir_info.zig"); -const HTTPWatcher = if (Environment.isTest or Environment.isWasm) void else @import("../http.zig").Watcher; +const HTTPWatcher = if (Environment.isTest or Environment.isWasm) void else @import("../bun_dev_http_server.zig").Watcher; const ResolvePath = @import("./resolve_path.zig"); const NodeFallbackModules = @import("../node_fallbacks.zig"); const Mutex = @import("../lock.zig").Lock; @@ -1001,12 +1001,12 @@ pub const Resolver = struct { bun.openFileForPath(span); if (!store_fd) { - std.debug.assert(file.handle > 2); + std.debug.assert(bun.FDTag.get(file.handle) == .none); out = try bun.getFdPath(file.handle, &buf); file.close(); query.entry.cache.fd = 0; } else { - query.entry.cache.fd = file.handle; + query.entry.cache.fd = bun.toFD(file.handle); Fs.FileSystem.setMaxFd(file.handle); } } @@ -1014,7 +1014,7 @@ pub const Resolver = struct { defer { if (r.fs.fs.needToCloseFiles()) { if (query.entry.cache.fd != 0) { - var file = std.fs.File{ .handle = query.entry.cache.fd }; + var file = std.fs.File{ .handle = bun.fdcast(query.entry.cache.fd) }; file.close(); query.entry.cache.fd = 0; } @@ -2040,10 +2040,10 @@ pub const Resolver = struct { if (r.store_fd) { Fs.FileSystem.setMaxFd(open_dir.dir.fd); - dir_entries_ptr.fd = open_dir.dir.fd; + dir_entries_ptr.fd = bun.toFD(open_dir.dir.fd); } - bun.fs.debug("readdir({d}, {s}) = {d}", .{ open_dir.dir.fd, dir_path, dir_entries_ptr.data.count() }); + bun.fs.debug("readdir({d}, {s}) = {d}", .{ bun.toFD(open_dir.dir.fd), dir_path, dir_entries_ptr.data.count() }); dir_entries_option = rfs.entries.put(&cached_dir_entry_result, .{ .entries = dir_entries_ptr, @@ -2064,7 +2064,7 @@ pub const Resolver = struct { // to check for a parent package.json null, allocators.NotFound, - open_dir.dir.fd, + bun.toFD(open_dir.dir.fd), package_id, ); return dir_info_ptr; @@ -2337,7 +2337,7 @@ pub const Resolver = struct { false, null, ); - _ = bun.JSC.Node.Syscall.close(entry.fd); + _ = bun.sys.close(entry.fd); // The file name needs to be persistent because it can have errors // and if those errors need to print the filename @@ -2527,7 +2527,7 @@ pub const Resolver = struct { if (open_dir_count > 0 and (!r.store_fd or r.fs.fs.needToCloseFiles())) { var open_dirs: []std.fs.IterableDir = bufs(.open_dirs)[0..open_dir_count]; for (open_dirs) |*open_dir| { - _ = bun.JSC.Node.Syscall.close(open_dir.dir.fd); + _ = bun.sys.close(bun.toFD(open_dir.dir.fd)); } } } @@ -2572,7 +2572,7 @@ pub const Resolver = struct { // } } - const open_dir = if (queue_top.fd != 0) std.fs.IterableDir{ .dir = .{ .fd = queue_top.fd } } else (_open_dir catch |err| { + const open_dir = if (queue_top.fd != 0) std.fs.IterableDir{ .dir = .{ .fd = bun.fdcast(queue_top.fd) } } else (_open_dir catch |err| { switch (err) { error.EACCESS => {}, @@ -2683,13 +2683,13 @@ pub const Resolver = struct { if (in_place) |existing| { existing.data.clearAndFree(allocator); } - new_entry.fd = if (r.store_fd) open_dir.dir.fd else 0; + new_entry.fd = if (r.store_fd) bun.toFD(open_dir.dir.fd) else 0; var dir_entries_ptr = in_place orelse allocator.create(Fs.FileSystem.DirEntry) catch unreachable; dir_entries_ptr.* = new_entry; dir_entries_option = try rfs.entries.put(&cached_dir_entry_result, .{ .entries = dir_entries_ptr, }); - bun.fs.debug("readdir({d}, {s}) = {d}", .{ open_dir.dir.fd, dir_path, dir_entries_ptr.data.count() }); + bun.fs.debug("readdir({d}, {s}) = {d}", .{ bun.toFD(open_dir.dir.fd), dir_path, dir_entries_ptr.data.count() }); } // We must initialize it as empty so that the result index is correct. @@ -2704,7 +2704,7 @@ pub const Resolver = struct { cached_dir_entry_result.index, r.dir_cache.atIndex(top_parent.index), top_parent.index, - open_dir.dir.fd, + bun.toFD(open_dir.dir.fd), null, ); @@ -3713,7 +3713,7 @@ pub const Resolver = struct { bin_folders = BinFolderArray.init(0) catch unreachable; } - const this_dir = std.fs.Dir{ .fd = fd }; + const this_dir = std.fs.Dir{ .fd = bun.fdcast(fd) }; var file = this_dir.openDirZ("node_modules/.bin", .{}, true) catch break :append_bin_dir; defer file.close(); var bin_path = bun.getFdPath(file.fd, bufs(.node_bin_path)) catch break :append_bin_dir; @@ -3738,7 +3738,7 @@ pub const Resolver = struct { bin_folders = BinFolderArray.init(0) catch unreachable; } - const this_dir = std.fs.Dir{ .fd = fd }; + const this_dir = std.fs.Dir{ .fd = bun.fdcast(fd) }; var file = this_dir.openDirZ(".bin", .{}, false) catch break :append_bin_dir; defer file.close(); var bin_path = bun.getFdPath(file.fd, bufs(.node_bin_path)) catch break :append_bin_dir; diff --git a/src/router.zig b/src/router.zig index bd79b6fc6..51047d9b5 100644 --- a/src/router.zig +++ b/src/router.zig @@ -737,7 +737,7 @@ pub const Route = struct { var needs_close = false; defer if (needs_close) file.close(); if (entry.cache.fd != 0) { - file = std.fs.File{ .handle = entry.cache.fd }; + file = std.fs.File{ .handle = bun.fdcast(entry.cache.fd) }; } else { var parts = [_]string{ entry.dir, entry.base() }; abs_path_str = FileSystem.instance.absBuf(&parts, &route_file_buf); @@ -750,7 +750,7 @@ pub const Route = struct { FileSystem.setMaxFd(file.handle); needs_close = FileSystem.instance.fs.needToCloseFiles(); - if (!needs_close) entry.cache.fd = file.handle; + if (!needs_close) entry.cache.fd = bun.toFD(file.handle); } var _abs = bun.getFdPath(file.handle, &route_file_buf) catch |err| { diff --git a/src/runtime.zig b/src/runtime.zig index 2c22f392e..cf9f1d208 100644 --- a/src/runtime.zig +++ b/src/runtime.zig @@ -45,7 +45,7 @@ pub const ErrorCSS = struct { content.error_css, ); defer file.close(); - return file.readToEndAlloc(default_allocator, (file.stat() catch unreachable).size) catch unreachable; + return file.readToEndAlloc(default_allocator, file.getEndPos() catch 0) catch unreachable; } else { return content.error_css; } @@ -68,7 +68,7 @@ pub const ErrorJS = struct { content.error_js, ); defer file.close(); - return file.readToEndAlloc(default_allocator, (file.stat() catch unreachable).size) catch unreachable; + return file.readToEndAlloc(default_allocator, file.getEndPos() catch 0) catch unreachable; } else { return content.error_js; } @@ -133,7 +133,7 @@ pub const Fallback = struct { ProdSourceContent, ); defer file.close(); - return file.readToEndAlloc(default_allocator, (file.stat() catch unreachable).size) catch unreachable; + return file.readToEndAlloc(default_allocator, file.getEndPos() catch 0) catch unreachable; } else { return ProdSourceContent; } @@ -220,7 +220,7 @@ pub const Runtime = struct { ProdSourceContent, ); defer file.close(); - return file.readToEndAlloc(default_allocator, (file.stat() catch unreachable).size) catch unreachable; + return file.readToEndAlloc(default_allocator, file.getEndPos() catch 0) catch unreachable; } else { return ProdSourceContent; } @@ -257,7 +257,7 @@ pub const Runtime = struct { ProdSourceContentWithRefresh, ); defer file.close(); - return file.readToEndAlloc(default_allocator, (file.stat() catch unreachable).size) catch unreachable; + return file.readToEndAlloc(default_allocator, file.getEndPos() catch 0) catch unreachable; } else { return ProdSourceContentWithRefresh; } diff --git a/src/sha.zig b/src/sha.zig index 542dc494e..6c345c0ff 100644 --- a/src/sha.zig +++ b/src/sha.zig @@ -200,7 +200,7 @@ const labels = [_][]const u8{ "Blake3", }; pub fn main() anyerror!void { - var file = try std.fs.cwd().openFileZ(std.os.argv[std.os.argv.len - 1], .{}); + var file = try std.fs.cwd().openFileZ(bun.argv()[bun.argv().len - 1], .{}); var bytes = try file.readToEndAlloc(std.heap.c_allocator, std.math.maxInt(usize)); var engine = BoringSSL.ENGINE_new().?; diff --git a/src/standalone_bun.zig b/src/standalone_bun.zig index 77cc92b15..ba5ec8f66 100644 --- a/src/standalone_bun.zig +++ b/src/standalone_bun.zig @@ -7,7 +7,7 @@ const Schema = bun.Schema.Api; const Environment = bun.Environment; -const Syscall = bun.JSC.Node.Syscall; +const Syscall = bun.sys; pub const StandaloneModuleGraph = struct { bytes: []const u8 = "", @@ -228,7 +228,7 @@ pub const StandaloneModuleGraph = struct { else std.mem.page_size; - pub fn inject(bytes: []const u8) i32 { + pub fn inject(bytes: []const u8) bun.FileDescriptor { var buf: [bun.MAX_PATH_BYTES]u8 = undefined; var zname: [:0]const u8 = bun.span(bun.fs.FileSystem.instance.tmpname("bun-build", &buf, @as(u64, @bitCast(std.time.milliTimestamp()))) catch |err| { Output.prettyErrorln("<r><red>error<r><d>:<r> failed to get temporary file name: {s}", .{@errorName(err)}); @@ -330,7 +330,7 @@ pub const StandaloneModuleGraph = struct { }; defer _ = Syscall.close(self_fd); - bun.copyFile(self_fd, fd) catch |err| { + bun.copyFile(bun.fdcast(self_fd), bun.fdcast(fd)) catch |err| { Output.prettyErrorln("<r><red>error<r><d>:<r> failed to copy bun executable into temporary file: {s}", .{@errorName(err)}); cleanup(zname, fd); Global.exit(1); @@ -361,24 +361,27 @@ pub const StandaloneModuleGraph = struct { // gap (a "hole") return null bytes ('\0') until data is actually // written into the gap. // - std.os.lseek_SET(cloned_executable_fd, seek_position) catch |err| { - Output.prettyErrorln( - "<r><red>error<r><d>:<r> {s} seeking to end of temporary file (pos: {d})", - .{ - @errorName(err), - seek_position, - }, - ); - cleanup(zname, cloned_executable_fd); - Global.exit(1); - }; + switch (Syscall.setFileOffset(cloned_executable_fd, seek_position)) { + .err => |err| { + Output.prettyErrorln( + "{}\nwhile seeking to end of temporary file (pos: {d})", + .{ + err, + seek_position, + }, + ); + cleanup(zname, cloned_executable_fd); + Global.exit(1); + }, + else => {}, + } var remain = bytes; while (remain.len > 0) { switch (Syscall.write(cloned_executable_fd, bytes)) { .result => |written| remain = remain[written..], .err => |err| { - Output.prettyErrorln("<r><red>error<r><d>:<r> failed to write to temporary file\n{s}", .{err}); + Output.prettyErrorln("<r><red>error<r><d>:<r> failed to write to temporary file\n{}", .{err}); cleanup(zname, cloned_executable_fd); Global.exit(1); @@ -388,8 +391,9 @@ pub const StandaloneModuleGraph = struct { // the final 8 bytes in the file are the length of the module graph with padding, excluding the trailer and offsets _ = Syscall.write(cloned_executable_fd, std.mem.asBytes(&total_byte_count)); - - _ = bun.C.fchmod(cloned_executable_fd, 0o777); + if (comptime !Environment.isWindows) { + _ = bun.C.fchmod(cloned_executable_fd, 0o777); + } return cloned_executable_fd; } @@ -434,6 +438,11 @@ pub const StandaloneModuleGraph = struct { } } + if (comptime Environment.isWindows) { + Output.prettyError("TODO: windows support. sorry!!\n", .{}); + Global.exit(1); + } + bun.C.moveFileZWithHandle( fd, std.fs.cwd().fd, @@ -459,7 +468,7 @@ pub const StandaloneModuleGraph = struct { defer _ = Syscall.close(self_exe); var trailer_bytes: [4096]u8 = undefined; - std.os.lseek_END(self_exe, -4096) catch return null; + std.os.lseek_END(bun.fdcast(self_exe), -4096) catch return null; var read_amount: usize = 0; while (read_amount < trailer_bytes.len) { switch (Syscall.read(self_exe, trailer_bytes[read_amount..])) { @@ -511,7 +520,7 @@ pub const StandaloneModuleGraph = struct { // if you have not a ton of code, we only do a single read() call if (Environment.allow_assert or offsets.byte_count > 1024 * 3) { const offset_from_end = trailer_bytes.len - (@intFromPtr(end) - @intFromPtr(@as([]u8, &trailer_bytes).ptr)); - std.os.lseek_END(self_exe, -@as(i64, @intCast(offset_from_end + offsets.byte_count))) catch return null; + std.os.lseek_END(bun.fdcast(self_exe), -@as(i64, @intCast(offset_from_end + offsets.byte_count))) catch return null; if (comptime Environment.allow_assert) { // actually we just want to verify this logic is correct in development @@ -553,16 +562,16 @@ pub const StandaloneModuleGraph = struct { // heuristic: `bun build --compile` won't be supported if the name is "bun" or "bunx". // this is a cheap way to avoid the extra overhead of opening the executable // and also just makes sense. - if (std.os.argv.len > 0) { - const argv0_len = bun.len(std.os.argv[0]); + if (bun.argv().len > 0) { + const argv0_len = bun.len(bun.argv()[0]); if (argv0_len == 3) { - if (bun.strings.eqlComptimeIgnoreLen(std.os.argv[0][0..argv0_len], "bun")) { + if (bun.strings.eqlComptimeIgnoreLen(bun.argv()[0][0..argv0_len], "bun")) { return null; } } if (argv0_len == 4) { - if (bun.strings.eqlComptimeIgnoreLen(std.os.argv[0][0..argv0_len], "bunx")) { + if (bun.strings.eqlComptimeIgnoreLen(bun.argv()[0][0..argv0_len], "bunx")) { return null; } } @@ -572,14 +581,14 @@ pub const StandaloneModuleGraph = struct { if (std.fs.openFileAbsoluteZ("/proc/self/exe", flags)) |easymode| { return easymode.handle; } else |_| { - if (std.os.argv.len > 0) { + if (bun.argv().len > 0) { // The user doesn't have /proc/ mounted, so now we just guess and hope for the best. var whichbuf: [bun.MAX_PATH_BYTES]u8 = undefined; if (bun.which( &whichbuf, bun.getenvZ("PATH") orelse return error.FileNotFound, "", - bun.span(std.os.argv[0]), + bun.span(bun.argv()[0]), )) |path| { return (try std.fs.cwd().openFileZ(path, flags)).handle; } @@ -590,7 +599,7 @@ pub const StandaloneModuleGraph = struct { } if (comptime Environment.isWindows) { - return (try std.fs.openSelfExe(flags)).handle; + return bun.toFD((try std.fs.openSelfExe(flags)).handle); } // Use of MAX_PATH_BYTES here is valid as the resulting path is immediately // opened with no modification. diff --git a/src/string_builder.zig b/src/string_builder.zig index 8acef5f07..2111ffa1a 100644 --- a/src/string_builder.zig +++ b/src/string_builder.zig @@ -38,6 +38,18 @@ pub fn deinit(this: *StringBuilder, allocator: Allocator) void { allocator.free(this.ptr.?[0..this.cap]); } +pub fn append16(this: *StringBuilder, slice: []const u16) ?[:0]u8 { + var buf = this.writable(); + const result = bun.simdutf.convert.utf16.to.utf8.with_errors.le(slice, buf); + if (result.status == .success) { + this.len += result.count + 1; + buf[result.count] = 0; + return buf[0..result.count :0]; + } + + return null; +} + pub fn append(this: *StringBuilder, slice: string) string { if (comptime Environment.allow_assert) { assert(this.len <= this.cap); // didn't count everything diff --git a/src/string_immutable.zig b/src/string_immutable.zig index 8266e7e27..c62266c62 100644 --- a/src/string_immutable.zig +++ b/src/string_immutable.zig @@ -23,6 +23,20 @@ pub inline fn contains(self: string, str: string) bool { return indexOf(self, str) != null; } +pub fn w(comptime str: []const u8) [:0]const u16 { + comptime var output: [str.len + 1]u16 = undefined; + + for (str, 0..) |c, i| { + output[i] = c; + } + output[str.len] = 0; + + const Static = struct { + pub const literal: [:0]const u16 = output[0 .. output.len - 1 :0]; + }; + return Static.literal; +} + pub fn toUTF16Literal(comptime str: []const u8) []const u16 { return comptime brk: { comptime var output: [str.len]u16 = undefined; @@ -1462,6 +1476,27 @@ pub fn utf16Codepoint(comptime Type: type, input: Type) UTF16Replacement { } } +pub fn fromWPath(buf: []u8, utf16: []const u16) [:0]const u8 { + std.debug.assert(buf.len > 0); + const encode_into_result = copyUTF16IntoUTF8(buf[0 .. buf.len - 1], []const u16, utf16, false); + std.debug.assert(encode_into_result.written < buf.len); + buf[encode_into_result.written] = 0; + return buf[0..encode_into_result.written :0]; +} + +pub fn toWPath(wbuf: []u16, utf8: []const u8) [:0]const u16 { + std.debug.assert(wbuf.len > 0); + var result = bun.simdutf.convert.utf8.to.utf16.with_errors.le( + utf8, + wbuf[0..wbuf.len -| 1], + ); + + // TODO: error handling + // if (result.status == .surrogate) { + // } + return wbuf[0..result.count :0]; +} + pub fn convertUTF16ToUTF8(list_: std.ArrayList(u8), comptime Type: type, utf16: Type) !std.ArrayList(u8) { var list = list_; var result = bun.simdutf.convert.utf16.to.utf8.with_errors.le( @@ -4525,6 +4560,10 @@ pub fn isIPAddress(input: []const u8) bool { if (containsChar(input, ':')) return true; + if (comptime Environment.isWindows) { + return bun.todo(@src(), false); + } + if (std.net.Address.resolveIp(input, 0)) |_| { return true; } else |_| { @@ -4533,6 +4572,10 @@ pub fn isIPAddress(input: []const u8) bool { } pub fn isIPV6Address(input: []const u8) bool { + if (comptime Environment.isWindows) { + return bun.todo(@src(), false); + } + if (std.net.Address.parseIp6(input, 0)) |_| { return true; } else |_| { diff --git a/src/string_mutable.zig b/src/string_mutable.zig index e0734574f..c6ac943f6 100644 --- a/src/string_mutable.zig +++ b/src/string_mutable.zig @@ -14,7 +14,7 @@ pub const MutableString = struct { allocator: std.mem.Allocator, list: std.ArrayListUnmanaged(u8), - pub fn init2048(allocator: std.mem.Allocator) !MutableString { + pub fn init2048(allocator: std.mem.Allocator) std.mem.Allocator.Error!MutableString { return MutableString.init(allocator, 2048); } @@ -53,7 +53,7 @@ pub const MutableString = struct { return BufferedWriter{ .context = self }; } - pub fn init(allocator: std.mem.Allocator, capacity: usize) !MutableString { + pub fn init(allocator: std.mem.Allocator, capacity: usize) std.mem.Allocator.Error!MutableString { return MutableString{ .allocator = allocator, .list = if (capacity > 0) try std.ArrayListUnmanaged(u8).initCapacity(allocator, capacity) else diff --git a/src/sync.zig b/src/sync.zig index ec9105cf3..5e57f7c6c 100644 --- a/src/sync.zig +++ b/src/sync.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const system = std.system; +const system = if (bun.Environment.isWindows) std.os.windows else std.os.system; const bun = @import("root").bun; // https://gist.github.com/kprotty/0d2dc3da4840341d6ff361b27bdac7dc diff --git a/src/watcher.zig b/src/watcher.zig index a31267c5f..5521414e3 100644 --- a/src/watcher.zig +++ b/src/watcher.zig @@ -207,7 +207,7 @@ pub const INotify = struct { pub fn stop() void { if (inotify_fd != 0) { - std.os.close(inotify_fd); + _ = bun.sys.close(inotify_fd); inotify_fd = 0; } } @@ -239,7 +239,7 @@ const DarwinWatcher = struct { pub fn stop() void { if (fd != 0) { - std.os.close(fd); + _ = bun.sys.close(fd); } fd = 0; @@ -384,6 +384,11 @@ pub fn NewWatcher(comptime ContextType: type) type { var watcher = try allocator.create(Watcher); errdefer allocator.destroy(watcher); + if (comptime bun.Environment.isWindows) { + bun.todo(@src(), {}); + return error.NotImplemented; + } + if (!PlatformWatcher.isRunning()) { try PlatformWatcher.init(); } @@ -420,7 +425,7 @@ pub fn NewWatcher(comptime ContextType: type) type { if (close_descriptors and this.running) { const fds = this.watchlist.items(.fd); for (fds) |fd| { - std.os.close(fd); + _ = bun.sys.close(fd); } } this.watchlist.deinit(this.allocator); @@ -449,7 +454,7 @@ pub fn NewWatcher(comptime ContextType: type) type { if (this.close_descriptors) { const fds = this.watchlist.items(.fd); for (fds) |fd| { - std.os.close(fd); + _ = bun.sys.close(fd); } } this.watchlist.deinit(this.allocator); @@ -464,7 +469,7 @@ pub fn NewWatcher(comptime ContextType: type) type { if (this.indexOf(hash)) |index| { const fds = this.watchlist.items(.fd); const fd = fds[index]; - std.os.close(fd); + _ = bun.sys.close(fd); this.watchlist.swapRemove(index); } } @@ -510,7 +515,7 @@ pub fn NewWatcher(comptime ContextType: type) type { if (item == last_item) continue; // close the file descriptors here. this should automatically remove it from being watched too. - std.os.close(fds[item]); + _ = bun.sys.close(fds[item]); // if (Environment.isLinux) { // INotify.unwatch(event_list_ids[item]); @@ -794,7 +799,7 @@ pub fn NewWatcher(comptime ContextType: type) type { if (fd_ > 0) break :brk fd_; const dir = try std.fs.cwd().openIterableDir(file_path, .{}); - break :brk @as(StoredFileDescriptorType, @truncate(dir.dir.fd)); + break :brk bun.toFD(dir.dir.fd); }; const parent_hash = Watcher.getHash(Fs.PathName.init(file_path).dirWithTrailingSlash()); diff --git a/src/which.zig b/src/which.zig index 69356e611..ec4157161 100644 --- a/src/which.zig +++ b/src/which.zig @@ -10,10 +10,10 @@ fn isValid(buf: *[bun.MAX_PATH_BYTES]u8, segment: []const u8, bin: []const u8) ? return @as(u16, @intCast(filepath.len)); } -extern "C" fn is_executable_file(path: [*:0]const u8) bool; +pub extern "C" fn is_executable_file(path: [*:0]const u8) bool; fn checkPath(filepath: [:0]const u8) bool { bun.JSC.markBinding(@src()); - return is_executable_file(filepath); + return bun.sys.isExecutableFilePath(filepath); } // Like /usr/bin/which but without needing to exec a child process diff --git a/src/windows.zig b/src/windows.zig new file mode 100644 index 000000000..359b81897 --- /dev/null +++ b/src/windows.zig @@ -0,0 +1,2917 @@ +const bun = @import("root").bun; +const windows = std.os.windows; +const win32 = windows; +pub const PATH_MAX_WIDE = windows.PATH_MAX_WIDE; +pub const MAX_PATH = windows.MAX_PATH; +pub const DWORD = windows.DWORD; +pub const BOOL = windows.BOOL; +pub const LPVOID = windows.LPVOID; +pub const LPCVOID = windows.LPCVOID; +pub const LPWSTR = windows.LPWSTR; +pub const LPCWSTR = windows.LPCWSTR; +pub const LPSTR = windows.LPSTR; +pub const LPCSTR = windows.LPCSTR; +pub const FALSE = windows.FALSE; +pub const TRUE = windows.TRUE; +pub const INVALID_HANDLE_VALUE = windows.INVALID_HANDLE_VALUE; +pub const FILE_BEGIN = windows.FILE_BEGIN; +pub const FILE_CURRENT = windows.FILE_CURRENT; +pub const ULONG = windows.ULONG; +pub const LARGE_INTEGER = windows.LARGE_INTEGER; +pub const UNICODE_STRING = windows.UNICODE_STRING; +pub const NTSTATUS = windows.NTSTATUS; +pub const NT_SUCCESS = windows.NT_SUCCESS; +pub const STATUS_SUCCESS = windows.STATUS_SUCCESS; +pub const DUPLICATE_SAME_ACCESS = windows.DUPLICATE_SAME_ACCESS; +pub const OBJECT_ATTRIBUTES = windows.OBJECT_ATTRIBUTES; +pub const kernel32 = windows.kernel32; +pub const IO_STATUS_BLOCK = windows.IO_STATUS_BLOCK; +pub const FILE_SHARE_READ = windows.FILE_SHARE_READ; +pub const FILE_SHARE_WRITE = windows.FILE_SHARE_WRITE; +pub const FILE_SHARE_DELETE = windows.FILE_SHARE_DELETE; +pub const FILE_ATTRIBUTE_NORMAL = windows.FILE_ATTRIBUTE_NORMAL; +pub const FILE_ATTRIBUTE_READONLY = windows.FILE_ATTRIBUTE_READONLY; +pub const FILE_ATTRIBUTE_HIDDEN = windows.FILE_ATTRIBUTE_HIDDEN; +pub const FILE_ATTRIBUTE_SYSTEM = windows.FILE_ATTRIBUTE_SYSTEM; +pub const FILE_ATTRIBUTE_DIRECTORY = windows.FILE_ATTRIBUTE_DIRECTORY; +pub const FILE_ATTRIBUTE_ARCHIVE = windows.FILE_ATTRIBUTE_ARCHIVE; +pub const FILE_ATTRIBUTE_DEVICE = windows.FILE_ATTRIBUTE_DEVICE; +pub const FILE_ATTRIBUTE_TEMPORARY = windows.FILE_ATTRIBUTE_TEMPORARY; +pub const FILE_ATTRIBUTE_SPARSE_FILE = windows.FILE_ATTRIBUTE_SPARSE_FILE; +pub const FILE_ATTRIBUTE_REPARSE_POINT = windows.FILE_ATTRIBUTE_REPARSE_POINT; +pub const FILE_ATTRIBUTE_COMPRESSED = windows.FILE_ATTRIBUTE_COMPRESSED; +pub const FILE_ATTRIBUTE_OFFLINE = windows.FILE_ATTRIBUTE_OFFLINE; +pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = windows.FILE_ATTRIBUTE_NOT_CONTENT_INDEXED; +pub const FILE_DIRECTORY_FILE = windows.FILE_DIRECTORY_FILE; +pub const FILE_WRITE_THROUGH = windows.FILE_WRITE_THROUGH; +pub const FILE_SEQUENTIAL_ONLY = windows.FILE_SEQUENTIAL_ONLY; +pub const FILE_SYNCHRONOUS_IO_NONALERT = windows.FILE_SYNCHRONOUS_IO_NONALERT; +pub const FILE_OPEN_REPARSE_POINT = windows.FILE_OPEN_REPARSE_POINT; +pub usingnamespace kernel32; +pub const ntdll = windows.ntdll; +pub usingnamespace ntdll; +pub const user32 = windows.user32; +pub const advapi32 = windows.advapi32; + +const std = @import("std"); +pub const HANDLE = win32.HANDLE; + +/// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfilevaliddata +pub extern "kernel32" fn SetFileValidData( + hFile: win32.HANDLE, + validDataLength: c_longlong, +) callconv(windows.WINAPI) win32.BOOL; + +pub extern fn CommandLineToArgvW( + lpCmdLine: win32.LPCWSTR, + pNumArgs: *c_int, +) [*]win32.LPWSTR; + +pub const LPDWORD = *win32.DWORD; + +pub extern "kernel32" fn GetBinaryTypeW( + lpApplicationName: win32.LPCWSTR, + lpBinaryType: LPDWORD, +) callconv(windows.WINAPI) win32.BOOL; + +/// A 32-bit Windows-based application +pub const SCS_32BIT_BINARY = 0; +/// A 64-bit Windows-based application. +pub const SCS_64BIT_BINARY = 6; +/// An MS-DOS – based application +pub const SCS_DOS_BINARY = 1; +/// A 16-bit OS/2-based application +pub const SCS_OS216_BINARY = 5; +/// A PIF file that executes an MS-DOS – based application +pub const SCS_PIF_BINARY = 3; +/// A POSIX – based application +pub const SCS_POSIX_BINARY = 4; + +/// Each process has a single current directory made up of two parts: +/// +/// - A disk designator that is either a drive letter followed by a colon, or a server name and share name (\\servername\sharename) +/// - A directory on the disk designator +/// +/// The current directory is shared by all threads of the process: If one thread changes the current directory, it affects all threads in the process. Multithreaded applications and shared library code should avoid calling the SetCurrentDirectory function due to the risk of affecting relative path calculations being performed by other threads. Conversely, multithreaded applications and shared library code should avoid using relative paths so that they are unaffected by changes to the current directory performed by other threads. +/// +/// Note that the current directory for a process is locked while the process is executing. This will prevent the directory from being deleted, moved, or renamed. +pub extern "kernel32" fn SetCurrentDirectory( + lpPathName: win32.LPCWSTR, +) callconv(windows.WINAPI) win32.BOOL; + +pub extern "ntdll" fn RtlNtStatusToDosError(win32.NTSTATUS) callconv(windows.WINAPI) Win32Error; + +const SystemErrno = bun.C.SystemErrno; + +// This was originally copied from Zig's standard library +/// Codes are from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/18d8fbe8-a967-4f1c-ae50-99ca8e491d2d +pub const Win32Error = enum(u16) { + /// The operation completed successfully. + SUCCESS = 0, + /// Incorrect function. + INVALID_FUNCTION = 1, + /// The system cannot find the file specified. + FILE_NOT_FOUND = 2, + /// The system cannot find the path specified. + PATH_NOT_FOUND = 3, + /// The system cannot open the file. + TOO_MANY_OPEN_FILES = 4, + /// Access is denied. + ACCESS_DENIED = 5, + /// The handle is invalid. + INVALID_HANDLE = 6, + /// The storage control blocks were destroyed. + ARENA_TRASHED = 7, + /// Not enough storage is available to process this command. + NOT_ENOUGH_MEMORY = 8, + /// The storage control block address is invalid. + INVALID_BLOCK = 9, + /// The environment is incorrect. + BAD_ENVIRONMENT = 10, + /// An attempt was made to load a program with an incorrect format. + BAD_FORMAT = 11, + /// The access code is invalid. + INVALID_ACCESS = 12, + /// The data is invalid. + INVALID_DATA = 13, + /// Not enough storage is available to complete this operation. + OUTOFMEMORY = 14, + /// The system cannot find the drive specified. + INVALID_DRIVE = 15, + /// The directory cannot be removed. + CURRENT_DIRECTORY = 16, + /// The system cannot move the file to a different disk drive. + NOT_SAME_DEVICE = 17, + /// There are no more files. + NO_MORE_FILES = 18, + /// The media is write protected. + WRITE_PROTECT = 19, + /// The system cannot find the device specified. + BAD_UNIT = 20, + /// The device is not ready. + NOT_READY = 21, + /// The device does not recognize the command. + BAD_COMMAND = 22, + /// Data error (cyclic redundancy check). + CRC = 23, + /// The program issued a command but the command length is incorrect. + BAD_LENGTH = 24, + /// The drive cannot locate a specific area or track on the disk. + SEEK = 25, + /// The specified disk or diskette cannot be accessed. + NOT_DOS_DISK = 26, + /// The drive cannot find the sector requested. + SECTOR_NOT_FOUND = 27, + /// The printer is out of paper. + OUT_OF_PAPER = 28, + /// The system cannot write to the specified device. + WRITE_FAULT = 29, + /// The system cannot read from the specified device. + READ_FAULT = 30, + /// A device attached to the system is not functioning. + GEN_FAILURE = 31, + /// The process cannot access the file because it is being used by another process. + SHARING_VIOLATION = 32, + /// The process cannot access the file because another process has locked a portion of the file. + LOCK_VIOLATION = 33, + /// The wrong diskette is in the drive. + /// Insert %2 (Volume Serial Number: %3) into drive %1. + WRONG_DISK = 34, + /// Too many files opened for sharing. + SHARING_BUFFER_EXCEEDED = 36, + /// Reached the end of the file. + HANDLE_EOF = 38, + /// The disk is full. + HANDLE_DISK_FULL = 39, + /// The request is not supported. + NOT_SUPPORTED = 50, + /// Windows cannot find the network path. + /// Verify that the network path is correct and the destination computer is not busy or turned off. + /// If Windows still cannot find the network path, contact your network administrator. + REM_NOT_LIST = 51, + /// You were not connected because a duplicate name exists on the network. + /// If joining a domain, go to System in Control Panel to change the computer name and try again. + /// If joining a workgroup, choose another workgroup name. + DUP_NAME = 52, + /// The network path was not found. + BAD_NETPATH = 53, + /// The network is busy. + NETWORK_BUSY = 54, + /// The specified network resource or device is no longer available. + DEV_NOT_EXIST = 55, + /// The network BIOS command limit has been reached. + TOO_MANY_CMDS = 56, + /// A network adapter hardware error occurred. + ADAP_HDW_ERR = 57, + /// The specified server cannot perform the requested operation. + BAD_NET_RESP = 58, + /// An unexpected network error occurred. + UNEXP_NET_ERR = 59, + /// The remote adapter is not compatible. + BAD_REM_ADAP = 60, + /// The printer queue is full. + PRINTQ_FULL = 61, + /// Space to store the file waiting to be printed is not available on the server. + NO_SPOOL_SPACE = 62, + /// Your file waiting to be printed was deleted. + PRINT_CANCELLED = 63, + /// The specified network name is no longer available. + NETNAME_DELETED = 64, + /// Network access is denied. + NETWORK_ACCESS_DENIED = 65, + /// The network resource type is not correct. + BAD_DEV_TYPE = 66, + /// The network name cannot be found. + BAD_NET_NAME = 67, + /// The name limit for the local computer network adapter card was exceeded. + TOO_MANY_NAMES = 68, + /// The network BIOS session limit was exceeded. + TOO_MANY_SESS = 69, + /// The remote server has been paused or is in the process of being started. + SHARING_PAUSED = 70, + /// No more connections can be made to this remote computer at this time because there are already as many connections as the computer can accept. + REQ_NOT_ACCEP = 71, + /// The specified printer or disk device has been paused. + REDIR_PAUSED = 72, + /// The file exists. + FILE_EXISTS = 80, + /// The directory or file cannot be created. + CANNOT_MAKE = 82, + /// Fail on INT 24. + FAIL_I24 = 83, + /// Storage to process this request is not available. + OUT_OF_STRUCTURES = 84, + /// The local device name is already in use. + ALREADY_ASSIGNED = 85, + /// The specified network password is not correct. + INVALID_PASSWORD = 86, + /// The parameter is incorrect. + INVALID_PARAMETER = 87, + /// A write fault occurred on the network. + NET_WRITE_FAULT = 88, + /// The system cannot start another process at this time. + NO_PROC_SLOTS = 89, + /// Cannot create another system semaphore. + TOO_MANY_SEMAPHORES = 100, + /// The exclusive semaphore is owned by another process. + EXCL_SEM_ALREADY_OWNED = 101, + /// The semaphore is set and cannot be closed. + SEM_IS_SET = 102, + /// The semaphore cannot be set again. + TOO_MANY_SEM_REQUESTS = 103, + /// Cannot request exclusive semaphores at interrupt time. + INVALID_AT_INTERRUPT_TIME = 104, + /// The previous ownership of this semaphore has ended. + SEM_OWNER_DIED = 105, + /// Insert the diskette for drive %1. + SEM_USER_LIMIT = 106, + /// The program stopped because an alternate diskette was not inserted. + DISK_CHANGE = 107, + /// The disk is in use or locked by another process. + DRIVE_LOCKED = 108, + /// The pipe has been ended. + BROKEN_PIPE = 109, + /// The system cannot open the device or file specified. + OPEN_FAILED = 110, + /// The file name is too long. + BUFFER_OVERFLOW = 111, + /// There is not enough space on the disk. + DISK_FULL = 112, + /// No more internal file identifiers available. + NO_MORE_SEARCH_HANDLES = 113, + /// The target internal file identifier is incorrect. + INVALID_TARGET_HANDLE = 114, + /// The IOCTL call made by the application program is not correct. + INVALID_CATEGORY = 117, + /// The verify-on-write switch parameter value is not correct. + INVALID_VERIFY_SWITCH = 118, + /// The system does not support the command requested. + BAD_DRIVER_LEVEL = 119, + /// This function is not supported on this system. + CALL_NOT_IMPLEMENTED = 120, + /// The semaphore timeout period has expired. + SEM_TIMEOUT = 121, + /// The data area passed to a system call is too small. + INSUFFICIENT_BUFFER = 122, + /// The filename, directory name, or volume label syntax is incorrect. + INVALID_NAME = 123, + /// The system call level is not correct. + INVALID_LEVEL = 124, + /// The disk has no volume label. + NO_VOLUME_LABEL = 125, + /// The specified module could not be found. + MOD_NOT_FOUND = 126, + /// The specified procedure could not be found. + PROC_NOT_FOUND = 127, + /// There are no child processes to wait for. + WAIT_NO_CHILDREN = 128, + /// The %1 application cannot be run in Win32 mode. + CHILD_NOT_COMPLETE = 129, + /// Attempt to use a file handle to an open disk partition for an operation other than raw disk I/O. + DIRECT_ACCESS_HANDLE = 130, + /// An attempt was made to move the file pointer before the beginning of the file. + NEGATIVE_SEEK = 131, + /// The file pointer cannot be set on the specified device or file. + SEEK_ON_DEVICE = 132, + /// A JOIN or SUBST command cannot be used for a drive that contains previously joined drives. + IS_JOIN_TARGET = 133, + /// An attempt was made to use a JOIN or SUBST command on a drive that has already been joined. + IS_JOINED = 134, + /// An attempt was made to use a JOIN or SUBST command on a drive that has already been substituted. + IS_SUBSTED = 135, + /// The system tried to delete the JOIN of a drive that is not joined. + NOT_JOINED = 136, + /// The system tried to delete the substitution of a drive that is not substituted. + NOT_SUBSTED = 137, + /// The system tried to join a drive to a directory on a joined drive. + JOIN_TO_JOIN = 138, + /// The system tried to substitute a drive to a directory on a substituted drive. + SUBST_TO_SUBST = 139, + /// The system tried to join a drive to a directory on a substituted drive. + JOIN_TO_SUBST = 140, + /// The system tried to SUBST a drive to a directory on a joined drive. + SUBST_TO_JOIN = 141, + /// The system cannot perform a JOIN or SUBST at this time. + BUSY_DRIVE = 142, + /// The system cannot join or substitute a drive to or for a directory on the same drive. + SAME_DRIVE = 143, + /// The directory is not a subdirectory of the root directory. + DIR_NOT_ROOT = 144, + /// The directory is not empty. + DIR_NOT_EMPTY = 145, + /// The path specified is being used in a substitute. + IS_SUBST_PATH = 146, + /// Not enough resources are available to process this command. + IS_JOIN_PATH = 147, + /// The path specified cannot be used at this time. + PATH_BUSY = 148, + /// An attempt was made to join or substitute a drive for which a directory on the drive is the target of a previous substitute. + IS_SUBST_TARGET = 149, + /// System trace information was not specified in your CONFIG.SYS file, or tracing is disallowed. + SYSTEM_TRACE = 150, + /// The number of specified semaphore events for DosMuxSemWait is not correct. + INVALID_EVENT_COUNT = 151, + /// DosMuxSemWait did not execute; too many semaphores are already set. + TOO_MANY_MUXWAITERS = 152, + /// The DosMuxSemWait list is not correct. + INVALID_LIST_FORMAT = 153, + /// The volume label you entered exceeds the label character limit of the target file system. + LABEL_TOO_LONG = 154, + /// Cannot create another thread. + TOO_MANY_TCBS = 155, + /// The recipient process has refused the signal. + SIGNAL_REFUSED = 156, + /// The segment is already discarded and cannot be locked. + DISCARDED = 157, + /// The segment is already unlocked. + NOT_LOCKED = 158, + /// The address for the thread ID is not correct. + BAD_THREADID_ADDR = 159, + /// One or more arguments are not correct. + BAD_ARGUMENTS = 160, + /// The specified path is invalid. + BAD_PATHNAME = 161, + /// A signal is already pending. + SIGNAL_PENDING = 162, + /// No more threads can be created in the system. + MAX_THRDS_REACHED = 164, + /// Unable to lock a region of a file. + LOCK_FAILED = 167, + /// The requested resource is in use. + BUSY = 170, + /// Device's command support detection is in progress. + DEVICE_SUPPORT_IN_PROGRESS = 171, + /// A lock request was not outstanding for the supplied cancel region. + CANCEL_VIOLATION = 173, + /// The file system does not support atomic changes to the lock type. + ATOMIC_LOCKS_NOT_SUPPORTED = 174, + /// The system detected a segment number that was not correct. + INVALID_SEGMENT_NUMBER = 180, + /// The operating system cannot run %1. + INVALID_ORDINAL = 182, + /// Cannot create a file when that file already exists. + ALREADY_EXISTS = 183, + /// The flag passed is not correct. + INVALID_FLAG_NUMBER = 186, + /// The specified system semaphore name was not found. + SEM_NOT_FOUND = 187, + /// The operating system cannot run %1. + INVALID_STARTING_CODESEG = 188, + /// The operating system cannot run %1. + INVALID_STACKSEG = 189, + /// The operating system cannot run %1. + INVALID_MODULETYPE = 190, + /// Cannot run %1 in Win32 mode. + INVALID_EXE_SIGNATURE = 191, + /// The operating system cannot run %1. + EXE_MARKED_INVALID = 192, + /// %1 is not a valid Win32 application. + BAD_EXE_FORMAT = 193, + /// The operating system cannot run %1. + ITERATED_DATA_EXCEEDS_64k = 194, + /// The operating system cannot run %1. + INVALID_MINALLOCSIZE = 195, + /// The operating system cannot run this application program. + DYNLINK_FROM_INVALID_RING = 196, + /// The operating system is not presently configured to run this application. + IOPL_NOT_ENABLED = 197, + /// The operating system cannot run %1. + INVALID_SEGDPL = 198, + /// The operating system cannot run this application program. + AUTODATASEG_EXCEEDS_64k = 199, + /// The code segment cannot be greater than or equal to 64K. + RING2SEG_MUST_BE_MOVABLE = 200, + /// The operating system cannot run %1. + RELOC_CHAIN_XEEDS_SEGLIM = 201, + /// The operating system cannot run %1. + INFLOOP_IN_RELOC_CHAIN = 202, + /// The system could not find the environment option that was entered. + ENVVAR_NOT_FOUND = 203, + /// No process in the command subtree has a signal handler. + NO_SIGNAL_SENT = 205, + /// The filename or extension is too long. + FILENAME_EXCED_RANGE = 206, + /// The ring 2 stack is in use. + RING2_STACK_IN_USE = 207, + /// The global filename characters, * or ?, are entered incorrectly or too many global filename characters are specified. + META_EXPANSION_TOO_LONG = 208, + /// The signal being posted is not correct. + INVALID_SIGNAL_NUMBER = 209, + /// The signal handler cannot be set. + THREAD_1_INACTIVE = 210, + /// The segment is locked and cannot be reallocated. + LOCKED = 212, + /// Too many dynamic-link modules are attached to this program or dynamic-link module. + TOO_MANY_MODULES = 214, + /// Cannot nest calls to LoadModule. + NESTING_NOT_ALLOWED = 215, + /// This version of %1 is not compatible with the version of Windows you're running. + /// Check your computer's system information and then contact the software publisher. + EXE_MACHINE_TYPE_MISMATCH = 216, + /// The image file %1 is signed, unable to modify. + EXE_CANNOT_MODIFY_SIGNED_BINARY = 217, + /// The image file %1 is strong signed, unable to modify. + EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY = 218, + /// This file is checked out or locked for editing by another user. + FILE_CHECKED_OUT = 220, + /// The file must be checked out before saving changes. + CHECKOUT_REQUIRED = 221, + /// The file type being saved or retrieved has been blocked. + BAD_FILE_TYPE = 222, + /// The file size exceeds the limit allowed and cannot be saved. + FILE_TOO_LARGE = 223, + /// Access Denied. Before opening files in this location, you must first add the web site to your trusted sites list, browse to the web site, and select the option to login automatically. + FORMS_AUTH_REQUIRED = 224, + /// Operation did not complete successfully because the file contains a virus or potentially unwanted software. + VIRUS_INFECTED = 225, + /// This file contains a virus or potentially unwanted software and cannot be opened. + /// Due to the nature of this virus or potentially unwanted software, the file has been removed from this location. + VIRUS_DELETED = 226, + /// The pipe is local. + PIPE_LOCAL = 229, + /// The pipe state is invalid. + BAD_PIPE = 230, + /// All pipe instances are busy. + PIPE_BUSY = 231, + /// The pipe is being closed. + NO_DATA = 232, + /// No process is on the other end of the pipe. + PIPE_NOT_CONNECTED = 233, + /// More data is available. + MORE_DATA = 234, + /// The session was canceled. + VC_DISCONNECTED = 240, + /// The specified extended attribute name was invalid. + INVALID_EA_NAME = 254, + /// The extended attributes are inconsistent. + EA_LIST_INCONSISTENT = 255, + /// The wait operation timed out. + IMEOUT = 258, + /// No more data is available. + NO_MORE_ITEMS = 259, + /// The copy functions cannot be used. + CANNOT_COPY = 266, + /// The directory name is invalid. + DIRECTORY = 267, + /// The extended attributes did not fit in the buffer. + EAS_DIDNT_FIT = 275, + /// The extended attribute file on the mounted file system is corrupt. + EA_FILE_CORRUPT = 276, + /// The extended attribute table file is full. + EA_TABLE_FULL = 277, + /// The specified extended attribute handle is invalid. + INVALID_EA_HANDLE = 278, + /// The mounted file system does not support extended attributes. + EAS_NOT_SUPPORTED = 282, + /// Attempt to release mutex not owned by caller. + NOT_OWNER = 288, + /// Too many posts were made to a semaphore. + TOO_MANY_POSTS = 298, + /// Only part of a ReadProcessMemory or WriteProcessMemory request was completed. + PARTIAL_COPY = 299, + /// The oplock request is denied. + OPLOCK_NOT_GRANTED = 300, + /// An invalid oplock acknowledgment was received by the system. + INVALID_OPLOCK_PROTOCOL = 301, + /// The volume is too fragmented to complete this operation. + DISK_TOO_FRAGMENTED = 302, + /// The file cannot be opened because it is in the process of being deleted. + DELETE_PENDING = 303, + /// Short name settings may not be changed on this volume due to the global registry setting. + INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING = 304, + /// Short names are not enabled on this volume. + SHORT_NAMES_NOT_ENABLED_ON_VOLUME = 305, + /// The security stream for the given volume is in an inconsistent state. Please run CHKDSK on the volume. + SECURITY_STREAM_IS_INCONSISTENT = 306, + /// A requested file lock operation cannot be processed due to an invalid byte range. + INVALID_LOCK_RANGE = 307, + /// The subsystem needed to support the image type is not present. + IMAGE_SUBSYSTEM_NOT_PRESENT = 308, + /// The specified file already has a notification GUID associated with it. + NOTIFICATION_GUID_ALREADY_DEFINED = 309, + /// An invalid exception handler routine has been detected. + INVALID_EXCEPTION_HANDLER = 310, + /// Duplicate privileges were specified for the token. + DUPLICATE_PRIVILEGES = 311, + /// No ranges for the specified operation were able to be processed. + NO_RANGES_PROCESSED = 312, + /// Operation is not allowed on a file system internal file. + NOT_ALLOWED_ON_SYSTEM_FILE = 313, + /// The physical resources of this disk have been exhausted. + DISK_RESOURCES_EXHAUSTED = 314, + /// The token representing the data is invalid. + INVALID_TOKEN = 315, + /// The device does not support the command feature. + DEVICE_FEATURE_NOT_SUPPORTED = 316, + /// The system cannot find message text for message number 0x%1 in the message file for %2. + MR_MID_NOT_FOUND = 317, + /// The scope specified was not found. + SCOPE_NOT_FOUND = 318, + /// The Central Access Policy specified is not defined on the target machine. + UNDEFINED_SCOPE = 319, + /// The Central Access Policy obtained from Active Directory is invalid. + INVALID_CAP = 320, + /// The device is unreachable. + DEVICE_UNREACHABLE = 321, + /// The target device has insufficient resources to complete the operation. + DEVICE_NO_RESOURCES = 322, + /// A data integrity checksum error occurred. Data in the file stream is corrupt. + DATA_CHECKSUM_ERROR = 323, + /// An attempt was made to modify both a KERNEL and normal Extended Attribute (EA) in the same operation. + INTERMIXED_KERNEL_EA_OPERATION = 324, + /// Device does not support file-level TRIM. + FILE_LEVEL_TRIM_NOT_SUPPORTED = 326, + /// The command specified a data offset that does not align to the device's granularity/alignment. + OFFSET_ALIGNMENT_VIOLATION = 327, + /// The command specified an invalid field in its parameter list. + INVALID_FIELD_IN_PARAMETER_LIST = 328, + /// An operation is currently in progress with the device. + OPERATION_IN_PROGRESS = 329, + /// An attempt was made to send down the command via an invalid path to the target device. + BAD_DEVICE_PATH = 330, + /// The command specified a number of descriptors that exceeded the maximum supported by the device. + TOO_MANY_DESCRIPTORS = 331, + /// Scrub is disabled on the specified file. + SCRUB_DATA_DISABLED = 332, + /// The storage device does not provide redundancy. + NOT_REDUNDANT_STORAGE = 333, + /// An operation is not supported on a resident file. + RESIDENT_FILE_NOT_SUPPORTED = 334, + /// An operation is not supported on a compressed file. + COMPRESSED_FILE_NOT_SUPPORTED = 335, + /// An operation is not supported on a directory. + DIRECTORY_NOT_SUPPORTED = 336, + /// The specified copy of the requested data could not be read. + NOT_READ_FROM_COPY = 337, + /// No action was taken as a system reboot is required. + FAIL_NOACTION_REBOOT = 350, + /// The shutdown operation failed. + FAIL_SHUTDOWN = 351, + /// The restart operation failed. + FAIL_RESTART = 352, + /// The maximum number of sessions has been reached. + MAX_SESSIONS_REACHED = 353, + /// The thread is already in background processing mode. + THREAD_MODE_ALREADY_BACKGROUND = 400, + /// The thread is not in background processing mode. + THREAD_MODE_NOT_BACKGROUND = 401, + /// The process is already in background processing mode. + PROCESS_MODE_ALREADY_BACKGROUND = 402, + /// The process is not in background processing mode. + PROCESS_MODE_NOT_BACKGROUND = 403, + /// Attempt to access invalid address. + INVALID_ADDRESS = 487, + /// User profile cannot be loaded. + USER_PROFILE_LOAD = 500, + /// Arithmetic result exceeded 32 bits. + ARITHMETIC_OVERFLOW = 534, + /// There is a process on other end of the pipe. + PIPE_CONNECTED = 535, + /// Waiting for a process to open the other end of the pipe. + PIPE_LISTENING = 536, + /// Application verifier has found an error in the current process. + VERIFIER_STOP = 537, + /// An error occurred in the ABIOS subsystem. + ABIOS_ERROR = 538, + /// A warning occurred in the WX86 subsystem. + WX86_WARNING = 539, + /// An error occurred in the WX86 subsystem. + WX86_ERROR = 540, + /// An attempt was made to cancel or set a timer that has an associated APC and the subject thread is not the thread that originally set the timer with an associated APC routine. + TIMER_NOT_CANCELED = 541, + /// Unwind exception code. + UNWIND = 542, + /// An invalid or unaligned stack was encountered during an unwind operation. + BAD_STACK = 543, + /// An invalid unwind target was encountered during an unwind operation. + INVALID_UNWIND_TARGET = 544, + /// Invalid Object Attributes specified to NtCreatePort or invalid Port Attributes specified to NtConnectPort + INVALID_PORT_ATTRIBUTES = 545, + /// Length of message passed to NtRequestPort or NtRequestWaitReplyPort was longer than the maximum message allowed by the port. + PORT_MESSAGE_TOO_LONG = 546, + /// An attempt was made to lower a quota limit below the current usage. + INVALID_QUOTA_LOWER = 547, + /// An attempt was made to attach to a device that was already attached to another device. + DEVICE_ALREADY_ATTACHED = 548, + /// An attempt was made to execute an instruction at an unaligned address and the host system does not support unaligned instruction references. + INSTRUCTION_MISALIGNMENT = 549, + /// Profiling not started. + PROFILING_NOT_STARTED = 550, + /// Profiling not stopped. + PROFILING_NOT_STOPPED = 551, + /// The passed ACL did not contain the minimum required information. + COULD_NOT_INTERPRET = 552, + /// The number of active profiling objects is at the maximum and no more may be started. + PROFILING_AT_LIMIT = 553, + /// Used to indicate that an operation cannot continue without blocking for I/O. + CANT_WAIT = 554, + /// Indicates that a thread attempted to terminate itself by default (called NtTerminateThread with NULL) and it was the last thread in the current process. + CANT_TERMINATE_SELF = 555, + /// If an MM error is returned which is not defined in the standard FsRtl filter, it is converted to one of the following errors which is guaranteed to be in the filter. + /// In this case information is lost, however, the filter correctly handles the exception. + UNEXPECTED_MM_CREATE_ERR = 556, + /// If an MM error is returned which is not defined in the standard FsRtl filter, it is converted to one of the following errors which is guaranteed to be in the filter. + /// In this case information is lost, however, the filter correctly handles the exception. + UNEXPECTED_MM_MAP_ERROR = 557, + /// If an MM error is returned which is not defined in the standard FsRtl filter, it is converted to one of the following errors which is guaranteed to be in the filter. + /// In this case information is lost, however, the filter correctly handles the exception. + UNEXPECTED_MM_EXTEND_ERR = 558, + /// A malformed function table was encountered during an unwind operation. + BAD_FUNCTION_TABLE = 559, + /// Indicates that an attempt was made to assign protection to a file system file or directory and one of the SIDs in the security descriptor could not be translated into a GUID that could be stored by the file system. + /// This causes the protection attempt to fail, which may cause a file creation attempt to fail. + NO_GUID_TRANSLATION = 560, + /// Indicates that an attempt was made to grow an LDT by setting its size, or that the size was not an even number of selectors. + INVALID_LDT_SIZE = 561, + /// Indicates that the starting value for the LDT information was not an integral multiple of the selector size. + INVALID_LDT_OFFSET = 563, + /// Indicates that the user supplied an invalid descriptor when trying to set up Ldt descriptors. + INVALID_LDT_DESCRIPTOR = 564, + /// Indicates a process has too many threads to perform the requested action. + /// For example, assignment of a primary token may only be performed when a process has zero or one threads. + TOO_MANY_THREADS = 565, + /// An attempt was made to operate on a thread within a specific process, but the thread specified is not in the process specified. + THREAD_NOT_IN_PROCESS = 566, + /// Page file quota was exceeded. + PAGEFILE_QUOTA_EXCEEDED = 567, + /// The Netlogon service cannot start because another Netlogon service running in the domain conflicts with the specified role. + LOGON_SERVER_CONFLICT = 568, + /// The SAM database on a Windows Server is significantly out of synchronization with the copy on the Domain Controller. A complete synchronization is required. + SYNCHRONIZATION_REQUIRED = 569, + /// The NtCreateFile API failed. This error should never be returned to an application, it is a place holder for the Windows Lan Manager Redirector to use in its internal error mapping routines. + NET_OPEN_FAILED = 570, + /// {Privilege Failed} The I/O permissions for the process could not be changed. + IO_PRIVILEGE_FAILED = 571, + /// {Application Exit by CTRL+C} The application terminated as a result of a CTRL+C. + CONTROL_C_EXIT = 572, + /// {Missing System File} The required system file %hs is bad or missing. + MISSING_SYSTEMFILE = 573, + /// {Application Error} The exception %s (0x%08lx) occurred in the application at location 0x%08lx. + UNHANDLED_EXCEPTION = 574, + /// {Application Error} The application was unable to start correctly (0x%lx). Click OK to close the application. + APP_INIT_FAILURE = 575, + /// {Unable to Create Paging File} The creation of the paging file %hs failed (%lx). The requested size was %ld. + PAGEFILE_CREATE_FAILED = 576, + /// Windows cannot verify the digital signature for this file. + /// A recent hardware or software change might have installed a file that is signed incorrectly or damaged, or that might be malicious software from an unknown source. + INVALID_IMAGE_HASH = 577, + /// {No Paging File Specified} No paging file was specified in the system configuration. + NO_PAGEFILE = 578, + /// {EXCEPTION} A real-mode application issued a floating-point instruction and floating-point hardware is not present. + ILLEGAL_FLOAT_CONTEXT = 579, + /// An event pair synchronization operation was performed using the thread specific client/server event pair object, but no event pair object was associated with the thread. + NO_EVENT_PAIR = 580, + /// A Windows Server has an incorrect configuration. + DOMAIN_CTRLR_CONFIG_ERROR = 581, + /// An illegal character was encountered. + /// For a multi-byte character set this includes a lead byte without a succeeding trail byte. + /// For the Unicode character set this includes the characters 0xFFFF and 0xFFFE. + ILLEGAL_CHARACTER = 582, + /// The Unicode character is not defined in the Unicode character set installed on the system. + UNDEFINED_CHARACTER = 583, + /// The paging file cannot be created on a floppy diskette. + FLOPPY_VOLUME = 584, + /// The system BIOS failed to connect a system interrupt to the device or bus for which the device is connected. + BIOS_FAILED_TO_CONNECT_INTERRUPT = 585, + /// This operation is only allowed for the Primary Domain Controller of the domain. + BACKUP_CONTROLLER = 586, + /// An attempt was made to acquire a mutant such that its maximum count would have been exceeded. + MUTANT_LIMIT_EXCEEDED = 587, + /// A volume has been accessed for which a file system driver is required that has not yet been loaded. + FS_DRIVER_REQUIRED = 588, + /// {Registry File Failure} The registry cannot load the hive (file): %hs or its log or alternate. It is corrupt, absent, or not writable. + CANNOT_LOAD_REGISTRY_FILE = 589, + /// {Unexpected Failure in DebugActiveProcess} An unexpected failure occurred while processing a DebugActiveProcess API request. + /// You may choose OK to terminate the process, or Cancel to ignore the error. + DEBUG_ATTACH_FAILED = 590, + /// {Fatal System Error} The %hs system process terminated unexpectedly with a status of 0x%08x (0x%08x 0x%08x). The system has been shut down. + SYSTEM_PROCESS_TERMINATED = 591, + /// {Data Not Accepted} The TDI client could not handle the data received during an indication. + DATA_NOT_ACCEPTED = 592, + /// NTVDM encountered a hard error. + VDM_HARD_ERROR = 593, + /// {Cancel Timeout} The driver %hs failed to complete a cancelled I/O request in the allotted time. + DRIVER_CANCEL_TIMEOUT = 594, + /// {Reply Message Mismatch} An attempt was made to reply to an LPC message, but the thread specified by the client ID in the message was not waiting on that message. + REPLY_MESSAGE_MISMATCH = 595, + /// {Delayed Write Failed} Windows was unable to save all the data for the file %hs. The data has been lost. + /// This error may be caused by a failure of your computer hardware or network connection. Please try to save this file elsewhere. + LOST_WRITEBEHIND_DATA = 596, + /// The parameter(s) passed to the server in the client/server shared memory window were invalid. + /// Too much data may have been put in the shared memory window. + CLIENT_SERVER_PARAMETERS_INVALID = 597, + /// The stream is not a tiny stream. + NOT_TINY_STREAM = 598, + /// The request must be handled by the stack overflow code. + STACK_OVERFLOW_READ = 599, + /// Internal OFS status codes indicating how an allocation operation is handled. + /// Either it is retried after the containing onode is moved or the extent stream is converted to a large stream. + CONVERT_TO_LARGE = 600, + /// The attempt to find the object found an object matching by ID on the volume but it is out of the scope of the handle used for the operation. + FOUND_OUT_OF_SCOPE = 601, + /// The bucket array must be grown. Retry transaction after doing so. + ALLOCATE_BUCKET = 602, + /// The user/kernel marshalling buffer has overflowed. + MARSHALL_OVERFLOW = 603, + /// The supplied variant structure contains invalid data. + INVALID_VARIANT = 604, + /// The specified buffer contains ill-formed data. + BAD_COMPRESSION_BUFFER = 605, + /// {Audit Failed} An attempt to generate a security audit failed. + AUDIT_FAILED = 606, + /// The timer resolution was not previously set by the current process. + TIMER_RESOLUTION_NOT_SET = 607, + /// There is insufficient account information to log you on. + INSUFFICIENT_LOGON_INFO = 608, + /// {Invalid DLL Entrypoint} The dynamic link library %hs is not written correctly. + /// The stack pointer has been left in an inconsistent state. + /// The entrypoint should be declared as WINAPI or STDCALL. + /// Select YES to fail the DLL load. Select NO to continue execution. + /// Selecting NO may cause the application to operate incorrectly. + BAD_DLL_ENTRYPOINT = 609, + /// {Invalid Service Callback Entrypoint} The %hs service is not written correctly. + /// The stack pointer has been left in an inconsistent state. + /// The callback entrypoint should be declared as WINAPI or STDCALL. + /// Selecting OK will cause the service to continue operation. + /// However, the service process may operate incorrectly. + BAD_SERVICE_ENTRYPOINT = 610, + /// There is an IP address conflict with another system on the network. + IP_ADDRESS_CONFLICT1 = 611, + /// There is an IP address conflict with another system on the network. + IP_ADDRESS_CONFLICT2 = 612, + /// {Low On Registry Space} The system has reached the maximum size allowed for the system part of the registry. Additional storage requests will be ignored. + REGISTRY_QUOTA_LIMIT = 613, + /// A callback return system service cannot be executed when no callback is active. + NO_CALLBACK_ACTIVE = 614, + /// The password provided is too short to meet the policy of your user account. Please choose a longer password. + PWD_TOO_SHORT = 615, + /// The policy of your user account does not allow you to change passwords too frequently. + /// This is done to prevent users from changing back to a familiar, but potentially discovered, password. + /// If you feel your password has been compromised then please contact your administrator immediately to have a new one assigned. + PWD_TOO_RECENT = 616, + /// You have attempted to change your password to one that you have used in the past. + /// The policy of your user account does not allow this. + /// Please select a password that you have not previously used. + PWD_HISTORY_CONFLICT = 617, + /// The specified compression format is unsupported. + UNSUPPORTED_COMPRESSION = 618, + /// The specified hardware profile configuration is invalid. + INVALID_HW_PROFILE = 619, + /// The specified Plug and Play registry device path is invalid. + INVALID_PLUGPLAY_DEVICE_PATH = 620, + /// The specified quota list is internally inconsistent with its descriptor. + QUOTA_LIST_INCONSISTENT = 621, + /// {Windows Evaluation Notification} The evaluation period for this installation of Windows has expired. This system will shutdown in 1 hour. + /// To restore access to this installation of Windows, please upgrade this installation using a licensed distribution of this product. + EVALUATION_EXPIRATION = 622, + /// {Illegal System DLL Relocation} The system DLL %hs was relocated in memory. The application will not run properly. + /// The relocation occurred because the DLL %hs occupied an address range reserved for Windows system DLLs. + /// The vendor supplying the DLL should be contacted for a new DLL. + ILLEGAL_DLL_RELOCATION = 623, + /// {DLL Initialization Failed} The application failed to initialize because the window station is shutting down. + DLL_INIT_FAILED_LOGOFF = 624, + /// The validation process needs to continue on to the next step. + VALIDATE_CONTINUE = 625, + /// There are no more matches for the current index enumeration. + NO_MORE_MATCHES = 626, + /// The range could not be added to the range list because of a conflict. + RANGE_LIST_CONFLICT = 627, + /// The server process is running under a SID different than that required by client. + SERVER_SID_MISMATCH = 628, + /// A group marked use for deny only cannot be enabled. + CANT_ENABLE_DENY_ONLY = 629, + /// {EXCEPTION} Multiple floating point faults. + FLOAT_MULTIPLE_FAULTS = 630, + /// {EXCEPTION} Multiple floating point traps. + FLOAT_MULTIPLE_TRAPS = 631, + /// The requested interface is not supported. + NOINTERFACE = 632, + /// {System Standby Failed} The driver %hs does not support standby mode. + /// Updating this driver may allow the system to go to standby mode. + DRIVER_FAILED_SLEEP = 633, + /// The system file %1 has become corrupt and has been replaced. + CORRUPT_SYSTEM_FILE = 634, + /// {Virtual Memory Minimum Too Low} Your system is low on virtual memory. + /// Windows is increasing the size of your virtual memory paging file. + /// During this process, memory requests for some applications may be denied. For more information, see Help. + COMMITMENT_MINIMUM = 635, + /// A device was removed so enumeration must be restarted. + PNP_RESTART_ENUMERATION = 636, + /// {Fatal System Error} The system image %s is not properly signed. + /// The file has been replaced with the signed file. The system has been shut down. + SYSTEM_IMAGE_BAD_SIGNATURE = 637, + /// Device will not start without a reboot. + PNP_REBOOT_REQUIRED = 638, + /// There is not enough power to complete the requested operation. + INSUFFICIENT_POWER = 639, + /// ERROR_MULTIPLE_FAULT_VIOLATION + MULTIPLE_FAULT_VIOLATION = 640, + /// The system is in the process of shutting down. + SYSTEM_SHUTDOWN = 641, + /// An attempt to remove a processes DebugPort was made, but a port was not already associated with the process. + PORT_NOT_SET = 642, + /// This version of Windows is not compatible with the behavior version of directory forest, domain or domain controller. + DS_VERSION_CHECK_FAILURE = 643, + /// The specified range could not be found in the range list. + RANGE_NOT_FOUND = 644, + /// The driver was not loaded because the system is booting into safe mode. + NOT_SAFE_MODE_DRIVER = 646, + /// The driver was not loaded because it failed its initialization call. + FAILED_DRIVER_ENTRY = 647, + /// The "%hs" encountered an error while applying power or reading the device configuration. + /// This may be caused by a failure of your hardware or by a poor connection. + DEVICE_ENUMERATION_ERROR = 648, + /// The create operation failed because the name contained at least one mount point which resolves to a volume to which the specified device object is not attached. + MOUNT_POINT_NOT_RESOLVED = 649, + /// The device object parameter is either not a valid device object or is not attached to the volume specified by the file name. + INVALID_DEVICE_OBJECT_PARAMETER = 650, + /// A Machine Check Error has occurred. + /// Please check the system eventlog for additional information. + MCA_OCCURED = 651, + /// There was error [%2] processing the driver database. + DRIVER_DATABASE_ERROR = 652, + /// System hive size has exceeded its limit. + SYSTEM_HIVE_TOO_LARGE = 653, + /// The driver could not be loaded because a previous version of the driver is still in memory. + DRIVER_FAILED_PRIOR_UNLOAD = 654, + /// {Volume Shadow Copy Service} Please wait while the Volume Shadow Copy Service prepares volume %hs for hibernation. + VOLSNAP_PREPARE_HIBERNATE = 655, + /// The system has failed to hibernate (The error code is %hs). + /// Hibernation will be disabled until the system is restarted. + HIBERNATION_FAILURE = 656, + /// The password provided is too long to meet the policy of your user account. Please choose a shorter password. + PWD_TOO_LONG = 657, + /// The requested operation could not be completed due to a file system limitation. + FILE_SYSTEM_LIMITATION = 665, + /// An assertion failure has occurred. + ASSERTION_FAILURE = 668, + /// An error occurred in the ACPI subsystem. + ACPI_ERROR = 669, + /// WOW Assertion Error. + WOW_ASSERTION = 670, + /// A device is missing in the system BIOS MPS table. This device will not be used. + /// Please contact your system vendor for system BIOS update. + PNP_BAD_MPS_TABLE = 671, + /// A translator failed to translate resources. + PNP_TRANSLATION_FAILED = 672, + /// A IRQ translator failed to translate resources. + PNP_IRQ_TRANSLATION_FAILED = 673, + /// Driver %2 returned invalid ID for a child device (%3). + PNP_INVALID_ID = 674, + /// {Kernel Debugger Awakened} the system debugger was awakened by an interrupt. + WAKE_SYSTEM_DEBUGGER = 675, + /// {Handles Closed} Handles to objects have been automatically closed as a result of the requested operation. + HANDLES_CLOSED = 676, + /// {Too Much Information} The specified access control list (ACL) contained more information than was expected. + EXTRANEOUS_INFORMATION = 677, + /// This warning level status indicates that the transaction state already exists for the registry sub-tree, but that a transaction commit was previously aborted. + /// The commit has NOT been completed, but has not been rolled back either (so it may still be committed if desired). + RXACT_COMMIT_NECESSARY = 678, + /// {Media Changed} The media may have changed. + MEDIA_CHECK = 679, + /// {GUID Substitution} During the translation of a global identifier (GUID) to a Windows security ID (SID), no administratively-defined GUID prefix was found. + /// A substitute prefix was used, which will not compromise system security. + /// However, this may provide a more restrictive access than intended. + GUID_SUBSTITUTION_MADE = 680, + /// The create operation stopped after reaching a symbolic link. + STOPPED_ON_SYMLINK = 681, + /// A long jump has been executed. + LONGJUMP = 682, + /// The Plug and Play query operation was not successful. + PLUGPLAY_QUERY_VETOED = 683, + /// A frame consolidation has been executed. + UNWIND_CONSOLIDATE = 684, + /// {Registry Hive Recovered} Registry hive (file): %hs was corrupted and it has been recovered. Some data might have been lost. + REGISTRY_HIVE_RECOVERED = 685, + /// The application is attempting to run executable code from the module %hs. This may be insecure. + /// An alternative, %hs, is available. Should the application use the secure module %hs? + DLL_MIGHT_BE_INSECURE = 686, + /// The application is loading executable code from the module %hs. + /// This is secure, but may be incompatible with previous releases of the operating system. + /// An alternative, %hs, is available. Should the application use the secure module %hs? + DLL_MIGHT_BE_INCOMPATIBLE = 687, + /// Debugger did not handle the exception. + DBG_EXCEPTION_NOT_HANDLED = 688, + /// Debugger will reply later. + DBG_REPLY_LATER = 689, + /// Debugger cannot provide handle. + DBG_UNABLE_TO_PROVIDE_HANDLE = 690, + /// Debugger terminated thread. + DBG_TERMINATE_THREAD = 691, + /// Debugger terminated process. + DBG_TERMINATE_PROCESS = 692, + /// Debugger got control C. + DBG_CONTROL_C = 693, + /// Debugger printed exception on control C. + DBG_PRINTEXCEPTION_C = 694, + /// Debugger received RIP exception. + DBG_RIPEXCEPTION = 695, + /// Debugger received control break. + DBG_CONTROL_BREAK = 696, + /// Debugger command communication exception. + DBG_COMMAND_EXCEPTION = 697, + /// {Object Exists} An attempt was made to create an object and the object name already existed. + OBJECT_NAME_EXISTS = 698, + /// {Thread Suspended} A thread termination occurred while the thread was suspended. + /// The thread was resumed, and termination proceeded. + THREAD_WAS_SUSPENDED = 699, + /// {Image Relocated} An image file could not be mapped at the address specified in the image file. Local fixups must be performed on this image. + IMAGE_NOT_AT_BASE = 700, + /// This informational level status indicates that a specified registry sub-tree transaction state did not yet exist and had to be created. + RXACT_STATE_CREATED = 701, + /// {Segment Load} A virtual DOS machine (VDM) is loading, unloading, or moving an MS-DOS or Win16 program segment image. + /// An exception is raised so a debugger can load, unload or track symbols and breakpoints within these 16-bit segments. + SEGMENT_NOTIFICATION = 702, + /// {Invalid Current Directory} The process cannot switch to the startup current directory %hs. + /// Select OK to set current directory to %hs, or select CANCEL to exit. + BAD_CURRENT_DIRECTORY = 703, + /// {Redundant Read} To satisfy a read request, the NT fault-tolerant file system successfully read the requested data from a redundant copy. + /// This was done because the file system encountered a failure on a member of the fault-tolerant volume, but was unable to reassign the failing area of the device. + FT_READ_RECOVERY_FROM_BACKUP = 704, + /// {Redundant Write} To satisfy a write request, the NT fault-tolerant file system successfully wrote a redundant copy of the information. + /// This was done because the file system encountered a failure on a member of the fault-tolerant volume, but was not able to reassign the failing area of the device. + FT_WRITE_RECOVERY = 705, + /// {Machine Type Mismatch} The image file %hs is valid, but is for a machine type other than the current machine. + /// Select OK to continue, or CANCEL to fail the DLL load. + IMAGE_MACHINE_TYPE_MISMATCH = 706, + /// {Partial Data Received} The network transport returned partial data to its client. The remaining data will be sent later. + RECEIVE_PARTIAL = 707, + /// {Expedited Data Received} The network transport returned data to its client that was marked as expedited by the remote system. + RECEIVE_EXPEDITED = 708, + /// {Partial Expedited Data Received} The network transport returned partial data to its client and this data was marked as expedited by the remote system. The remaining data will be sent later. + RECEIVE_PARTIAL_EXPEDITED = 709, + /// {TDI Event Done} The TDI indication has completed successfully. + EVENT_DONE = 710, + /// {TDI Event Pending} The TDI indication has entered the pending state. + EVENT_PENDING = 711, + /// Checking file system on %wZ. + CHECKING_FILE_SYSTEM = 712, + /// {Fatal Application Exit} %hs. + FATAL_APP_EXIT = 713, + /// The specified registry key is referenced by a predefined handle. + PREDEFINED_HANDLE = 714, + /// {Page Unlocked} The page protection of a locked page was changed to 'No Access' and the page was unlocked from memory and from the process. + WAS_UNLOCKED = 715, + /// %hs + SERVICE_NOTIFICATION = 716, + /// {Page Locked} One of the pages to lock was already locked. + WAS_LOCKED = 717, + /// Application popup: %1 : %2 + LOG_HARD_ERROR = 718, + /// ERROR_ALREADY_WIN32 + ALREADY_WIN32 = 719, + /// {Machine Type Mismatch} The image file %hs is valid, but is for a machine type other than the current machine. + IMAGE_MACHINE_TYPE_MISMATCH_EXE = 720, + /// A yield execution was performed and no thread was available to run. + NO_YIELD_PERFORMED = 721, + /// The resumable flag to a timer API was ignored. + TIMER_RESUME_IGNORED = 722, + /// The arbiter has deferred arbitration of these resources to its parent. + ARBITRATION_UNHANDLED = 723, + /// The inserted CardBus device cannot be started because of a configuration error on "%hs". + CARDBUS_NOT_SUPPORTED = 724, + /// The CPUs in this multiprocessor system are not all the same revision level. + /// To use all processors the operating system restricts itself to the features of the least capable processor in the system. + /// Should problems occur with this system, contact the CPU manufacturer to see if this mix of processors is supported. + MP_PROCESSOR_MISMATCH = 725, + /// The system was put into hibernation. + HIBERNATED = 726, + /// The system was resumed from hibernation. + RESUME_HIBERNATION = 727, + /// Windows has detected that the system firmware (BIOS) was updated [previous firmware date = %2, current firmware date %3]. + FIRMWARE_UPDATED = 728, + /// A device driver is leaking locked I/O pages causing system degradation. + /// The system has automatically enabled tracking code in order to try and catch the culprit. + DRIVERS_LEAKING_LOCKED_PAGES = 729, + /// The system has awoken. + WAKE_SYSTEM = 730, + /// ERROR_WAIT_1 + WAIT_1 = 731, + /// ERROR_WAIT_2 + WAIT_2 = 732, + /// ERROR_WAIT_3 + WAIT_3 = 733, + /// ERROR_WAIT_63 + WAIT_63 = 734, + /// ERROR_ABANDONED_WAIT_0 + ABANDONED_WAIT_0 = 735, + /// ERROR_ABANDONED_WAIT_63 + ABANDONED_WAIT_63 = 736, + /// ERROR_USER_APC + USER_APC = 737, + /// ERROR_KERNEL_APC + KERNEL_APC = 738, + /// ERROR_ALERTED + ALERTED = 739, + /// The requested operation requires elevation. + ELEVATION_REQUIRED = 740, + /// A reparse should be performed by the Object Manager since the name of the file resulted in a symbolic link. + REPARSE = 741, + /// An open/create operation completed while an oplock break is underway. + OPLOCK_BREAK_IN_PROGRESS = 742, + /// A new volume has been mounted by a file system. + VOLUME_MOUNTED = 743, + /// This success level status indicates that the transaction state already exists for the registry sub-tree, but that a transaction commit was previously aborted. The commit has now been completed. + RXACT_COMMITTED = 744, + /// This indicates that a notify change request has been completed due to closing the handle which made the notify change request. + NOTIFY_CLEANUP = 745, + /// {Connect Failure on Primary Transport} An attempt was made to connect to the remote server %hs on the primary transport, but the connection failed. + /// The computer WAS able to connect on a secondary transport. + PRIMARY_TRANSPORT_CONNECT_FAILED = 746, + /// Page fault was a transition fault. + PAGE_FAULT_TRANSITION = 747, + /// Page fault was a demand zero fault. + PAGE_FAULT_DEMAND_ZERO = 748, + /// Page fault was a demand zero fault. + PAGE_FAULT_COPY_ON_WRITE = 749, + /// Page fault was a demand zero fault. + PAGE_FAULT_GUARD_PAGE = 750, + /// Page fault was satisfied by reading from a secondary storage device. + PAGE_FAULT_PAGING_FILE = 751, + /// Cached page was locked during operation. + CACHE_PAGE_LOCKED = 752, + /// Crash dump exists in paging file. + CRASH_DUMP = 753, + /// Specified buffer contains all zeros. + BUFFER_ALL_ZEROS = 754, + /// A reparse should be performed by the Object Manager since the name of the file resulted in a symbolic link. + REPARSE_OBJECT = 755, + /// The device has succeeded a query-stop and its resource requirements have changed. + RESOURCE_REQUIREMENTS_CHANGED = 756, + /// The translator has translated these resources into the global space and no further translations should be performed. + TRANSLATION_COMPLETE = 757, + /// A process being terminated has no threads to terminate. + NOTHING_TO_TERMINATE = 758, + /// The specified process is not part of a job. + PROCESS_NOT_IN_JOB = 759, + /// The specified process is part of a job. + PROCESS_IN_JOB = 760, + /// {Volume Shadow Copy Service} The system is now ready for hibernation. + VOLSNAP_HIBERNATE_READY = 761, + /// A file system or file system filter driver has successfully completed an FsFilter operation. + FSFILTER_OP_COMPLETED_SUCCESSFULLY = 762, + /// The specified interrupt vector was already connected. + INTERRUPT_VECTOR_ALREADY_CONNECTED = 763, + /// The specified interrupt vector is still connected. + INTERRUPT_STILL_CONNECTED = 764, + /// An operation is blocked waiting for an oplock. + WAIT_FOR_OPLOCK = 765, + /// Debugger handled exception. + DBG_EXCEPTION_HANDLED = 766, + /// Debugger continued. + DBG_CONTINUE = 767, + /// An exception occurred in a user mode callback and the kernel callback frame should be removed. + CALLBACK_POP_STACK = 768, + /// Compression is disabled for this volume. + COMPRESSION_DISABLED = 769, + /// The data provider cannot fetch backwards through a result set. + CANTFETCHBACKWARDS = 770, + /// The data provider cannot scroll backwards through a result set. + CANTSCROLLBACKWARDS = 771, + /// The data provider requires that previously fetched data is released before asking for more data. + ROWSNOTRELEASED = 772, + /// The data provider was not able to interpret the flags set for a column binding in an accessor. + BAD_ACCESSOR_FLAGS = 773, + /// One or more errors occurred while processing the request. + ERRORS_ENCOUNTERED = 774, + /// The implementation is not capable of performing the request. + NOT_CAPABLE = 775, + /// The client of a component requested an operation which is not valid given the state of the component instance. + REQUEST_OUT_OF_SEQUENCE = 776, + /// A version number could not be parsed. + VERSION_PARSE_ERROR = 777, + /// The iterator's start position is invalid. + BADSTARTPOSITION = 778, + /// The hardware has reported an uncorrectable memory error. + MEMORY_HARDWARE = 779, + /// The attempted operation required self healing to be enabled. + DISK_REPAIR_DISABLED = 780, + /// The Desktop heap encountered an error while allocating session memory. + /// There is more information in the system event log. + INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE = 781, + /// The system power state is transitioning from %2 to %3. + SYSTEM_POWERSTATE_TRANSITION = 782, + /// The system power state is transitioning from %2 to %3 but could enter %4. + SYSTEM_POWERSTATE_COMPLEX_TRANSITION = 783, + /// A thread is getting dispatched with MCA EXCEPTION because of MCA. + MCA_EXCEPTION = 784, + /// Access to %1 is monitored by policy rule %2. + ACCESS_AUDIT_BY_POLICY = 785, + /// Access to %1 has been restricted by your Administrator by policy rule %2. + ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY = 786, + /// A valid hibernation file has been invalidated and should be abandoned. + ABANDON_HIBERFILE = 787, + /// {Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. + /// This error may be caused by network connectivity issues. Please try to save this file elsewhere. + LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED = 788, + /// {Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. + /// This error was returned by the server on which the file exists. Please try to save this file elsewhere. + LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR = 789, + /// {Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. + /// This error may be caused if the device has been removed or the media is write-protected. + LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR = 790, + /// The resources required for this device conflict with the MCFG table. + BAD_MCFG_TABLE = 791, + /// The volume repair could not be performed while it is online. + /// Please schedule to take the volume offline so that it can be repaired. + DISK_REPAIR_REDIRECTED = 792, + /// The volume repair was not successful. + DISK_REPAIR_UNSUCCESSFUL = 793, + /// One of the volume corruption logs is full. + /// Further corruptions that may be detected won't be logged. + CORRUPT_LOG_OVERFULL = 794, + /// One of the volume corruption logs is internally corrupted and needs to be recreated. + /// The volume may contain undetected corruptions and must be scanned. + CORRUPT_LOG_CORRUPTED = 795, + /// One of the volume corruption logs is unavailable for being operated on. + CORRUPT_LOG_UNAVAILABLE = 796, + /// One of the volume corruption logs was deleted while still having corruption records in them. + /// The volume contains detected corruptions and must be scanned. + CORRUPT_LOG_DELETED_FULL = 797, + /// One of the volume corruption logs was cleared by chkdsk and no longer contains real corruptions. + CORRUPT_LOG_CLEARED = 798, + /// Orphaned files exist on the volume but could not be recovered because no more new names could be created in the recovery directory. Files must be moved from the recovery directory. + ORPHAN_NAME_EXHAUSTED = 799, + /// The oplock that was associated with this handle is now associated with a different handle. + OPLOCK_SWITCHED_TO_NEW_HANDLE = 800, + /// An oplock of the requested level cannot be granted. An oplock of a lower level may be available. + CANNOT_GRANT_REQUESTED_OPLOCK = 801, + /// The operation did not complete successfully because it would cause an oplock to be broken. + /// The caller has requested that existing oplocks not be broken. + CANNOT_BREAK_OPLOCK = 802, + /// The handle with which this oplock was associated has been closed. The oplock is now broken. + OPLOCK_HANDLE_CLOSED = 803, + /// The specified access control entry (ACE) does not contain a condition. + NO_ACE_CONDITION = 804, + /// The specified access control entry (ACE) contains an invalid condition. + INVALID_ACE_CONDITION = 805, + /// Access to the specified file handle has been revoked. + FILE_HANDLE_REVOKED = 806, + /// An image file was mapped at a different address from the one specified in the image file but fixups will still be automatically performed on the image. + IMAGE_AT_DIFFERENT_BASE = 807, + /// Access to the extended attribute was denied. + EA_ACCESS_DENIED = 994, + /// The I/O operation has been aborted because of either a thread exit or an application request. + OPERATION_ABORTED = 995, + /// Overlapped I/O event is not in a signaled state. + IO_INCOMPLETE = 996, + /// Overlapped I/O operation is in progress. + IO_PENDING = 997, + /// Invalid access to memory location. + NOACCESS = 998, + /// Error performing inpage operation. + SWAPERROR = 999, + /// Recursion too deep; the stack overflowed. + STACK_OVERFLOW = 1001, + /// The window cannot act on the sent message. + INVALID_MESSAGE = 1002, + /// Cannot complete this function. + CAN_NOT_COMPLETE = 1003, + /// Invalid flags. + INVALID_FLAGS = 1004, + /// The volume does not contain a recognized file system. + /// Please make sure that all required file system drivers are loaded and that the volume is not corrupted. + UNRECOGNIZED_VOLUME = 1005, + /// The volume for a file has been externally altered so that the opened file is no longer valid. + FILE_INVALID = 1006, + /// The requested operation cannot be performed in full-screen mode. + FULLSCREEN_MODE = 1007, + /// An attempt was made to reference a token that does not exist. + NO_TOKEN = 1008, + /// The configuration registry database is corrupt. + BADDB = 1009, + /// The configuration registry key is invalid. + BADKEY = 1010, + /// The configuration registry key could not be opened. + CANTOPEN = 1011, + /// The configuration registry key could not be read. + CANTREAD = 1012, + /// The configuration registry key could not be written. + CANTWRITE = 1013, + /// One of the files in the registry database had to be recovered by use of a log or alternate copy. The recovery was successful. + REGISTRY_RECOVERED = 1014, + /// The registry is corrupted. The structure of one of the files containing registry data is corrupted, or the system's memory image of the file is corrupted, or the file could not be recovered because the alternate copy or log was absent or corrupted. + REGISTRY_CORRUPT = 1015, + /// An I/O operation initiated by the registry failed unrecoverably. + /// The registry could not read in, or write out, or flush, one of the files that contain the system's image of the registry. + REGISTRY_IO_FAILED = 1016, + /// The system has attempted to load or restore a file into the registry, but the specified file is not in a registry file format. + NOT_REGISTRY_FILE = 1017, + /// Illegal operation attempted on a registry key that has been marked for deletion. + KEY_DELETED = 1018, + /// System could not allocate the required space in a registry log. + NO_LOG_SPACE = 1019, + /// Cannot create a symbolic link in a registry key that already has subkeys or values. + KEY_HAS_CHILDREN = 1020, + /// Cannot create a stable subkey under a volatile parent key. + CHILD_MUST_BE_VOLATILE = 1021, + /// A notify change request is being completed and the information is not being returned in the caller's buffer. + /// The caller now needs to enumerate the files to find the changes. + NOTIFY_ENUM_DIR = 1022, + /// A stop control has been sent to a service that other running services are dependent on. + DEPENDENT_SERVICES_RUNNING = 1051, + /// The requested control is not valid for this service. + INVALID_SERVICE_CONTROL = 1052, + /// The service did not respond to the start or control request in a timely fashion. + SERVICE_REQUEST_TIMEOUT = 1053, + /// A thread could not be created for the service. + SERVICE_NO_THREAD = 1054, + /// The service database is locked. + SERVICE_DATABASE_LOCKED = 1055, + /// An instance of the service is already running. + SERVICE_ALREADY_RUNNING = 1056, + /// The account name is invalid or does not exist, or the password is invalid for the account name specified. + INVALID_SERVICE_ACCOUNT = 1057, + /// The service cannot be started, either because it is disabled or because it has no enabled devices associated with it. + SERVICE_DISABLED = 1058, + /// Circular service dependency was specified. + CIRCULAR_DEPENDENCY = 1059, + /// The specified service does not exist as an installed service. + SERVICE_DOES_NOT_EXIST = 1060, + /// The service cannot accept control messages at this time. + SERVICE_CANNOT_ACCEPT_CTRL = 1061, + /// The service has not been started. + SERVICE_NOT_ACTIVE = 1062, + /// The service process could not connect to the service controller. + FAILED_SERVICE_CONTROLLER_CONNECT = 1063, + /// An exception occurred in the service when handling the control request. + EXCEPTION_IN_SERVICE = 1064, + /// The database specified does not exist. + DATABASE_DOES_NOT_EXIST = 1065, + /// The service has returned a service-specific error code. + SERVICE_SPECIFIC_ERROR = 1066, + /// The process terminated unexpectedly. + PROCESS_ABORTED = 1067, + /// The dependency service or group failed to start. + SERVICE_DEPENDENCY_FAIL = 1068, + /// The service did not start due to a logon failure. + SERVICE_LOGON_FAILED = 1069, + /// After starting, the service hung in a start-pending state. + SERVICE_START_HANG = 1070, + /// The specified service database lock is invalid. + INVALID_SERVICE_LOCK = 1071, + /// The specified service has been marked for deletion. + SERVICE_MARKED_FOR_DELETE = 1072, + /// The specified service already exists. + SERVICE_EXISTS = 1073, + /// The system is currently running with the last-known-good configuration. + ALREADY_RUNNING_LKG = 1074, + /// The dependency service does not exist or has been marked for deletion. + SERVICE_DEPENDENCY_DELETED = 1075, + /// The current boot has already been accepted for use as the last-known-good control set. + BOOT_ALREADY_ACCEPTED = 1076, + /// No attempts to start the service have been made since the last boot. + SERVICE_NEVER_STARTED = 1077, + /// The name is already in use as either a service name or a service display name. + DUPLICATE_SERVICE_NAME = 1078, + /// The account specified for this service is different from the account specified for other services running in the same process. + DIFFERENT_SERVICE_ACCOUNT = 1079, + /// Failure actions can only be set for Win32 services, not for drivers. + CANNOT_DETECT_DRIVER_FAILURE = 1080, + /// This service runs in the same process as the service control manager. + /// Therefore, the service control manager cannot take action if this service's process terminates unexpectedly. + CANNOT_DETECT_PROCESS_ABORT = 1081, + /// No recovery program has been configured for this service. + NO_RECOVERY_PROGRAM = 1082, + /// The executable program that this service is configured to run in does not implement the service. + SERVICE_NOT_IN_EXE = 1083, + /// This service cannot be started in Safe Mode. + NOT_SAFEBOOT_SERVICE = 1084, + /// The physical end of the tape has been reached. + END_OF_MEDIA = 1100, + /// A tape access reached a filemark. + FILEMARK_DETECTED = 1101, + /// The beginning of the tape or a partition was encountered. + BEGINNING_OF_MEDIA = 1102, + /// A tape access reached the end of a set of files. + SETMARK_DETECTED = 1103, + /// No more data is on the tape. + NO_DATA_DETECTED = 1104, + /// Tape could not be partitioned. + PARTITION_FAILURE = 1105, + /// When accessing a new tape of a multivolume partition, the current block size is incorrect. + INVALID_BLOCK_LENGTH = 1106, + /// Tape partition information could not be found when loading a tape. + DEVICE_NOT_PARTITIONED = 1107, + /// Unable to lock the media eject mechanism. + UNABLE_TO_LOCK_MEDIA = 1108, + /// Unable to unload the media. + UNABLE_TO_UNLOAD_MEDIA = 1109, + /// The media in the drive may have changed. + MEDIA_CHANGED = 1110, + /// The I/O bus was reset. + BUS_RESET = 1111, + /// No media in drive. + NO_MEDIA_IN_DRIVE = 1112, + /// No mapping for the Unicode character exists in the target multi-byte code page. + NO_UNICODE_TRANSLATION = 1113, + /// A dynamic link library (DLL) initialization routine failed. + DLL_INIT_FAILED = 1114, + /// A system shutdown is in progress. + SHUTDOWN_IN_PROGRESS = 1115, + /// Unable to abort the system shutdown because no shutdown was in progress. + NO_SHUTDOWN_IN_PROGRESS = 1116, + /// The request could not be performed because of an I/O device error. + IO_DEVICE = 1117, + /// No serial device was successfully initialized. The serial driver will unload. + SERIAL_NO_DEVICE = 1118, + /// Unable to open a device that was sharing an interrupt request (IRQ) with other devices. + /// At least one other device that uses that IRQ was already opened. + IRQ_BUSY = 1119, + /// A serial I/O operation was completed by another write to the serial port. The IOCTL_SERIAL_XOFF_COUNTER reached zero.) + MORE_WRITES = 1120, + /// A serial I/O operation completed because the timeout period expired. + /// The IOCTL_SERIAL_XOFF_COUNTER did not reach zero.) + COUNTER_TIMEOUT = 1121, + /// No ID address mark was found on the floppy disk. + FLOPPY_ID_MARK_NOT_FOUND = 1122, + /// Mismatch between the floppy disk sector ID field and the floppy disk controller track address. + FLOPPY_WRONG_CYLINDER = 1123, + /// The floppy disk controller reported an error that is not recognized by the floppy disk driver. + FLOPPY_UNKNOWN_ERROR = 1124, + /// The floppy disk controller returned inconsistent results in its registers. + FLOPPY_BAD_REGISTERS = 1125, + /// While accessing the hard disk, a recalibrate operation failed, even after retries. + DISK_RECALIBRATE_FAILED = 1126, + /// While accessing the hard disk, a disk operation failed even after retries. + DISK_OPERATION_FAILED = 1127, + /// While accessing the hard disk, a disk controller reset was needed, but even that failed. + DISK_RESET_FAILED = 1128, + /// Physical end of tape encountered. + EOM_OVERFLOW = 1129, + /// Not enough server storage is available to process this command. + NOT_ENOUGH_SERVER_MEMORY = 1130, + /// A potential deadlock condition has been detected. + POSSIBLE_DEADLOCK = 1131, + /// The base address or the file offset specified does not have the proper alignment. + MAPPED_ALIGNMENT = 1132, + /// An attempt to change the system power state was vetoed by another application or driver. + SET_POWER_STATE_VETOED = 1140, + /// The system BIOS failed an attempt to change the system power state. + SET_POWER_STATE_FAILED = 1141, + /// An attempt was made to create more links on a file than the file system supports. + TOO_MANY_LINKS = 1142, + /// The specified program requires a newer version of Windows. + OLD_WIN_VERSION = 1150, + /// The specified program is not a Windows or MS-DOS program. + APP_WRONG_OS = 1151, + /// Cannot start more than one instance of the specified program. + SINGLE_INSTANCE_APP = 1152, + /// The specified program was written for an earlier version of Windows. + RMODE_APP = 1153, + /// One of the library files needed to run this application is damaged. + INVALID_DLL = 1154, + /// No application is associated with the specified file for this operation. + NO_ASSOCIATION = 1155, + /// An error occurred in sending the command to the application. + DDE_FAIL = 1156, + /// One of the library files needed to run this application cannot be found. + DLL_NOT_FOUND = 1157, + /// The current process has used all of its system allowance of handles for Window Manager objects. + NO_MORE_USER_HANDLES = 1158, + /// The message can be used only with synchronous operations. + MESSAGE_SYNC_ONLY = 1159, + /// The indicated source element has no media. + SOURCE_ELEMENT_EMPTY = 1160, + /// The indicated destination element already contains media. + DESTINATION_ELEMENT_FULL = 1161, + /// The indicated element does not exist. + ILLEGAL_ELEMENT_ADDRESS = 1162, + /// The indicated element is part of a magazine that is not present. + MAGAZINE_NOT_PRESENT = 1163, + /// The indicated device requires reinitialization due to hardware errors. + DEVICE_REINITIALIZATION_NEEDED = 1164, + /// The device has indicated that cleaning is required before further operations are attempted. + DEVICE_REQUIRES_CLEANING = 1165, + /// The device has indicated that its door is open. + DEVICE_DOOR_OPEN = 1166, + /// The device is not connected. + DEVICE_NOT_CONNECTED = 1167, + /// Element not found. + NOT_FOUND = 1168, + /// There was no match for the specified key in the index. + NO_MATCH = 1169, + /// The property set specified does not exist on the object. + SET_NOT_FOUND = 1170, + /// The point passed to GetMouseMovePoints is not in the buffer. + POINT_NOT_FOUND = 1171, + /// The tracking (workstation) service is not running. + NO_TRACKING_SERVICE = 1172, + /// The Volume ID could not be found. + NO_VOLUME_ID = 1173, + /// Unable to remove the file to be replaced. + UNABLE_TO_REMOVE_REPLACED = 1175, + /// Unable to move the replacement file to the file to be replaced. + /// The file to be replaced has retained its original name. + UNABLE_TO_MOVE_REPLACEMENT = 1176, + /// Unable to move the replacement file to the file to be replaced. + /// The file to be replaced has been renamed using the backup name. + UNABLE_TO_MOVE_REPLACEMENT_2 = 1177, + /// The volume change journal is being deleted. + JOURNAL_DELETE_IN_PROGRESS = 1178, + /// The volume change journal is not active. + JOURNAL_NOT_ACTIVE = 1179, + /// A file was found, but it may not be the correct file. + POTENTIAL_FILE_FOUND = 1180, + /// The journal entry has been deleted from the journal. + JOURNAL_ENTRY_DELETED = 1181, + /// A system shutdown has already been scheduled. + SHUTDOWN_IS_SCHEDULED = 1190, + /// The system shutdown cannot be initiated because there are other users logged on to the computer. + SHUTDOWN_USERS_LOGGED_ON = 1191, + /// The specified device name is invalid. + BAD_DEVICE = 1200, + /// The device is not currently connected but it is a remembered connection. + CONNECTION_UNAVAIL = 1201, + /// The local device name has a remembered connection to another network resource. + DEVICE_ALREADY_REMEMBERED = 1202, + /// The network path was either typed incorrectly, does not exist, or the network provider is not currently available. + /// Please try retyping the path or contact your network administrator. + NO_NET_OR_BAD_PATH = 1203, + /// The specified network provider name is invalid. + BAD_PROVIDER = 1204, + /// Unable to open the network connection profile. + CANNOT_OPEN_PROFILE = 1205, + /// The network connection profile is corrupted. + BAD_PROFILE = 1206, + /// Cannot enumerate a noncontainer. + NOT_CONTAINER = 1207, + /// An extended error has occurred. + EXTENDED_ERROR = 1208, + /// The format of the specified group name is invalid. + INVALID_GROUPNAME = 1209, + /// The format of the specified computer name is invalid. + INVALID_COMPUTERNAME = 1210, + /// The format of the specified event name is invalid. + INVALID_EVENTNAME = 1211, + /// The format of the specified domain name is invalid. + INVALID_DOMAINNAME = 1212, + /// The format of the specified service name is invalid. + INVALID_SERVICENAME = 1213, + /// The format of the specified network name is invalid. + INVALID_NETNAME = 1214, + /// The format of the specified share name is invalid. + INVALID_SHARENAME = 1215, + /// The format of the specified password is invalid. + INVALID_PASSWORDNAME = 1216, + /// The format of the specified message name is invalid. + INVALID_MESSAGENAME = 1217, + /// The format of the specified message destination is invalid. + INVALID_MESSAGEDEST = 1218, + /// Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. + /// Disconnect all previous connections to the server or shared resource and try again. + SESSION_CREDENTIAL_CONFLICT = 1219, + /// An attempt was made to establish a session to a network server, but there are already too many sessions established to that server. + REMOTE_SESSION_LIMIT_EXCEEDED = 1220, + /// The workgroup or domain name is already in use by another computer on the network. + DUP_DOMAINNAME = 1221, + /// The network is not present or not started. + NO_NETWORK = 1222, + /// The operation was canceled by the user. + CANCELLED = 1223, + /// The requested operation cannot be performed on a file with a user-mapped section open. + USER_MAPPED_FILE = 1224, + /// The remote computer refused the network connection. + CONNECTION_REFUSED = 1225, + /// The network connection was gracefully closed. + GRACEFUL_DISCONNECT = 1226, + /// The network transport endpoint already has an address associated with it. + ADDRESS_ALREADY_ASSOCIATED = 1227, + /// An address has not yet been associated with the network endpoint. + ADDRESS_NOT_ASSOCIATED = 1228, + /// An operation was attempted on a nonexistent network connection. + CONNECTION_INVALID = 1229, + /// An invalid operation was attempted on an active network connection. + CONNECTION_ACTIVE = 1230, + /// The network location cannot be reached. + /// For information about network troubleshooting, see Windows Help. + NETWORK_UNREACHABLE = 1231, + /// The network location cannot be reached. + /// For information about network troubleshooting, see Windows Help. + HOST_UNREACHABLE = 1232, + /// The network location cannot be reached. + /// For information about network troubleshooting, see Windows Help. + PROTOCOL_UNREACHABLE = 1233, + /// No service is operating at the destination network endpoint on the remote system. + PORT_UNREACHABLE = 1234, + /// The request was aborted. + REQUEST_ABORTED = 1235, + /// The network connection was aborted by the local system. + CONNECTION_ABORTED = 1236, + /// The operation could not be completed. A retry should be performed. + RETRY = 1237, + /// A connection to the server could not be made because the limit on the number of concurrent connections for this account has been reached. + CONNECTION_COUNT_LIMIT = 1238, + /// Attempting to log in during an unauthorized time of day for this account. + LOGIN_TIME_RESTRICTION = 1239, + /// The account is not authorized to log in from this station. + LOGIN_WKSTA_RESTRICTION = 1240, + /// The network address could not be used for the operation requested. + INCORRECT_ADDRESS = 1241, + /// The service is already registered. + ALREADY_REGISTERED = 1242, + /// The specified service does not exist. + SERVICE_NOT_FOUND = 1243, + /// The operation being requested was not performed because the user has not been authenticated. + NOT_AUTHENTICATED = 1244, + /// The operation being requested was not performed because the user has not logged on to the network. The specified service does not exist. + NOT_LOGGED_ON = 1245, + /// Continue with work in progress. + CONTINUE = 1246, + /// An attempt was made to perform an initialization operation when initialization has already been completed. + ALREADY_INITIALIZED = 1247, + /// No more local devices. + NO_MORE_DEVICES = 1248, + /// The specified site does not exist. + NO_SUCH_SITE = 1249, + /// A domain controller with the specified name already exists. + DOMAIN_CONTROLLER_EXISTS = 1250, + /// This operation is supported only when you are connected to the server. + ONLY_IF_CONNECTED = 1251, + /// The group policy framework should call the extension even if there are no changes. + OVERRIDE_NOCHANGES = 1252, + /// The specified user does not have a valid profile. + BAD_USER_PROFILE = 1253, + /// This operation is not supported on a computer running Windows Server 2003 for Small Business Server. + NOT_SUPPORTED_ON_SBS = 1254, + /// The server machine is shutting down. + SERVER_SHUTDOWN_IN_PROGRESS = 1255, + /// The remote system is not available. + /// For information about network troubleshooting, see Windows Help. + HOST_DOWN = 1256, + /// The security identifier provided is not from an account domain. + NON_ACCOUNT_SID = 1257, + /// The security identifier provided does not have a domain component. + NON_DOMAIN_SID = 1258, + /// AppHelp dialog canceled thus preventing the application from starting. + APPHELP_BLOCK = 1259, + /// This program is blocked by group policy. + /// For more information, contact your system administrator. + ACCESS_DISABLED_BY_POLICY = 1260, + /// A program attempt to use an invalid register value. + /// Normally caused by an uninitialized register. This error is Itanium specific. + REG_NAT_CONSUMPTION = 1261, + /// The share is currently offline or does not exist. + CSCSHARE_OFFLINE = 1262, + /// The Kerberos protocol encountered an error while validating the KDC certificate during smartcard logon. + /// There is more information in the system event log. + PKINIT_FAILURE = 1263, + /// The Kerberos protocol encountered an error while attempting to utilize the smartcard subsystem. + SMARTCARD_SUBSYSTEM_FAILURE = 1264, + /// The system cannot contact a domain controller to service the authentication request. Please try again later. + DOWNGRADE_DETECTED = 1265, + /// The machine is locked and cannot be shut down without the force option. + MACHINE_LOCKED = 1271, + /// An application-defined callback gave invalid data when called. + CALLBACK_SUPPLIED_INVALID_DATA = 1273, + /// The group policy framework should call the extension in the synchronous foreground policy refresh. + SYNC_FOREGROUND_REFRESH_REQUIRED = 1274, + /// This driver has been blocked from loading. + DRIVER_BLOCKED = 1275, + /// A dynamic link library (DLL) referenced a module that was neither a DLL nor the process's executable image. + INVALID_IMPORT_OF_NON_DLL = 1276, + /// Windows cannot open this program since it has been disabled. + ACCESS_DISABLED_WEBBLADE = 1277, + /// Windows cannot open this program because the license enforcement system has been tampered with or become corrupted. + ACCESS_DISABLED_WEBBLADE_TAMPER = 1278, + /// A transaction recover failed. + RECOVERY_FAILURE = 1279, + /// The current thread has already been converted to a fiber. + ALREADY_FIBER = 1280, + /// The current thread has already been converted from a fiber. + ALREADY_THREAD = 1281, + /// The system detected an overrun of a stack-based buffer in this application. + /// This overrun could potentially allow a malicious user to gain control of this application. + STACK_BUFFER_OVERRUN = 1282, + /// Data present in one of the parameters is more than the function can operate on. + PARAMETER_QUOTA_EXCEEDED = 1283, + /// An attempt to do an operation on a debug object failed because the object is in the process of being deleted. + DEBUGGER_INACTIVE = 1284, + /// An attempt to delay-load a .dll or get a function address in a delay-loaded .dll failed. + DELAY_LOAD_FAILED = 1285, + /// %1 is a 16-bit application. You do not have permissions to execute 16-bit applications. + /// Check your permissions with your system administrator. + VDM_DISALLOWED = 1286, + /// Insufficient information exists to identify the cause of failure. + UNIDENTIFIED_ERROR = 1287, + /// The parameter passed to a C runtime function is incorrect. + INVALID_CRUNTIME_PARAMETER = 1288, + /// The operation occurred beyond the valid data length of the file. + BEYOND_VDL = 1289, + /// The service start failed since one or more services in the same process have an incompatible service SID type setting. + /// A service with restricted service SID type can only coexist in the same process with other services with a restricted SID type. + /// If the service SID type for this service was just configured, the hosting process must be restarted in order to start this service. + /// On Windows Server 2003 and Windows XP, an unrestricted service cannot coexist in the same process with other services. + /// The service with the unrestricted service SID type must be moved to an owned process in order to start this service. + INCOMPATIBLE_SERVICE_SID_TYPE = 1290, + /// The process hosting the driver for this device has been terminated. + DRIVER_PROCESS_TERMINATED = 1291, + /// An operation attempted to exceed an implementation-defined limit. + IMPLEMENTATION_LIMIT = 1292, + /// Either the target process, or the target thread's containing process, is a protected process. + PROCESS_IS_PROTECTED = 1293, + /// The service notification client is lagging too far behind the current state of services in the machine. + SERVICE_NOTIFY_CLIENT_LAGGING = 1294, + /// The requested file operation failed because the storage quota was exceeded. + /// To free up disk space, move files to a different location or delete unnecessary files. + /// For more information, contact your system administrator. + DISK_QUOTA_EXCEEDED = 1295, + /// The requested file operation failed because the storage policy blocks that type of file. + /// For more information, contact your system administrator. + CONTENT_BLOCKED = 1296, + /// A privilege that the service requires to function properly does not exist in the service account configuration. + /// You may use the Services Microsoft Management Console (MMC) snap-in (services.msc) and the Local Security Settings MMC snap-in (secpol.msc) to view the service configuration and the account configuration. + INCOMPATIBLE_SERVICE_PRIVILEGE = 1297, + /// A thread involved in this operation appears to be unresponsive. + APP_HANG = 1298, + /// Indicates a particular Security ID may not be assigned as the label of an object. + INVALID_LABEL = 1299, + /// Not all privileges or groups referenced are assigned to the caller. + NOT_ALL_ASSIGNED = 1300, + /// Some mapping between account names and security IDs was not done. + SOME_NOT_MAPPED = 1301, + /// No system quota limits are specifically set for this account. + NO_QUOTAS_FOR_ACCOUNT = 1302, + /// No encryption key is available. A well-known encryption key was returned. + LOCAL_USER_SESSION_KEY = 1303, + /// The password is too complex to be converted to a LAN Manager password. + /// The LAN Manager password returned is a NULL string. + NULL_LM_PASSWORD = 1304, + /// The revision level is unknown. + UNKNOWN_REVISION = 1305, + /// Indicates two revision levels are incompatible. + REVISION_MISMATCH = 1306, + /// This security ID may not be assigned as the owner of this object. + INVALID_OWNER = 1307, + /// This security ID may not be assigned as the primary group of an object. + INVALID_PRIMARY_GROUP = 1308, + /// An attempt has been made to operate on an impersonation token by a thread that is not currently impersonating a client. + NO_IMPERSONATION_TOKEN = 1309, + /// The group may not be disabled. + CANT_DISABLE_MANDATORY = 1310, + /// There are currently no logon servers available to service the logon request. + NO_LOGON_SERVERS = 1311, + /// A specified logon session does not exist. It may already have been terminated. + NO_SUCH_LOGON_SESSION = 1312, + /// A specified privilege does not exist. + NO_SUCH_PRIVILEGE = 1313, + /// A required privilege is not held by the client. + PRIVILEGE_NOT_HELD = 1314, + /// The name provided is not a properly formed account name. + INVALID_ACCOUNT_NAME = 1315, + /// The specified account already exists. + USER_EXISTS = 1316, + /// The specified account does not exist. + NO_SUCH_USER = 1317, + /// The specified group already exists. + GROUP_EXISTS = 1318, + /// The specified group does not exist. + NO_SUCH_GROUP = 1319, + /// Either the specified user account is already a member of the specified group, or the specified group cannot be deleted because it contains a member. + MEMBER_IN_GROUP = 1320, + /// The specified user account is not a member of the specified group account. + MEMBER_NOT_IN_GROUP = 1321, + /// This operation is disallowed as it could result in an administration account being disabled, deleted or unable to log on. + LAST_ADMIN = 1322, + /// Unable to update the password. The value provided as the current password is incorrect. + WRONG_PASSWORD = 1323, + /// Unable to update the password. The value provided for the new password contains values that are not allowed in passwords. + ILL_FORMED_PASSWORD = 1324, + /// Unable to update the password. The value provided for the new password does not meet the length, complexity, or history requirements of the domain. + PASSWORD_RESTRICTION = 1325, + /// The user name or password is incorrect. + LOGON_FAILURE = 1326, + /// Account restrictions are preventing this user from signing in. + /// For example: blank passwords aren't allowed, sign-in times are limited, or a policy restriction has been enforced. + ACCOUNT_RESTRICTION = 1327, + /// Your account has time restrictions that keep you from signing in right now. + INVALID_LOGON_HOURS = 1328, + /// This user isn't allowed to sign in to this computer. + INVALID_WORKSTATION = 1329, + /// The password for this account has expired. + PASSWORD_EXPIRED = 1330, + /// This user can't sign in because this account is currently disabled. + ACCOUNT_DISABLED = 1331, + /// No mapping between account names and security IDs was done. + NONE_MAPPED = 1332, + /// Too many local user identifiers (LUIDs) were requested at one time. + TOO_MANY_LUIDS_REQUESTED = 1333, + /// No more local user identifiers (LUIDs) are available. + LUIDS_EXHAUSTED = 1334, + /// The subauthority part of a security ID is invalid for this particular use. + INVALID_SUB_AUTHORITY = 1335, + /// The access control list (ACL) structure is invalid. + INVALID_ACL = 1336, + /// The security ID structure is invalid. + INVALID_SID = 1337, + /// The security descriptor structure is invalid. + INVALID_SECURITY_DESCR = 1338, + /// The inherited access control list (ACL) or access control entry (ACE) could not be built. + BAD_INHERITANCE_ACL = 1340, + /// The server is currently disabled. + SERVER_DISABLED = 1341, + /// The server is currently enabled. + SERVER_NOT_DISABLED = 1342, + /// The value provided was an invalid value for an identifier authority. + INVALID_ID_AUTHORITY = 1343, + /// No more memory is available for security information updates. + ALLOTTED_SPACE_EXCEEDED = 1344, + /// The specified attributes are invalid, or incompatible with the attributes for the group as a whole. + INVALID_GROUP_ATTRIBUTES = 1345, + /// Either a required impersonation level was not provided, or the provided impersonation level is invalid. + BAD_IMPERSONATION_LEVEL = 1346, + /// Cannot open an anonymous level security token. + CANT_OPEN_ANONYMOUS = 1347, + /// The validation information class requested was invalid. + BAD_VALIDATION_CLASS = 1348, + /// The type of the token is inappropriate for its attempted use. + BAD_TOKEN_TYPE = 1349, + /// Unable to perform a security operation on an object that has no associated security. + NO_SECURITY_ON_OBJECT = 1350, + /// Configuration information could not be read from the domain controller, either because the machine is unavailable, or access has been denied. + CANT_ACCESS_DOMAIN_INFO = 1351, + /// The security account manager (SAM) or local security authority (LSA) server was in the wrong state to perform the security operation. + INVALID_SERVER_STATE = 1352, + /// The domain was in the wrong state to perform the security operation. + INVALID_DOMAIN_STATE = 1353, + /// This operation is only allowed for the Primary Domain Controller of the domain. + INVALID_DOMAIN_ROLE = 1354, + /// The specified domain either does not exist or could not be contacted. + NO_SUCH_DOMAIN = 1355, + /// The specified domain already exists. + DOMAIN_EXISTS = 1356, + /// An attempt was made to exceed the limit on the number of domains per server. + DOMAIN_LIMIT_EXCEEDED = 1357, + /// Unable to complete the requested operation because of either a catastrophic media failure or a data structure corruption on the disk. + INTERNAL_DB_CORRUPTION = 1358, + /// An internal error occurred. + INTERNAL_ERROR = 1359, + /// Generic access types were contained in an access mask which should already be mapped to nongeneric types. + GENERIC_NOT_MAPPED = 1360, + /// A security descriptor is not in the right format (absolute or self-relative). + BAD_DESCRIPTOR_FORMAT = 1361, + /// The requested action is restricted for use by logon processes only. + /// The calling process has not registered as a logon process. + NOT_LOGON_PROCESS = 1362, + /// Cannot start a new logon session with an ID that is already in use. + LOGON_SESSION_EXISTS = 1363, + /// A specified authentication package is unknown. + NO_SUCH_PACKAGE = 1364, + /// The logon session is not in a state that is consistent with the requested operation. + BAD_LOGON_SESSION_STATE = 1365, + /// The logon session ID is already in use. + LOGON_SESSION_COLLISION = 1366, + /// A logon request contained an invalid logon type value. + INVALID_LOGON_TYPE = 1367, + /// Unable to impersonate using a named pipe until data has been read from that pipe. + CANNOT_IMPERSONATE = 1368, + /// The transaction state of a registry subtree is incompatible with the requested operation. + RXACT_INVALID_STATE = 1369, + /// An internal security database corruption has been encountered. + RXACT_COMMIT_FAILURE = 1370, + /// Cannot perform this operation on built-in accounts. + SPECIAL_ACCOUNT = 1371, + /// Cannot perform this operation on this built-in special group. + SPECIAL_GROUP = 1372, + /// Cannot perform this operation on this built-in special user. + SPECIAL_USER = 1373, + /// The user cannot be removed from a group because the group is currently the user's primary group. + MEMBERS_PRIMARY_GROUP = 1374, + /// The token is already in use as a primary token. + TOKEN_ALREADY_IN_USE = 1375, + /// The specified local group does not exist. + NO_SUCH_ALIAS = 1376, + /// The specified account name is not a member of the group. + MEMBER_NOT_IN_ALIAS = 1377, + /// The specified account name is already a member of the group. + MEMBER_IN_ALIAS = 1378, + /// The specified local group already exists. + ALIAS_EXISTS = 1379, + /// Logon failure: the user has not been granted the requested logon type at this computer. + LOGON_NOT_GRANTED = 1380, + /// The maximum number of secrets that may be stored in a single system has been exceeded. + TOO_MANY_SECRETS = 1381, + /// The length of a secret exceeds the maximum length allowed. + SECRET_TOO_LONG = 1382, + /// The local security authority database contains an internal inconsistency. + INTERNAL_DB_ERROR = 1383, + /// During a logon attempt, the user's security context accumulated too many security IDs. + TOO_MANY_CONTEXT_IDS = 1384, + /// Logon failure: the user has not been granted the requested logon type at this computer. + LOGON_TYPE_NOT_GRANTED = 1385, + /// A cross-encrypted password is necessary to change a user password. + NT_CROSS_ENCRYPTION_REQUIRED = 1386, + /// A member could not be added to or removed from the local group because the member does not exist. + NO_SUCH_MEMBER = 1387, + /// A new member could not be added to a local group because the member has the wrong account type. + INVALID_MEMBER = 1388, + /// Too many security IDs have been specified. + TOO_MANY_SIDS = 1389, + /// A cross-encrypted password is necessary to change this user password. + LM_CROSS_ENCRYPTION_REQUIRED = 1390, + /// Indicates an ACL contains no inheritable components. + NO_INHERITANCE = 1391, + /// The file or directory is corrupted and unreadable. + FILE_CORRUPT = 1392, + /// The disk structure is corrupted and unreadable. + DISK_CORRUPT = 1393, + /// There is no user session key for the specified logon session. + NO_USER_SESSION_KEY = 1394, + /// The service being accessed is licensed for a particular number of connections. + /// No more connections can be made to the service at this time because there are already as many connections as the service can accept. + LICENSE_QUOTA_EXCEEDED = 1395, + /// The target account name is incorrect. + WRONG_TARGET_NAME = 1396, + /// Mutual Authentication failed. The server's password is out of date at the domain controller. + MUTUAL_AUTH_FAILED = 1397, + /// There is a time and/or date difference between the client and server. + TIME_SKEW = 1398, + /// This operation cannot be performed on the current domain. + CURRENT_DOMAIN_NOT_ALLOWED = 1399, + /// Invalid window handle. + INVALID_WINDOW_HANDLE = 1400, + /// Invalid menu handle. + INVALID_MENU_HANDLE = 1401, + /// Invalid cursor handle. + INVALID_CURSOR_HANDLE = 1402, + /// Invalid accelerator table handle. + INVALID_ACCEL_HANDLE = 1403, + /// Invalid hook handle. + INVALID_HOOK_HANDLE = 1404, + /// Invalid handle to a multiple-window position structure. + INVALID_DWP_HANDLE = 1405, + /// Cannot create a top-level child window. + TLW_WITH_WSCHILD = 1406, + /// Cannot find window class. + CANNOT_FIND_WND_CLASS = 1407, + /// Invalid window; it belongs to other thread. + WINDOW_OF_OTHER_THREAD = 1408, + /// Hot key is already registered. + HOTKEY_ALREADY_REGISTERED = 1409, + /// Class already exists. + CLASS_ALREADY_EXISTS = 1410, + /// Class does not exist. + CLASS_DOES_NOT_EXIST = 1411, + /// Class still has openwin32. + CLASS_HAS_WINDOWS = 1412, + /// Invalid index. + INVALID_INDEX = 1413, + /// Invalid icon handle. + INVALID_ICON_HANDLE = 1414, + /// Using private DIALOG window words. + PRIVATE_DIALOG_INDEX = 1415, + /// The list box identifier was not found. + LISTBOX_ID_NOT_FOUND = 1416, + /// No wildcards were found. + NO_WILDCARD_CHARACTERS = 1417, + /// Thread does not have a clipboard open. + CLIPBOARD_NOT_OPEN = 1418, + /// Hot key is not registered. + HOTKEY_NOT_REGISTERED = 1419, + /// The window is not a valid dialog window. + WINDOW_NOT_DIALOG = 1420, + /// Control ID not found. + CONTROL_ID_NOT_FOUND = 1421, + /// Invalid message for a combo box because it does not have an edit control. + INVALID_COMBOBOX_MESSAGE = 1422, + /// The window is not a combo box. + WINDOW_NOT_COMBOBOX = 1423, + /// Height must be less than 256. + INVALID_EDIT_HEIGHT = 1424, + /// Invalid device context (DC) handle. + DC_NOT_FOUND = 1425, + /// Invalid hook procedure type. + INVALID_HOOK_FILTER = 1426, + /// Invalid hook procedure. + INVALID_FILTER_PROC = 1427, + /// Cannot set nonlocal hook without a module handle. + HOOK_NEEDS_HMOD = 1428, + /// This hook procedure can only be set globally. + GLOBAL_ONLY_HOOK = 1429, + /// The journal hook procedure is already installed. + JOURNAL_HOOK_SET = 1430, + /// The hook procedure is not installed. + HOOK_NOT_INSTALLED = 1431, + /// Invalid message for single-selection list box. + INVALID_LB_MESSAGE = 1432, + /// LB_SETCOUNT sent to non-lazy list box. + SETCOUNT_ON_BAD_LB = 1433, + /// This list box does not support tab stops. + LB_WITHOUT_TABSTOPS = 1434, + /// Cannot destroy object created by another thread. + DESTROY_OBJECT_OF_OTHER_THREAD = 1435, + + /// The data present in the reparse point buffer is invalid. + INVALID_REPARSE_DATA = 3492, + + /// Childwin32.cannot have menus. + CHILD_WINDOW_MENU = 1436, + /// The window does not have a system menu. + NO_SYSTEM_MENU = 1437, + /// Invalid message box style. + INVALID_MSGBOX_STYLE = 1438, + /// Invalid system-wide (SPI_*) parameter. + INVALID_SPI_VALUE = 1439, + /// Screen already locked. + SCREEN_ALREADY_LOCKED = 1440, + /// All handles towin32.in a multiple-window position structure must have the same parent. + HWNDS_HAVE_DIFF_PARENT = 1441, + /// The window is not a child window. + NOT_CHILD_WINDOW = 1442, + /// Invalid GW_* command. + INVALID_GW_COMMAND = 1443, + /// Invalid thread identifier. + INVALID_THREAD_ID = 1444, + /// Cannot process a message from a window that is not a multiple document interface (MDI) window. + NON_MDICHILD_WINDOW = 1445, + /// Popup menu already active. + POPUP_ALREADY_ACTIVE = 1446, + /// The window does not have scroll bars. + NO_SCROLLBARS = 1447, + /// Scroll bar range cannot be greater than MAXLONG. + INVALID_SCROLLBAR_RANGE = 1448, + /// Cannot show or remove the window in the way specified. + INVALID_SHOWWIN_COMMAND = 1449, + /// Insufficient system resources exist to complete the requested service. + NO_SYSTEM_RESOURCES = 1450, + /// Insufficient system resources exist to complete the requested service. + NONPAGED_SYSTEM_RESOURCES = 1451, + /// Insufficient system resources exist to complete the requested service. + PAGED_SYSTEM_RESOURCES = 1452, + /// Insufficient quota to complete the requested service. + WORKING_SET_QUOTA = 1453, + /// Insufficient quota to complete the requested service. + PAGEFILE_QUOTA = 1454, + /// The paging file is too small for this operation to complete. + COMMITMENT_LIMIT = 1455, + /// A menu item was not found. + MENU_ITEM_NOT_FOUND = 1456, + /// Invalid keyboard layout handle. + INVALID_KEYBOARD_HANDLE = 1457, + /// Hook type not allowed. + HOOK_TYPE_NOT_ALLOWED = 1458, + /// This operation requires an interactive window station. + REQUIRES_INTERACTIVE_WINDOWSTATION = 1459, + /// This operation returned because the timeout period expired. + TIMEOUT = 1460, + /// Invalid monitor handle. + INVALID_MONITOR_HANDLE = 1461, + /// Incorrect size argument. + INCORRECT_SIZE = 1462, + /// The symbolic link cannot be followed because its type is disabled. + SYMLINK_CLASS_DISABLED = 1463, + /// This application does not support the current operation on symbolic links. + SYMLINK_NOT_SUPPORTED = 1464, + /// Windows was unable to parse the requested XML data. + XML_PARSE_ERROR = 1465, + /// An error was encountered while processing an XML digital signature. + XMLDSIG_ERROR = 1466, + /// This application must be restarted. + RESTART_APPLICATION = 1467, + /// The caller made the connection request in the wrong routing compartment. + WRONG_COMPARTMENT = 1468, + /// There was an AuthIP failure when attempting to connect to the remote host. + AUTHIP_FAILURE = 1469, + /// Insufficient NVRAM resources exist to complete the requested service. A reboot might be required. + NO_NVRAM_RESOURCES = 1470, + /// Unable to finish the requested operation because the specified process is not a GUI process. + NOT_GUI_PROCESS = 1471, + /// The event log file is corrupted. + EVENTLOG_FILE_CORRUPT = 1500, + /// No event log file could be opened, so the event logging service did not start. + EVENTLOG_CANT_START = 1501, + /// The event log file is full. + LOG_FILE_FULL = 1502, + /// The event log file has changed between read operations. + EVENTLOG_FILE_CHANGED = 1503, + /// The specified task name is invalid. + INVALID_TASK_NAME = 1550, + /// The specified task index is invalid. + INVALID_TASK_INDEX = 1551, + /// The specified thread is already joining a task. + THREAD_ALREADY_IN_TASK = 1552, + /// The Windows Installer Service could not be accessed. + /// This can occur if the Windows Installer is not correctly installed. Contact your support personnel for assistance. + INSTALL_SERVICE_FAILURE = 1601, + /// User cancelled installation. + INSTALL_USEREXIT = 1602, + /// Fatal error during installation. + INSTALL_FAILURE = 1603, + /// Installation suspended, incomplete. + INSTALL_SUSPEND = 1604, + /// This action is only valid for products that are currently installed. + UNKNOWN_PRODUCT = 1605, + /// Feature ID not registered. + UNKNOWN_FEATURE = 1606, + /// Component ID not registered. + UNKNOWN_COMPONENT = 1607, + /// Unknown property. + UNKNOWN_PROPERTY = 1608, + /// Handle is in an invalid state. + INVALID_HANDLE_STATE = 1609, + /// The configuration data for this product is corrupt. Contact your support personnel. + BAD_CONFIGURATION = 1610, + /// Component qualifier not present. + INDEX_ABSENT = 1611, + /// The installation source for this product is not available. + /// Verify that the source exists and that you can access it. + INSTALL_SOURCE_ABSENT = 1612, + /// This installation package cannot be installed by the Windows Installer service. + /// You must install a Windows service pack that contains a newer version of the Windows Installer service. + INSTALL_PACKAGE_VERSION = 1613, + /// Product is uninstalled. + PRODUCT_UNINSTALLED = 1614, + /// SQL query syntax invalid or unsupported. + BAD_QUERY_SYNTAX = 1615, + /// Record field does not exist. + INVALID_FIELD = 1616, + /// The device has been removed. + DEVICE_REMOVED = 1617, + /// Another installation is already in progress. + /// Complete that installation before proceeding with this install. + INSTALL_ALREADY_RUNNING = 1618, + /// This installation package could not be opened. + /// Verify that the package exists and that you can access it, or contact the application vendor to verify that this is a valid Windows Installer package. + INSTALL_PACKAGE_OPEN_FAILED = 1619, + /// This installation package could not be opened. + /// Contact the application vendor to verify that this is a valid Windows Installer package. + INSTALL_PACKAGE_INVALID = 1620, + /// There was an error starting the Windows Installer service user interface. Contact your support personnel. + INSTALL_UI_FAILURE = 1621, + /// Error opening installation log file. + /// Verify that the specified log file location exists and that you can write to it. + INSTALL_LOG_FAILURE = 1622, + /// The language of this installation package is not supported by your system. + INSTALL_LANGUAGE_UNSUPPORTED = 1623, + /// Error applying transforms. Verify that the specified transform paths are valid. + INSTALL_TRANSFORM_FAILURE = 1624, + /// This installation is forbidden by system policy. Contact your system administrator. + INSTALL_PACKAGE_REJECTED = 1625, + /// Function could not be executed. + FUNCTION_NOT_CALLED = 1626, + /// Function failed during execution. + FUNCTION_FAILED = 1627, + /// Invalid or unknown table specified. + INVALID_TABLE = 1628, + /// Data supplied is of wrong type. + DATATYPE_MISMATCH = 1629, + /// Data of this type is not supported. + UNSUPPORTED_TYPE = 1630, + /// The Windows Installer service failed to start. Contact your support personnel. + CREATE_FAILED = 1631, + /// The Temp folder is on a drive that is full or is inaccessible. + /// Free up space on the drive or verify that you have write permission on the Temp folder. + INSTALL_TEMP_UNWRITABLE = 1632, + /// This installation package is not supported by this processor type. Contact your product vendor. + INSTALL_PLATFORM_UNSUPPORTED = 1633, + /// Component not used on this computer. + INSTALL_NOTUSED = 1634, + /// This update package could not be opened. + /// Verify that the update package exists and that you can access it, or contact the application vendor to verify that this is a valid Windows Installer update package. + PATCH_PACKAGE_OPEN_FAILED = 1635, + /// This update package could not be opened. + /// Contact the application vendor to verify that this is a valid Windows Installer update package. + PATCH_PACKAGE_INVALID = 1636, + /// This update package cannot be processed by the Windows Installer service. + /// You must install a Windows service pack that contains a newer version of the Windows Installer service. + PATCH_PACKAGE_UNSUPPORTED = 1637, + /// Another version of this product is already installed. Installation of this version cannot continue. + /// To configure or remove the existing version of this product, use Add/Remove Programs on the Control Panel. + PRODUCT_VERSION = 1638, + /// Invalid command line argument. Consult the Windows Installer SDK for detailed command line help. + INVALID_COMMAND_LINE = 1639, + /// Only administrators have permission to add, remove, or configure server software during a Terminal services remote session. + /// If you want to install or configure software on the server, contact your network administrator. + INSTALL_REMOTE_DISALLOWED = 1640, + /// The requested operation completed successfully. + /// The system will be restarted so the changes can take effect. + SUCCESS_REBOOT_INITIATED = 1641, + /// The upgrade cannot be installed by the Windows Installer service because the program to be upgraded may be missing, or the upgrade may update a different version of the program. + /// Verify that the program to be upgraded exists on your computer and that you have the correct upgrade. + PATCH_TARGET_NOT_FOUND = 1642, + /// The update package is not permitted by software restriction policy. + PATCH_PACKAGE_REJECTED = 1643, + /// One or more customizations are not permitted by software restriction policy. + INSTALL_TRANSFORM_REJECTED = 1644, + /// The Windows Installer does not permit installation from a Remote Desktop Connection. + INSTALL_REMOTE_PROHIBITED = 1645, + /// Uninstallation of the update package is not supported. + PATCH_REMOVAL_UNSUPPORTED = 1646, + /// The update is not applied to this product. + UNKNOWN_PATCH = 1647, + /// No valid sequence could be found for the set of updates. + PATCH_NO_SEQUENCE = 1648, + /// Update removal was disallowed by policy. + PATCH_REMOVAL_DISALLOWED = 1649, + /// The XML update data is invalid. + INVALID_PATCH_XML = 1650, + /// Windows Installer does not permit updating of managed advertised products. + /// At least one feature of the product must be installed before applying the update. + PATCH_MANAGED_ADVERTISED_PRODUCT = 1651, + /// The Windows Installer service is not accessible in Safe Mode. + /// Please try again when your computer is not in Safe Mode or you can use System Restore to return your machine to a previous good state. + INSTALL_SERVICE_SAFEBOOT = 1652, + /// A fail fast exception occurred. + /// Exception handlers will not be invoked and the process will be terminated immediately. + FAIL_FAST_EXCEPTION = 1653, + /// The app that you are trying to run is not supported on this version of Windows. + INSTALL_REJECTED = 1654, + /// The string binding is invalid. + RPC_S_INVALID_STRING_BINDING = 1700, + /// The binding handle is not the correct type. + RPC_S_WRONG_KIND_OF_BINDING = 1701, + /// The binding handle is invalid. + RPC_S_INVALID_BINDING = 1702, + /// The RPC protocol sequence is not supported. + RPC_S_PROTSEQ_NOT_SUPPORTED = 1703, + /// The RPC protocol sequence is invalid. + RPC_S_INVALID_RPC_PROTSEQ = 1704, + /// The string universal unique identifier (UUID) is invalid. + RPC_S_INVALID_STRING_UUID = 1705, + /// The endpoint format is invalid. + RPC_S_INVALID_ENDPOINT_FORMAT = 1706, + /// The network address is invalid. + RPC_S_INVALID_NET_ADDR = 1707, + /// No endpoint was found. + RPC_S_NO_ENDPOINT_FOUND = 1708, + /// The timeout value is invalid. + RPC_S_INVALID_TIMEOUT = 1709, + /// The object universal unique identifier (UUID) was not found. + RPC_S_OBJECT_NOT_FOUND = 1710, + /// The object universal unique identifier (UUID) has already been registered. + RPC_S_ALREADY_REGISTERED = 1711, + /// The type universal unique identifier (UUID) has already been registered. + RPC_S_TYPE_ALREADY_REGISTERED = 1712, + /// The RPC server is already listening. + RPC_S_ALREADY_LISTENING = 1713, + /// No protocol sequences have been registered. + RPC_S_NO_PROTSEQS_REGISTERED = 1714, + /// The RPC server is not listening. + RPC_S_NOT_LISTENING = 1715, + /// The manager type is unknown. + RPC_S_UNKNOWN_MGR_TYPE = 1716, + /// The interface is unknown. + RPC_S_UNKNOWN_IF = 1717, + /// There are no bindings. + RPC_S_NO_BINDINGS = 1718, + /// There are no protocol sequences. + RPC_S_NO_PROTSEQS = 1719, + /// The endpoint cannot be created. + RPC_S_CANT_CREATE_ENDPOINT = 1720, + /// Not enough resources are available to complete this operation. + RPC_S_OUT_OF_RESOURCES = 1721, + /// The RPC server is unavailable. + RPC_S_SERVER_UNAVAILABLE = 1722, + /// The RPC server is too busy to complete this operation. + RPC_S_SERVER_TOO_BUSY = 1723, + /// The network options are invalid. + RPC_S_INVALID_NETWORK_OPTIONS = 1724, + /// There are no remote procedure calls active on this thread. + RPC_S_NO_CALL_ACTIVE = 1725, + /// The remote procedure call failed. + RPC_S_CALL_FAILED = 1726, + /// The remote procedure call failed and did not execute. + RPC_S_CALL_FAILED_DNE = 1727, + /// A remote procedure call (RPC) protocol error occurred. + RPC_S_PROTOCOL_ERROR = 1728, + /// Access to the HTTP proxy is denied. + RPC_S_PROXY_ACCESS_DENIED = 1729, + /// The transfer syntax is not supported by the RPC server. + RPC_S_UNSUPPORTED_TRANS_SYN = 1730, + /// The universal unique identifier (UUID) type is not supported. + RPC_S_UNSUPPORTED_TYPE = 1732, + /// The tag is invalid. + RPC_S_INVALID_TAG = 1733, + /// The array bounds are invalid. + RPC_S_INVALID_BOUND = 1734, + /// The binding does not contain an entry name. + RPC_S_NO_ENTRY_NAME = 1735, + /// The name syntax is invalid. + RPC_S_INVALID_NAME_SYNTAX = 1736, + /// The name syntax is not supported. + RPC_S_UNSUPPORTED_NAME_SYNTAX = 1737, + /// No network address is available to use to construct a universal unique identifier (UUID). + RPC_S_UUID_NO_ADDRESS = 1739, + /// The endpoint is a duplicate. + RPC_S_DUPLICATE_ENDPOINT = 1740, + /// The authentication type is unknown. + RPC_S_UNKNOWN_AUTHN_TYPE = 1741, + /// The maximum number of calls is too small. + RPC_S_MAX_CALLS_TOO_SMALL = 1742, + /// The string is too long. + RPC_S_STRING_TOO_LONG = 1743, + /// The RPC protocol sequence was not found. + RPC_S_PROTSEQ_NOT_FOUND = 1744, + /// The procedure number is out of range. + RPC_S_PROCNUM_OUT_OF_RANGE = 1745, + /// The binding does not contain any authentication information. + RPC_S_BINDING_HAS_NO_AUTH = 1746, + /// The authentication service is unknown. + RPC_S_UNKNOWN_AUTHN_SERVICE = 1747, + /// The authentication level is unknown. + RPC_S_UNKNOWN_AUTHN_LEVEL = 1748, + /// The security context is invalid. + RPC_S_INVALID_AUTH_IDENTITY = 1749, + /// The authorization service is unknown. + RPC_S_UNKNOWN_AUTHZ_SERVICE = 1750, + /// The entry is invalid. + EPT_S_INVALID_ENTRY = 1751, + /// The server endpoint cannot perform the operation. + EPT_S_CANT_PERFORM_OP = 1752, + /// There are no more endpoints available from the endpoint mapper. + EPT_S_NOT_REGISTERED = 1753, + /// No interfaces have been exported. + RPC_S_NOTHING_TO_EXPORT = 1754, + /// The entry name is incomplete. + RPC_S_INCOMPLETE_NAME = 1755, + /// The version option is invalid. + RPC_S_INVALID_VERS_OPTION = 1756, + /// There are no more members. + RPC_S_NO_MORE_MEMBERS = 1757, + /// There is nothing to unexport. + RPC_S_NOT_ALL_OBJS_UNEXPORTED = 1758, + /// The interface was not found. + RPC_S_INTERFACE_NOT_FOUND = 1759, + /// The entry already exists. + RPC_S_ENTRY_ALREADY_EXISTS = 1760, + /// The entry is not found. + RPC_S_ENTRY_NOT_FOUND = 1761, + /// The name service is unavailable. + RPC_S_NAME_SERVICE_UNAVAILABLE = 1762, + /// The network address family is invalid. + RPC_S_INVALID_NAF_ID = 1763, + /// The requested operation is not supported. + RPC_S_CANNOT_SUPPORT = 1764, + /// No security context is available to allow impersonation. + RPC_S_NO_CONTEXT_AVAILABLE = 1765, + /// An internal error occurred in a remote procedure call (RPC). + RPC_S_INTERNAL_ERROR = 1766, + /// The RPC server attempted an integer division by zero. + RPC_S_ZERO_DIVIDE = 1767, + /// An addressing error occurred in the RPC server. + RPC_S_ADDRESS_ERROR = 1768, + /// A floating-point operation at the RPC server caused a division by zero. + RPC_S_FP_DIV_ZERO = 1769, + /// A floating-point underflow occurred at the RPC server. + RPC_S_FP_UNDERFLOW = 1770, + /// A floating-point overflow occurred at the RPC server. + RPC_S_FP_OVERFLOW = 1771, + /// The list of RPC servers available for the binding of auto handles has been exhausted. + RPC_X_NO_MORE_ENTRIES = 1772, + /// Unable to open the character translation table file. + RPC_X_SS_CHAR_TRANS_OPEN_FAIL = 1773, + /// The file containing the character translation table has fewer than 512 bytes. + RPC_X_SS_CHAR_TRANS_SHORT_FILE = 1774, + /// A null context handle was passed from the client to the host during a remote procedure call. + RPC_X_SS_IN_NULL_CONTEXT = 1775, + /// The context handle changed during a remote procedure call. + RPC_X_SS_CONTEXT_DAMAGED = 1777, + /// The binding handles passed to a remote procedure call do not match. + RPC_X_SS_HANDLES_MISMATCH = 1778, + /// The stub is unable to get the remote procedure call handle. + RPC_X_SS_CANNOT_GET_CALL_HANDLE = 1779, + /// A null reference pointer was passed to the stub. + RPC_X_NULL_REF_POINTER = 1780, + /// The enumeration value is out of range. + RPC_X_ENUM_VALUE_OUT_OF_RANGE = 1781, + /// The byte count is too small. + RPC_X_BYTE_COUNT_TOO_SMALL = 1782, + /// The stub received bad data. + RPC_X_BAD_STUB_DATA = 1783, + /// The supplied user buffer is not valid for the requested operation. + INVALID_USER_BUFFER = 1784, + /// The disk media is not recognized. It may not be formatted. + UNRECOGNIZED_MEDIA = 1785, + /// The workstation does not have a trust secret. + NO_TRUST_LSA_SECRET = 1786, + /// The security database on the server does not have a computer account for this workstation trust relationship. + NO_TRUST_SAM_ACCOUNT = 1787, + /// The trust relationship between the primary domain and the trusted domain failed. + TRUSTED_DOMAIN_FAILURE = 1788, + /// The trust relationship between this workstation and the primary domain failed. + TRUSTED_RELATIONSHIP_FAILURE = 1789, + /// The network logon failed. + TRUST_FAILURE = 1790, + /// A remote procedure call is already in progress for this thread. + RPC_S_CALL_IN_PROGRESS = 1791, + /// An attempt was made to logon, but the network logon service was not started. + NETLOGON_NOT_STARTED = 1792, + /// The user's account has expired. + ACCOUNT_EXPIRED = 1793, + /// The redirector is in use and cannot be unloaded. + REDIRECTOR_HAS_OPEN_HANDLES = 1794, + /// The specified printer driver is already installed. + PRINTER_DRIVER_ALREADY_INSTALLED = 1795, + /// The specified port is unknown. + UNKNOWN_PORT = 1796, + /// The printer driver is unknown. + UNKNOWN_PRINTER_DRIVER = 1797, + /// The print processor is unknown. + UNKNOWN_PRINTPROCESSOR = 1798, + /// The specified separator file is invalid. + INVALID_SEPARATOR_FILE = 1799, + /// The specified priority is invalid. + INVALID_PRIORITY = 1800, + /// The printer name is invalid. + INVALID_PRINTER_NAME = 1801, + /// The printer already exists. + PRINTER_ALREADY_EXISTS = 1802, + /// The printer command is invalid. + INVALID_PRINTER_COMMAND = 1803, + /// The specified datatype is invalid. + INVALID_DATATYPE = 1804, + /// The environment specified is invalid. + INVALID_ENVIRONMENT = 1805, + /// There are no more bindings. + RPC_S_NO_MORE_BINDINGS = 1806, + /// The account used is an interdomain trust account. + /// Use your global user account or local user account to access this server. + NOLOGON_INTERDOMAIN_TRUST_ACCOUNT = 1807, + /// The account used is a computer account. + /// Use your global user account or local user account to access this server. + NOLOGON_WORKSTATION_TRUST_ACCOUNT = 1808, + /// The account used is a server trust account. + /// Use your global user account or local user account to access this server. + NOLOGON_SERVER_TRUST_ACCOUNT = 1809, + /// The name or security ID (SID) of the domain specified is inconsistent with the trust information for that domain. + DOMAIN_TRUST_INCONSISTENT = 1810, + /// The server is in use and cannot be unloaded. + SERVER_HAS_OPEN_HANDLES = 1811, + /// The specified image file did not contain a resource section. + RESOURCE_DATA_NOT_FOUND = 1812, + /// The specified resource type cannot be found in the image file. + RESOURCE_TYPE_NOT_FOUND = 1813, + /// The specified resource name cannot be found in the image file. + RESOURCE_NAME_NOT_FOUND = 1814, + /// The specified resource language ID cannot be found in the image file. + RESOURCE_LANG_NOT_FOUND = 1815, + /// Not enough quota is available to process this command. + NOT_ENOUGH_QUOTA = 1816, + /// No interfaces have been registered. + RPC_S_NO_INTERFACES = 1817, + /// The remote procedure call was cancelled. + RPC_S_CALL_CANCELLED = 1818, + /// The binding handle does not contain all required information. + RPC_S_BINDING_INCOMPLETE = 1819, + /// A communications failure occurred during a remote procedure call. + RPC_S_COMM_FAILURE = 1820, + /// The requested authentication level is not supported. + RPC_S_UNSUPPORTED_AUTHN_LEVEL = 1821, + /// No principal name registered. + RPC_S_NO_PRINC_NAME = 1822, + /// The error specified is not a valid Windows RPC error code. + RPC_S_NOT_RPC_ERROR = 1823, + /// A UUID that is valid only on this computer has been allocated. + RPC_S_UUID_LOCAL_ONLY = 1824, + /// A security package specific error occurred. + RPC_S_SEC_PKG_ERROR = 1825, + /// Thread is not canceled. + RPC_S_NOT_CANCELLED = 1826, + /// Invalid operation on the encoding/decoding handle. + RPC_X_INVALID_ES_ACTION = 1827, + /// Incompatible version of the serializing package. + RPC_X_WRONG_ES_VERSION = 1828, + /// Incompatible version of the RPC stub. + RPC_X_WRONG_STUB_VERSION = 1829, + /// The RPC pipe object is invalid or corrupted. + RPC_X_INVALID_PIPE_OBJECT = 1830, + /// An invalid operation was attempted on an RPC pipe object. + RPC_X_WRONG_PIPE_ORDER = 1831, + /// Unsupported RPC pipe version. + RPC_X_WRONG_PIPE_VERSION = 1832, + /// HTTP proxy server rejected the connection because the cookie authentication failed. + RPC_S_COOKIE_AUTH_FAILED = 1833, + /// The group member was not found. + RPC_S_GROUP_MEMBER_NOT_FOUND = 1898, + /// The endpoint mapper database entry could not be created. + EPT_S_CANT_CREATE = 1899, + /// The object universal unique identifier (UUID) is the nil UUID. + RPC_S_INVALID_OBJECT = 1900, + /// The specified time is invalid. + INVALID_TIME = 1901, + /// The specified form name is invalid. + INVALID_FORM_NAME = 1902, + /// The specified form size is invalid. + INVALID_FORM_SIZE = 1903, + /// The specified printer handle is already being waited on. + ALREADY_WAITING = 1904, + /// The specified printer has been deleted. + PRINTER_DELETED = 1905, + /// The state of the printer is invalid. + INVALID_PRINTER_STATE = 1906, + /// The user's password must be changed before signing in. + PASSWORD_MUST_CHANGE = 1907, + /// Could not find the domain controller for this domain. + DOMAIN_CONTROLLER_NOT_FOUND = 1908, + /// The referenced account is currently locked out and may not be logged on to. + ACCOUNT_LOCKED_OUT = 1909, + /// The object exporter specified was not found. + OR_INVALID_OXID = 1910, + /// The object specified was not found. + OR_INVALID_OID = 1911, + /// The object resolver set specified was not found. + OR_INVALID_SET = 1912, + /// Some data remains to be sent in the request buffer. + RPC_S_SEND_INCOMPLETE = 1913, + /// Invalid asynchronous remote procedure call handle. + RPC_S_INVALID_ASYNC_HANDLE = 1914, + /// Invalid asynchronous RPC call handle for this operation. + RPC_S_INVALID_ASYNC_CALL = 1915, + /// The RPC pipe object has already been closed. + RPC_X_PIPE_CLOSED = 1916, + /// The RPC call completed before all pipes were processed. + RPC_X_PIPE_DISCIPLINE_ERROR = 1917, + /// No more data is available from the RPC pipe. + RPC_X_PIPE_EMPTY = 1918, + /// No site name is available for this machine. + NO_SITENAME = 1919, + /// The file cannot be accessed by the system. + CANT_ACCESS_FILE = 1920, + /// The name of the file cannot be resolved by the system. + CANT_RESOLVE_FILENAME = 1921, + /// The entry is not of the expected type. + RPC_S_ENTRY_TYPE_MISMATCH = 1922, + /// Not all object UUIDs could be exported to the specified entry. + RPC_S_NOT_ALL_OBJS_EXPORTED = 1923, + /// Interface could not be exported to the specified entry. + RPC_S_INTERFACE_NOT_EXPORTED = 1924, + /// The specified profile entry could not be added. + RPC_S_PROFILE_NOT_ADDED = 1925, + /// The specified profile element could not be added. + RPC_S_PRF_ELT_NOT_ADDED = 1926, + /// The specified profile element could not be removed. + RPC_S_PRF_ELT_NOT_REMOVED = 1927, + /// The group element could not be added. + RPC_S_GRP_ELT_NOT_ADDED = 1928, + /// The group element could not be removed. + RPC_S_GRP_ELT_NOT_REMOVED = 1929, + /// The printer driver is not compatible with a policy enabled on your computer that blocks NT 4.0 drivers. + KM_DRIVER_BLOCKED = 1930, + /// The context has expired and can no longer be used. + CONTEXT_EXPIRED = 1931, + /// The current user's delegated trust creation quota has been exceeded. + PER_USER_TRUST_QUOTA_EXCEEDED = 1932, + /// The total delegated trust creation quota has been exceeded. + ALL_USER_TRUST_QUOTA_EXCEEDED = 1933, + /// The current user's delegated trust deletion quota has been exceeded. + USER_DELETE_TRUST_QUOTA_EXCEEDED = 1934, + /// The computer you are signing into is protected by an authentication firewall. + /// The specified account is not allowed to authenticate to the computer. + AUTHENTICATION_FIREWALL_FAILED = 1935, + /// Remote connections to the Print Spooler are blocked by a policy set on your machine. + REMOTE_PRINT_CONNECTIONS_BLOCKED = 1936, + /// Authentication failed because NTLM authentication has been disabled. + NTLM_BLOCKED = 1937, + /// Logon Failure: EAS policy requires that the user change their password before this operation can be performed. + PASSWORD_CHANGE_REQUIRED = 1938, + /// The pixel format is invalid. + INVALID_PIXEL_FORMAT = 2000, + /// The specified driver is invalid. + BAD_DRIVER = 2001, + /// The window style or class attribute is invalid for this operation. + INVALID_WINDOW_STYLE = 2002, + /// The requested metafile operation is not supported. + METAFILE_NOT_SUPPORTED = 2003, + /// The requested transformation operation is not supported. + TRANSFORM_NOT_SUPPORTED = 2004, + /// The requested clipping operation is not supported. + CLIPPING_NOT_SUPPORTED = 2005, + /// The specified color management module is invalid. + INVALID_CMM = 2010, + /// The specified color profile is invalid. + INVALID_PROFILE = 2011, + /// The specified tag was not found. + TAG_NOT_FOUND = 2012, + /// A required tag is not present. + TAG_NOT_PRESENT = 2013, + /// The specified tag is already present. + DUPLICATE_TAG = 2014, + /// The specified color profile is not associated with the specified device. + PROFILE_NOT_ASSOCIATED_WITH_DEVICE = 2015, + /// The specified color profile was not found. + PROFILE_NOT_FOUND = 2016, + /// The specified color space is invalid. + INVALID_COLORSPACE = 2017, + /// Image Color Management is not enabled. + ICM_NOT_ENABLED = 2018, + /// There was an error while deleting the color transform. + DELETING_ICM_XFORM = 2019, + /// The specified color transform is invalid. + INVALID_TRANSFORM = 2020, + /// The specified transform does not match the bitmap's color space. + COLORSPACE_MISMATCH = 2021, + /// The specified named color index is not present in the profile. + INVALID_COLORINDEX = 2022, + /// The specified profile is intended for a device of a different type than the specified device. + PROFILE_DOES_NOT_MATCH_DEVICE = 2023, + /// The network connection was made successfully, but the user had to be prompted for a password other than the one originally specified. + CONNECTED_OTHER_PASSWORD = 2108, + /// The network connection was made successfully using default credentials. + CONNECTED_OTHER_PASSWORD_DEFAULT = 2109, + /// The specified username is invalid. + BAD_USERNAME = 2202, + /// This network connection does not exist. + NOT_CONNECTED = 2250, + /// This network connection has files open or requests pending. + OPEN_FILES = 2401, + /// Active connections still exist. + ACTIVE_CONNECTIONS = 2402, + /// The device is in use by an active process and cannot be disconnected. + DEVICE_IN_USE = 2404, + /// The specified print monitor is unknown. + UNKNOWN_PRINT_MONITOR = 3000, + /// The specified printer driver is currently in use. + PRINTER_DRIVER_IN_USE = 3001, + /// The spool file was not found. + SPOOL_FILE_NOT_FOUND = 3002, + /// A StartDocPrinter call was not issued. + SPL_NO_STARTDOC = 3003, + /// An AddJob call was not issued. + SPL_NO_ADDJOB = 3004, + /// The specified print processor has already been installed. + PRINT_PROCESSOR_ALREADY_INSTALLED = 3005, + /// The specified print monitor has already been installed. + PRINT_MONITOR_ALREADY_INSTALLED = 3006, + /// The specified print monitor does not have the required functions. + INVALID_PRINT_MONITOR = 3007, + /// The specified print monitor is currently in use. + PRINT_MONITOR_IN_USE = 3008, + /// The requested operation is not allowed when there are jobs queued to the printer. + PRINTER_HAS_JOBS_QUEUED = 3009, + /// The requested operation is successful. + /// Changes will not be effective until the system is rebooted. + SUCCESS_REBOOT_REQUIRED = 3010, + /// The requested operation is successful. + /// Changes will not be effective until the service is restarted. + SUCCESS_RESTART_REQUIRED = 3011, + /// No printers were found. + PRINTER_NOT_FOUND = 3012, + /// The printer driver is known to be unreliable. + PRINTER_DRIVER_WARNED = 3013, + /// The printer driver is known to harm the system. + PRINTER_DRIVER_BLOCKED = 3014, + /// The specified printer driver package is currently in use. + PRINTER_DRIVER_PACKAGE_IN_USE = 3015, + /// Unable to find a core driver package that is required by the printer driver package. + CORE_DRIVER_PACKAGE_NOT_FOUND = 3016, + /// The requested operation failed. + /// A system reboot is required to roll back changes made. + FAIL_REBOOT_REQUIRED = 3017, + /// The requested operation failed. + /// A system reboot has been initiated to roll back changes made. + FAIL_REBOOT_INITIATED = 3018, + /// The specified printer driver was not found on the system and needs to be downloaded. + PRINTER_DRIVER_DOWNLOAD_NEEDED = 3019, + /// The requested print job has failed to print. + /// A print system update requires the job to be resubmitted. + PRINT_JOB_RESTART_REQUIRED = 3020, + /// The printer driver does not contain a valid manifest, or contains too many manifests. + INVALID_PRINTER_DRIVER_MANIFEST = 3021, + /// The specified printer cannot be shared. + PRINTER_NOT_SHAREABLE = 3022, + /// The operation was paused. + REQUEST_PAUSED = 3050, + /// Reissue the given operation as a cached IO operation. + IO_REISSUE_AS_CACHED = 3950, + _, + + /// An application attempts to use an event object, but the specified handle is not valid. + pub const WSA_INVALID_HANDLE: Win32Error = @enumFromInt(6); + + /// An application used a Windows Sockets function that directly maps to a Windows function. The Windows function is indicating a lack of required memory resources. + pub const WSA_NOT_ENOUGH_MEMORY: Win32Error = @enumFromInt(8); + + /// An application used a Windows Sockets function which directly maps to a Windows function. The Windows function is indicating a problem with one or more parameters. + pub const WSA_INVALID_PARAMETER: Win32Error = @enumFromInt(87); + + /// An overlapped operation was canceled due to the closure of the socket, or the execution of the SIO_FLUSH command in WSAIoctl. + pub const WSA_OPERATION_ABORTED: Win32Error = @enumFromInt(995); + + /// The application has tried to determine the status of an overlapped operation which is not yet completed. Applications that use WSAGetOverlappedResult (with the fWait flag set to FALSE) in a polling mode to determine when an overlapped operation has completed, get this error code until the operation is complete. + pub const WSA_IO_INCOMPLETE: Win32Error = @enumFromInt(996); + + /// The application has initiated an overlapped operation that cannot be completed immediately. A completion indication will be given later when the operation has been completed. + pub const WSA_IO_PENDING: Win32Error = @enumFromInt(997); + + /// A blocking operation was interrupted by a call to WSACancelBlockingCall. + pub const WSAEINTR: Win32Error = @enumFromInt(10004); + + /// The file handle supplied is not valid. + pub const WSAEBADF: Win32Error = @enumFromInt(10009); + + /// An attempt was made to access a socket in a way forbidden by its access permissions. An example is using a broadcast address for sendto without broadcast permission being set using setsockopt(SO_BROADCAST). + /// Another possible reason for the WSAEACCES error is that when the bind function is called (on Windows NT 4.0 with SP4 and later), another application, service, or kernel mode driver is bound to the same address with exclusive access. Such exclusive access is a new feature of Windows NT 4.0 with SP4 and later, and is implemented by using the SO_EXCLUSIVEADDRUSE option. + pub const WSAEACCES: Win32Error = @enumFromInt(10013); + + /// The system detected an invalid pointer address in attempting to use a pointer argument of a call. This error occurs if an application passes an invalid pointer value, or if the length of the buffer is too small. For instance, if the length of an argument, which is a sockaddr structure, is smaller than the sizeof(sockaddr). + pub const WSAEFAULT: Win32Error = @enumFromInt(10014); + + /// Some invalid argument was supplied (for example, specifying an invalid level to the setsockopt function). In some instances, it also refers to the current state of the socket—for instance, calling accept on a socket that is not listening. + pub const WSAEINVAL: Win32Error = @enumFromInt(10022); + + /// Too many open sockets. Each implementation may have a maximum number of socket handles available, either globally, per process, or per thread. + pub const WSAEMFILE: Win32Error = @enumFromInt(10024); + + /// This error is returned from operations on nonblocking sockets that cannot be completed immediately, for example recv when no data is queued to be read from the socket. It is a nonfatal error, and the operation should be retried later. It is normal for WSAEWOULDBLOCK to be reported as the result from calling connect on a nonblocking SOCK_STREAM socket, since some time must elapse for the connection to be established. + pub const WSAEWOULDBLOCK: Win32Error = @enumFromInt(10035); + + /// A blocking operation is currently executing. Windows Sockets only allows a single blocking operation—per- task or thread—to be outstanding, and if any other function call is made (whether or not it references that or any other socket) the function fails with the WSAEINPROGRESS error. + pub const WSAEINPROGRESS: Win32Error = @enumFromInt(10036); + + /// An operation was attempted on a nonblocking socket with an operation already in progress—that is, calling connect a second time on a nonblocking socket that is already connecting, or canceling an asynchronous request (WSAAsyncGetXbyY) that has already been canceled or completed. + pub const WSAEALREADY: Win32Error = @enumFromInt(10037); + + /// An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid. + pub const WSAENOTSOCK: Win32Error = @enumFromInt(10038); + + /// A required address was omitted from an operation on a socket. For example, this error is returned if sendto is called with the remote address of ADDR_ANY. + pub const WSAEDESTADDRREQ: Win32Error = @enumFromInt(10039); + + /// A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram was smaller than the datagram itself. + pub const WSAEMSGSIZE: Win32Error = @enumFromInt(10040); + + /// A protocol was specified in the socket function call that does not support the semantics of the socket type requested. For example, the ARPA Internet UDP protocol cannot be specified with a socket type of SOCK_STREAM. + pub const WSAEPROTOTYPE: Win32Error = @enumFromInt(10041); + + /// An unknown, invalid or unsupported option or level was specified in a getsockopt or setsockopt call. + pub const WSAENOPROTOOPT: Win32Error = @enumFromInt(10042); + + /// The requested protocol has not been configured into the system, or no implementation for it exists. For example, a socket call requests a SOCK_DGRAM socket, but specifies a stream protocol. + pub const WSAEPROTONOSUPPORT: Win32Error = @enumFromInt(10043); + + /// The support for the specified socket type does not exist in this address family. For example, the optional type SOCK_RAW might be selected in a socket call, and the implementation does not support SOCK_RAW sockets at all. + pub const WSAESOCKTNOSUPPORT: Win32Error = @enumFromInt(10044); + + /// The attempted operation is not supported for the type of object referenced. Usually this occurs when a socket descriptor to a socket that cannot support this operation is trying to accept a connection on a datagram socket. + pub const WSAEOPNOTSUPP: Win32Error = @enumFromInt(10045); + + /// The protocol family has not been configured into the system or no implementation for it exists. This message has a slightly different meaning from WSAEAFNOSUPPORT. However, it is interchangeable in most cases, and all Windows Sockets functions that return one of these messages also specify WSAEAFNOSUPPORT. + pub const WSAEPFNOSUPPORT: Win32Error = @enumFromInt(10046); + + /// An address incompatible with the requested protocol was used. All sockets are created with an associated address family (that is, AF_INET for Internet Protocols) and a generic protocol type (that is, SOCK_STREAM). This error is returned if an incorrect protocol is explicitly requested in the socket call, or if an address of the wrong family is used for a socket, for example, in sendto. + pub const WSAEAFNOSUPPORT: Win32Error = @enumFromInt(10047); + + /// Typically, only one usage of each socket address (protocol/IP address/port) is permitted. This error occurs if an application attempts to bind a socket to an IP address/port that has already been used for an existing socket, or a socket that was not closed properly, or one that is still in the process of closing. For server applications that need to bind multiple sockets to the same port number, consider using setsockopt (SO_REUSEADDR). Client applications usually need not call bind at all—connect chooses an unused port automatically. When bind is called with a wildcard address (involving ADDR_ANY), a WSAEADDRINUSE error could be delayed until the specific address is committed. This could happen with a call to another function later, including connect, listen, WSAConnect, or WSAJoinLeaf. + pub const WSAEADDRINUSE: Win32Error = @enumFromInt(10048); + + /// The requested address is not valid in its context. This normally results from an attempt to bind to an address that is not valid for the local computer. This can also result from connect, sendto, WSAConnect, WSAJoinLeaf, or WSASendTo when the remote address or port is not valid for a remote computer (for example, address or port 0). + pub const WSAEADDRNOTAVAIL: Win32Error = @enumFromInt(10049); + + /// A socket operation encountered a dead network. This could indicate a serious failure of the network system (that is, the protocol stack that the Windows Sockets DLL runs over), the network interface, or the local network itself. + pub const WSAENETDOWN: Win32Error = @enumFromInt(10050); + + /// A socket operation was attempted to an unreachable network. This usually means the local software knows no route to reach the remote host. + pub const WSAENETUNREACH: Win32Error = @enumFromInt(10051); + + /// The connection has been broken due to keep-alive activity detecting a failure while the operation was in progress. It can also be returned by setsockopt if an attempt is made to set SO_KEEPALIVE on a connection that has already failed. + pub const WSAENETRESET: Win32Error = @enumFromInt(10052); + + /// An established connection was aborted by the software in your host computer, possibly due to a data transmission time-out or protocol error. + pub const WSAECONNABORTED: Win32Error = @enumFromInt(10053); + + /// An existing connection was forcibly closed by the remote host. This normally results if the peer application on the remote host is suddenly stopped, the host is rebooted, the host or remote network interface is disabled, or the remote host uses a hard close (see setsockopt for more information on the SO_LINGER option on the remote socket). This error may also result if a connection was broken due to keep-alive activity detecting a failure while one or more operations are in progress. Operations that were in progress fail with WSAENETRESET. Subsequent operations fail with WSAECONNRESET. + pub const WSAECONNRESET: Win32Error = @enumFromInt(10054); + + /// An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full. + pub const WSAENOBUFS: Win32Error = @enumFromInt(10055); + + /// A connect request was made on an already-connected socket. Some implementations also return this error if sendto is called on a connected SOCK_DGRAM socket (for SOCK_STREAM sockets, the to parameter in sendto is ignored) although other implementations treat this as a legal occurrence. + pub const WSAEISCONN: Win32Error = @enumFromInt(10056); + + /// A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using sendto) no address was supplied. Any other type of operation might also return this error—for example, setsockopt setting SO_KEEPALIVE if the connection has been reset. + pub const WSAENOTCONN: Win32Error = @enumFromInt(10057); + + /// A request to send or receive data was disallowed because the socket had already been shut down in that direction with a previous shutdown call. By calling shutdown a partial close of a socket is requested, which is a signal that sending or receiving, or both have been discontinued. + pub const WSAESHUTDOWN: Win32Error = @enumFromInt(10058); + + /// Too many references to some kernel object. + pub const WSAETOOMANYREFS: Win32Error = @enumFromInt(10059); + + /// A connection attempt failed because the connected party did not properly respond after a period of time, or the established connection failed because the connected host has failed to respond. + pub const WSAETIMEDOUT: Win32Error = @enumFromInt(10060); + + /// No connection could be made because the target computer actively refused it. This usually results from trying to connect to a service that is inactive on the foreign host—that is, one with no server application running. + pub const WSAECONNREFUSED: Win32Error = @enumFromInt(10061); + + /// Cannot translate a name. + pub const WSAELOOP: Win32Error = @enumFromInt(10062); + + /// A name component or a name was too long. + pub const WSAENAMETOOLONG: Win32Error = @enumFromInt(10063); + + /// A socket operation failed because the destination host is down. A socket operation encountered a dead host. Networking activity on the local host has not been initiated. These conditions are more likely to be indicated by the error WSAETIMEDOUT. + pub const WSAEHOSTDOWN: Win32Error = @enumFromInt(10064); + + /// A socket operation was attempted to an unreachable host. See WSAENETUNREACH. + pub const WSAEHOSTUNREACH: Win32Error = @enumFromInt(10065); + + /// Cannot remove a directory that is not empty. + pub const WSAENOTEMPTY: Win32Error = @enumFromInt(10066); + + /// A Windows Sockets implementation may have a limit on the number of applications that can use it simultaneously. WSAStartup may fail with this error if the limit has been reached. + pub const WSAEPROCLIM: Win32Error = @enumFromInt(10067); + + /// Ran out of user quota. + pub const WSAEUSERS: Win32Error = @enumFromInt(10068); + + /// Ran out of disk quota. + pub const WSAEDQUOT: Win32Error = @enumFromInt(10069); + + /// The file handle reference is no longer available. + pub const WSAESTALE: Win32Error = @enumFromInt(10070); + + /// The item is not available locally. + pub const WSAEREMOTE: Win32Error = @enumFromInt(10071); + + /// This error is returned by WSAStartup if the Windows Sockets implementation cannot function at this time because the underlying system it uses to provide network services is currently unavailable. Users should check: + pub const WSASYSNOTREADY: Win32Error = @enumFromInt(10091); + + /// The current Windows Sockets implementation does not support the Windows Sockets specification version requested by the application. Check that no old Windows Sockets DLL files are being accessed. + pub const WSAVERNOTSUPPORTED: Win32Error = @enumFromInt(10092); + + /// Either the application has not called WSAStartup or WSAStartup failed. The application may be accessing a socket that the current active task does not own (that is, trying to share a socket between tasks), or WSACleanup has been called too many times. + pub const WSANOTINITIALISED: Win32Error = @enumFromInt(10093); + + /// Returned by WSARecv and WSARecvFrom to indicate that the remote party has initiated a graceful shutdown sequence. + pub const WSAEDISCON: Win32Error = @enumFromInt(10101); + + /// No more results can be returned by the WSALookupServiceNext function. + pub const WSAENOMORE: Win32Error = @enumFromInt(10102); + + /// A call to the WSALookupServiceEnd function was made while this call was still processing. The call has been canceled. + pub const WSAECANCELLED: Win32Error = @enumFromInt(10103); + + /// The service provider procedure call table is invalid. A service provider returned a bogus procedure table to Ws2_32.dll. This is usually caused by one or more of the function pointers being NULL. + pub const WSAEINVALIDPROCTABLE: Win32Error = @enumFromInt(10104); + + /// The requested service provider is invalid. This error is returned by the WSCGetProviderInfo and WSCGetProviderInfo32 functions if the protocol entry specified could not be found. This error is also returned if the service provider returned a version number other than 2.0. + pub const WSAEINVALIDPROVIDER: Win32Error = @enumFromInt(10105); + + /// The requested service provider could not be loaded or initialized. This error is returned if either a service provider's DLL could not be loaded (LoadLibrary failed) or the provider's WSPStartup or NSPStartup function failed. + pub const WSAEPROVIDERFAILEDINIT: Win32Error = @enumFromInt(10106); + + /// A system call that should never fail has failed. This is a generic error code, returned under various conditions. + /// Returned when a system call that should never fail does fail. For example, if a call to WaitForMultipleEvents fails or one of the registry functions fails trying to manipulate the protocol/namespace catalogs. + /// Returned when a provider does not return SUCCESS and does not provide an extended error code. Can indicate a service provider implementation error. + pub const WSASYSCALLFAILURE: Win32Error = @enumFromInt(10107); + + /// No such service is known. The service cannot be found in the specified name space. + pub const WSASERVICE_NOT_FOUND: Win32Error = @enumFromInt(10108); + + /// The specified class was not found. + pub const WSATYPE_NOT_FOUND: Win32Error = @enumFromInt(10109); + + /// No more results can be returned by the WSALookupServiceNext function. + pub const WSA_E_NO_MORE: Win32Error = @enumFromInt(10110); + + /// A call to the WSALookupServiceEnd function was made while this call was still processing. The call has been canceled. + pub const WSA_E_CANCELLED: Win32Error = @enumFromInt(10111); + + /// A database query failed because it was actively refused. + pub const WSAEREFUSED: Win32Error = @enumFromInt(10112); + + /// No such host is known. The name is not an official host name or alias, or it cannot be found in the database(s) being queried. This error may also be returned for protocol and service queries, and means that the specified name could not be found in the relevant database. + pub const WSAHOST_NOT_FOUND: Win32Error = @enumFromInt(11001); + + /// This is usually a temporary error during host name resolution and means that the local server did not receive a response from an authoritative server. A retry at some time later may be successful. + pub const WSATRY_AGAIN: Win32Error = @enumFromInt(11002); + + /// This indicates that some sort of nonrecoverable error occurred during a database lookup. This may be because the database files (for example, BSD-compatible HOSTS, SERVICES, or PROTOCOLS files) could not be found, or a DNS request was returned by the server with a severe error. + pub const WSANO_RECOVERY: Win32Error = @enumFromInt(11003); + + /// The requested name is valid and was found in the database, but it does not have the correct associated data being resolved for. The usual example for this is a host name-to-address translation attempt (using gethostbyname or WSAAsyncGetHostByName) which uses the DNS (Domain Name Server). An MX record is returned but no A record—indicating the host itself exists, but is not directly reachable. + pub const WSANO_DATA: Win32Error = @enumFromInt(11004); + + /// At least one QoS reserve has arrived. + pub const WSA_QOS_RECEIVERS: Win32Error = @enumFromInt(11005); + + /// At least one QoS send path has arrived. + pub const WSA_QOS_SENDERS: Win32Error = @enumFromInt(11006); + + /// There are no QoS senders. + pub const WSA_QOS_NO_SENDERS: Win32Error = @enumFromInt(11007); + + /// There are no QoS receivers. + pub const WSA_QOS_NO_RECEIVERS: Win32Error = @enumFromInt(11008); + + /// The QoS reserve request has been confirmed. + pub const WSA_QOS_REQUEST_CONFIRMED: Win32Error = @enumFromInt(11009); + + /// A QoS error occurred due to lack of resources. + pub const WSA_QOS_ADMISSION_FAILURE: Win32Error = @enumFromInt(11010); + + /// The QoS request was rejected because the policy system couldn't allocate the requested resource within the existing policy. + pub const WSA_QOS_POLICY_FAILURE: Win32Error = @enumFromInt(11011); + + /// An unknown or conflicting QoS style was encountered. + pub const WSA_QOS_BAD_STYLE: Win32Error = @enumFromInt(11012); + + /// A problem was encountered with some part of the filterspec or the provider-specific buffer in general. + pub const WSA_QOS_BAD_OBJECT: Win32Error = @enumFromInt(11013); + + /// An error with the underlying traffic control (TC) API as the generic QoS request was converted for local enforcement by the TC API. This could be due to an out of memory error or to an internal QoS provider error. + pub const WSA_QOS_TRAFFIC_CTRL_ERROR: Win32Error = @enumFromInt(11014); + + /// A general QoS error. + pub const WSA_QOS_GENERIC_ERROR: Win32Error = @enumFromInt(11015); + + /// An invalid or unrecognized service type was found in the QoS flowspec. + pub const WSA_QOS_ESERVICETYPE: Win32Error = @enumFromInt(11016); + + /// An invalid or inconsistent flowspec was found in the QOS structure. + pub const WSA_QOS_EFLOWSPEC: Win32Error = @enumFromInt(11017); + + /// An invalid QoS provider-specific buffer. + pub const WSA_QOS_EPROVSPECBUF: Win32Error = @enumFromInt(11018); + + /// An invalid QoS filter style was used. + pub const WSA_QOS_EFILTERSTYLE: Win32Error = @enumFromInt(11019); + + /// An invalid QoS filter type was used. + pub const WSA_QOS_EFILTERTYPE: Win32Error = @enumFromInt(11020); + + /// An incorrect number of QoS FILTERSPECs were specified in the FLOWDESCRIPTOR. + pub const WSA_QOS_EFILTERCOUNT: Win32Error = @enumFromInt(11021); + + /// An object with an invalid ObjectLength field was specified in the QoS provider-specific buffer. + pub const WSA_QOS_EOBJLENGTH: Win32Error = @enumFromInt(11022); + + /// An incorrect number of flow descriptors was specified in the QoS structure. + pub const WSA_QOS_EFLOWCOUNT: Win32Error = @enumFromInt(11023); + + /// An unrecognized object was found in the QoS provider-specific buffer. + pub const WSA_QOS_EUNKOWNPSOBJ: Win32Error = @enumFromInt(11024); + + /// An invalid policy object was found in the QoS provider-specific buffer. + pub const WSA_QOS_EPOLICYOBJ: Win32Error = @enumFromInt(11025); + + /// An invalid QoS flow descriptor was found in the flow descriptor list. + pub const WSA_QOS_EFLOWDESC: Win32Error = @enumFromInt(11026); + + /// An invalid or inconsistent flowspec was found in the QoS provider-specific buffer. + pub const WSA_QOS_EPSFLOWSPEC: Win32Error = @enumFromInt(11027); + + /// An invalid FILTERSPEC was found in the QoS provider-specific buffer. + pub const WSA_QOS_EPSFILTERSPEC: Win32Error = @enumFromInt(11028); + + /// An invalid shape discard mode object was found in the QoS provider-specific buffer. + pub const WSA_QOS_ESDMODEOBJ: Win32Error = @enumFromInt(11029); + + /// An invalid shaping rate object was found in the QoS provider-specific buffer. + pub const WSA_QOS_ESHAPERATEOBJ: Win32Error = @enumFromInt(11030); + + /// A reserved policy element was found in the QoS provider-specific buffer. + pub const WSA_QOS_RESERVED_PETYPE: Win32Error = @enumFromInt(11031); + + pub fn get() Win32Error { + return @enumFromInt(@intFromEnum(bun.windows.kernel32.GetLastError())); + } + + pub fn toSystemErrno(this: Win32Error) ?SystemErrno { + return SystemErrno.init(this); + } + + pub fn fromNTStatus(status: win32.NTSTATUS) Win32Error { + return RtlNtStatusToDosError(status); + } +}; diff --git a/src/windows_c.zig b/src/windows_c.zig new file mode 100644 index 000000000..299614579 --- /dev/null +++ b/src/windows_c.zig @@ -0,0 +1,1032 @@ +const std = @import("std"); +const bun = @import("root").bun; +const builtin = @import("builtin"); +const win32 = std.os.windows; +const os = std.os; +const mem = std.mem; +const Stat = std.fs.File.Stat; +const Kind = std.fs.File.Kind; +const StatError = std.fs.File.StatError; + +pub fn getTotalMemory() usize { + return 0; +} +pub fn getSystemMemory() usize { + return 0; +} + +pub fn getFreeMemory() usize { + return 0; +} + +pub fn getSystemUptime() usize { + return 0; +} + +pub fn getSystemLoadavg() [3]f32 { + return .{ 0, 0, 0 }; +} + +pub const Mode = i32; +const Win32Error = bun.windows.Win32Error; + +// The way we do errors in Bun needs to get cleaned up. +// This is way too complicated. +// The problem is because we use libc in some cases and we use zig's std lib in other places and other times we go direct. +// So we end up with a lot of redundant code. +pub const SystemErrno = enum(u8) { + SUCCESS = 0, + EPERM = 1, + ENOENT = 2, + ESRCH = 3, + EINTR = 4, + EIO = 5, + ENXIO = 6, + E2BIG = 7, + ENOEXEC = 8, + EBADF = 9, + ECHILD = 10, + EAGAIN = 11, + ENOMEM = 12, + EACCES = 13, + EFAULT = 14, + ENOTBLK = 15, + EBUSY = 16, + EEXIST = 17, + EXDEV = 18, + ENODEV = 19, + ENOTDIR = 20, + EISDIR = 21, + EINVAL = 22, + ENFILE = 23, + EMFILE = 24, + ENOTTY = 25, + ETXTBSY = 26, + EFBIG = 27, + ENOSPC = 28, + ESPIPE = 29, + EROFS = 30, + EMLINK = 31, + EPIPE = 32, + EDOM = 33, + ERANGE = 34, + EDEADLK = 35, + ENAMETOOLONG = 36, + ENOLCK = 37, + ENOSYS = 38, + ENOTEMPTY = 39, + ELOOP = 40, + EWOULDBLOCK = 41, + ENOMSG = 42, + EIDRM = 43, + ECHRNG = 44, + EL2NSYNC = 45, + EL3HLT = 46, + EL3RST = 47, + ELNRNG = 48, + EUNATCH = 49, + ENOCSI = 50, + EL2HLT = 51, + EBADE = 52, + EBADR = 53, + EXFULL = 54, + ENOANO = 55, + EBADRQC = 56, + EBADSLT = 57, + EDEADLOCK = 58, + EBFONT = 59, + ENOSTR = 60, + ENODATA = 61, + ETIME = 62, + ENOSR = 63, + ENONET = 64, + ENOPKG = 65, + EREMOTE = 66, + ENOLINK = 67, + EADV = 68, + ESRMNT = 69, + ECOMM = 70, + EPROTO = 71, + EMULTIHOP = 72, + EDOTDOT = 73, + EBADMSG = 74, + EOVERFLOW = 75, + ENOTUNIQ = 76, + EBADFD = 77, + EREMCHG = 78, + ELIBACC = 79, + ELIBBAD = 80, + ELIBSCN = 81, + ELIBMAX = 82, + ELIBEXEC = 83, + EILSEQ = 84, + ERESTART = 85, + ESTRPIPE = 86, + EUSERS = 87, + ENOTSOCK = 88, + EDESTADDRREQ = 89, + EMSGSIZE = 90, + EPROTOTYPE = 91, + ENOPROTOOPT = 92, + EPROTONOSUPPORT = 93, + ESOCKTNOSUPPORT = 94, + /// For Linux, EOPNOTSUPP is the real value + /// but it's ~the same and is incompatible across operating systems + /// https://lists.gnu.org/archive/html/bug-glibc/2002-08/msg00017.html + ENOTSUP = 95, + EPFNOSUPPORT = 96, + EAFNOSUPPORT = 97, + EADDRINUSE = 98, + EADDRNOTAVAIL = 99, + ENETDOWN = 100, + ENETUNREACH = 101, + ENETRESET = 102, + ECONNABORTED = 103, + ECONNRESET = 104, + ENOBUFS = 105, + EISCONN = 106, + ENOTCONN = 107, + ESHUTDOWN = 108, + ETOOMANYREFS = 109, + ETIMEDOUT = 110, + ECONNREFUSED = 111, + EHOSTDOWN = 112, + EHOSTUNREACH = 113, + EALREADY = 114, + EINPROGRESS = 115, + ESTALE = 116, + EUCLEAN = 117, + ENOTNAM = 118, + ENAVAIL = 119, + EISNAM = 120, + EREMOTEIO = 121, + EDQUOT = 122, + ENOMEDIUM = 123, + EMEDIUMTYPE = 124, + ECANCELED = 125, + ENOKEY = 126, + EKEYEXPIRED = 127, + EKEYREVOKED = 128, + EKEYREJECTED = 129, + EOWNERDEAD = 130, + ENOTRECOVERABLE = 131, + ERFKILL = 132, + EHWPOISON = 133, + // made up erropr + EUNKNOWN = 134, + ECHARSET = 135, + EOF = 136, + + pub const max = 137; + + pub const Error = error{ + PERM, + NOENT, + SRCH, + INTR, + IO, + NXIO, + @"2BIG", + NOEXEC, + BADF, + CHILD, + AGAIN, + NOMEM, + ACCES, + FAULT, + NOTBLK, + BUSY, + EXIST, + XDEV, + NODEV, + NOTDIR, + ISDIR, + INVAL, + NFILE, + MFILE, + NOTTY, + TXTBSY, + FBIG, + NOSPC, + SPIPE, + ROFS, + MLINK, + PIPE, + DOM, + RANGE, + DEADLK, + NAMETOOLONG, + NOLCK, + NOSYS, + NOTEMPTY, + LOOP, + WOULDBLOCK, + NOMSG, + IDRM, + CHRNG, + L2NSYNC, + L3HLT, + L3RST, + LNRNG, + UNATCH, + NOCSI, + L2HLT, + BADE, + BADR, + XFULL, + NOANO, + BADRQC, + BADSLT, + DEADLOCK, + BFONT, + NOSTR, + NODATA, + TIME, + NOSR, + NONET, + NOPKG, + REMOTE, + NOLINK, + ADV, + SRMNT, + COMM, + PROTO, + MULTIHOP, + DOTDOT, + BADMSG, + OVERFLOW, + NOTUNIQ, + BADFD, + REMCHG, + LIBACC, + LIBBAD, + LIBSCN, + LIBMAX, + LIBEXEC, + ILSEQ, + RESTART, + STRPIPE, + USERS, + NOTSOCK, + DESTADDRREQ, + MSGSIZE, + PROTOTYPE, + NOPROTOOPT, + PROTONOSUPPORT, + SOCKTNOSUPPORT, + NOTSUP, + PFNOSUPPORT, + AFNOSUPPORT, + ADDRINUSE, + ADDRNOTAVAIL, + NETDOWN, + NETUNREACH, + NETRESET, + CONNABORTED, + CONNRESET, + NOBUFS, + ISCONN, + NOTCONN, + SHUTDOWN, + TOOMANYREFS, + TIMEDOUT, + CONNREFUSED, + HOSTDOWN, + HOSTUNREACH, + ALREADY, + INPROGRESS, + STALE, + UCLEAN, + NOTNAM, + NAVAIL, + ISNAM, + REMOTEIO, + DQUOT, + NOMEDIUM, + MEDIUMTYPE, + CANCELED, + NOKEY, + KEYEXPIRED, + KEYREVOKED, + KEYREJECTED, + OWNERDEAD, + NOTRECOVERABLE, + RFKILL, + HWPOISON, + UNKNOWN, + CHARSET, + OF, + Unexpected, + }; + + pub inline fn toE(this: SystemErrno) E { + return @enumFromInt(@intFromEnum(this)); + } + + const error_map: [SystemErrno.max]Error = brk: { + var errors: [SystemErrno.max]Error = undefined; + errors[@intFromEnum(SystemErrno.EPERM)] = error.PERM; + errors[@intFromEnum(SystemErrno.ENOENT)] = error.NOENT; + errors[@intFromEnum(SystemErrno.ESRCH)] = error.SRCH; + errors[@intFromEnum(SystemErrno.EINTR)] = error.INTR; + errors[@intFromEnum(SystemErrno.EIO)] = error.IO; + errors[@intFromEnum(SystemErrno.ENXIO)] = error.NXIO; + errors[@intFromEnum(SystemErrno.E2BIG)] = error.@"2BIG"; + errors[@intFromEnum(SystemErrno.ENOEXEC)] = error.NOEXEC; + errors[@intFromEnum(SystemErrno.EBADF)] = error.BADF; + errors[@intFromEnum(SystemErrno.ECHILD)] = error.CHILD; + errors[@intFromEnum(SystemErrno.EAGAIN)] = error.AGAIN; + errors[@intFromEnum(SystemErrno.ENOMEM)] = error.NOMEM; + errors[@intFromEnum(SystemErrno.EACCES)] = error.ACCES; + errors[@intFromEnum(SystemErrno.EFAULT)] = error.FAULT; + errors[@intFromEnum(SystemErrno.ENOTBLK)] = error.NOTBLK; + errors[@intFromEnum(SystemErrno.EBUSY)] = error.BUSY; + errors[@intFromEnum(SystemErrno.EEXIST)] = error.EXIST; + errors[@intFromEnum(SystemErrno.EXDEV)] = error.XDEV; + errors[@intFromEnum(SystemErrno.ENODEV)] = error.NODEV; + errors[@intFromEnum(SystemErrno.ENOTDIR)] = error.NOTDIR; + errors[@intFromEnum(SystemErrno.EISDIR)] = error.ISDIR; + errors[@intFromEnum(SystemErrno.EINVAL)] = error.INVAL; + errors[@intFromEnum(SystemErrno.ENFILE)] = error.NFILE; + errors[@intFromEnum(SystemErrno.EMFILE)] = error.MFILE; + errors[@intFromEnum(SystemErrno.ENOTTY)] = error.NOTTY; + errors[@intFromEnum(SystemErrno.ETXTBSY)] = error.TXTBSY; + errors[@intFromEnum(SystemErrno.EFBIG)] = error.FBIG; + errors[@intFromEnum(SystemErrno.ENOSPC)] = error.NOSPC; + errors[@intFromEnum(SystemErrno.ESPIPE)] = error.SPIPE; + errors[@intFromEnum(SystemErrno.EROFS)] = error.ROFS; + errors[@intFromEnum(SystemErrno.EMLINK)] = error.MLINK; + errors[@intFromEnum(SystemErrno.EPIPE)] = error.PIPE; + errors[@intFromEnum(SystemErrno.EDOM)] = error.DOM; + errors[@intFromEnum(SystemErrno.ERANGE)] = error.RANGE; + errors[@intFromEnum(SystemErrno.EDEADLK)] = error.DEADLK; + errors[@intFromEnum(SystemErrno.ENAMETOOLONG)] = error.NAMETOOLONG; + errors[@intFromEnum(SystemErrno.ENOLCK)] = error.NOLCK; + errors[@intFromEnum(SystemErrno.ENOSYS)] = error.NOSYS; + errors[@intFromEnum(SystemErrno.ENOTEMPTY)] = error.NOTEMPTY; + errors[@intFromEnum(SystemErrno.ELOOP)] = error.LOOP; + errors[@intFromEnum(SystemErrno.EWOULDBLOCK)] = error.WOULDBLOCK; + errors[@intFromEnum(SystemErrno.ENOMSG)] = error.NOMSG; + errors[@intFromEnum(SystemErrno.EIDRM)] = error.IDRM; + errors[@intFromEnum(SystemErrno.ECHRNG)] = error.CHRNG; + errors[@intFromEnum(SystemErrno.EL2NSYNC)] = error.L2NSYNC; + errors[@intFromEnum(SystemErrno.EL3HLT)] = error.L3HLT; + errors[@intFromEnum(SystemErrno.EL3RST)] = error.L3RST; + errors[@intFromEnum(SystemErrno.ELNRNG)] = error.LNRNG; + errors[@intFromEnum(SystemErrno.EUNATCH)] = error.UNATCH; + errors[@intFromEnum(SystemErrno.ENOCSI)] = error.NOCSI; + errors[@intFromEnum(SystemErrno.EL2HLT)] = error.L2HLT; + errors[@intFromEnum(SystemErrno.EBADE)] = error.BADE; + errors[@intFromEnum(SystemErrno.EBADR)] = error.BADR; + errors[@intFromEnum(SystemErrno.EXFULL)] = error.XFULL; + errors[@intFromEnum(SystemErrno.ENOANO)] = error.NOANO; + errors[@intFromEnum(SystemErrno.EBADRQC)] = error.BADRQC; + errors[@intFromEnum(SystemErrno.EBADSLT)] = error.BADSLT; + errors[@intFromEnum(SystemErrno.EDEADLOCK)] = error.DEADLOCK; + errors[@intFromEnum(SystemErrno.EBFONT)] = error.BFONT; + errors[@intFromEnum(SystemErrno.ENOSTR)] = error.NOSTR; + errors[@intFromEnum(SystemErrno.ENODATA)] = error.NODATA; + errors[@intFromEnum(SystemErrno.ETIME)] = error.TIME; + errors[@intFromEnum(SystemErrno.ENOSR)] = error.NOSR; + errors[@intFromEnum(SystemErrno.ENONET)] = error.NONET; + errors[@intFromEnum(SystemErrno.ENOPKG)] = error.NOPKG; + errors[@intFromEnum(SystemErrno.EREMOTE)] = error.REMOTE; + errors[@intFromEnum(SystemErrno.ENOLINK)] = error.NOLINK; + errors[@intFromEnum(SystemErrno.EADV)] = error.ADV; + errors[@intFromEnum(SystemErrno.ESRMNT)] = error.SRMNT; + errors[@intFromEnum(SystemErrno.ECOMM)] = error.COMM; + errors[@intFromEnum(SystemErrno.EPROTO)] = error.PROTO; + errors[@intFromEnum(SystemErrno.EMULTIHOP)] = error.MULTIHOP; + errors[@intFromEnum(SystemErrno.EDOTDOT)] = error.DOTDOT; + errors[@intFromEnum(SystemErrno.EBADMSG)] = error.BADMSG; + errors[@intFromEnum(SystemErrno.EOVERFLOW)] = error.OVERFLOW; + errors[@intFromEnum(SystemErrno.ENOTUNIQ)] = error.NOTUNIQ; + errors[@intFromEnum(SystemErrno.EBADFD)] = error.BADFD; + errors[@intFromEnum(SystemErrno.EREMCHG)] = error.REMCHG; + errors[@intFromEnum(SystemErrno.ELIBACC)] = error.LIBACC; + errors[@intFromEnum(SystemErrno.ELIBBAD)] = error.LIBBAD; + errors[@intFromEnum(SystemErrno.ELIBSCN)] = error.LIBSCN; + errors[@intFromEnum(SystemErrno.ELIBMAX)] = error.LIBMAX; + errors[@intFromEnum(SystemErrno.ELIBEXEC)] = error.LIBEXEC; + errors[@intFromEnum(SystemErrno.EILSEQ)] = error.ILSEQ; + errors[@intFromEnum(SystemErrno.ERESTART)] = error.RESTART; + errors[@intFromEnum(SystemErrno.ESTRPIPE)] = error.STRPIPE; + errors[@intFromEnum(SystemErrno.EUSERS)] = error.USERS; + errors[@intFromEnum(SystemErrno.ENOTSOCK)] = error.NOTSOCK; + errors[@intFromEnum(SystemErrno.EDESTADDRREQ)] = error.DESTADDRREQ; + errors[@intFromEnum(SystemErrno.EMSGSIZE)] = error.MSGSIZE; + errors[@intFromEnum(SystemErrno.EPROTOTYPE)] = error.PROTOTYPE; + errors[@intFromEnum(SystemErrno.ENOPROTOOPT)] = error.NOPROTOOPT; + errors[@intFromEnum(SystemErrno.EPROTONOSUPPORT)] = error.PROTONOSUPPORT; + errors[@intFromEnum(SystemErrno.ESOCKTNOSUPPORT)] = error.SOCKTNOSUPPORT; + errors[@intFromEnum(SystemErrno.ENOTSUP)] = error.NOTSUP; + errors[@intFromEnum(SystemErrno.EPFNOSUPPORT)] = error.PFNOSUPPORT; + errors[@intFromEnum(SystemErrno.EAFNOSUPPORT)] = error.AFNOSUPPORT; + errors[@intFromEnum(SystemErrno.EADDRINUSE)] = error.ADDRINUSE; + errors[@intFromEnum(SystemErrno.EADDRNOTAVAIL)] = error.ADDRNOTAVAIL; + errors[@intFromEnum(SystemErrno.ENETDOWN)] = error.NETDOWN; + errors[@intFromEnum(SystemErrno.ENETUNREACH)] = error.NETUNREACH; + errors[@intFromEnum(SystemErrno.ENETRESET)] = error.NETRESET; + errors[@intFromEnum(SystemErrno.ECONNABORTED)] = error.CONNABORTED; + errors[@intFromEnum(SystemErrno.ECONNRESET)] = error.CONNRESET; + errors[@intFromEnum(SystemErrno.ENOBUFS)] = error.NOBUFS; + errors[@intFromEnum(SystemErrno.EISCONN)] = error.ISCONN; + errors[@intFromEnum(SystemErrno.ENOTCONN)] = error.NOTCONN; + errors[@intFromEnum(SystemErrno.ESHUTDOWN)] = error.SHUTDOWN; + errors[@intFromEnum(SystemErrno.ETOOMANYREFS)] = error.TOOMANYREFS; + errors[@intFromEnum(SystemErrno.ETIMEDOUT)] = error.TIMEDOUT; + errors[@intFromEnum(SystemErrno.ECONNREFUSED)] = error.CONNREFUSED; + errors[@intFromEnum(SystemErrno.EHOSTDOWN)] = error.HOSTDOWN; + errors[@intFromEnum(SystemErrno.EHOSTUNREACH)] = error.HOSTUNREACH; + errors[@intFromEnum(SystemErrno.EALREADY)] = error.ALREADY; + errors[@intFromEnum(SystemErrno.EINPROGRESS)] = error.INPROGRESS; + errors[@intFromEnum(SystemErrno.ESTALE)] = error.STALE; + errors[@intFromEnum(SystemErrno.EUCLEAN)] = error.UCLEAN; + errors[@intFromEnum(SystemErrno.ENOTNAM)] = error.NOTNAM; + errors[@intFromEnum(SystemErrno.ENAVAIL)] = error.NAVAIL; + errors[@intFromEnum(SystemErrno.EISNAM)] = error.ISNAM; + errors[@intFromEnum(SystemErrno.EREMOTEIO)] = error.REMOTEIO; + errors[@intFromEnum(SystemErrno.EDQUOT)] = error.DQUOT; + errors[@intFromEnum(SystemErrno.ENOMEDIUM)] = error.NOMEDIUM; + errors[@intFromEnum(SystemErrno.EMEDIUMTYPE)] = error.MEDIUMTYPE; + errors[@intFromEnum(SystemErrno.ECANCELED)] = error.CANCELED; + errors[@intFromEnum(SystemErrno.ENOKEY)] = error.NOKEY; + errors[@intFromEnum(SystemErrno.EKEYEXPIRED)] = error.KEYEXPIRED; + errors[@intFromEnum(SystemErrno.EKEYREVOKED)] = error.KEYREVOKED; + errors[@intFromEnum(SystemErrno.EKEYREJECTED)] = error.KEYREJECTED; + errors[@intFromEnum(SystemErrno.EOWNERDEAD)] = error.OWNERDEAD; + errors[@intFromEnum(SystemErrno.ENOTRECOVERABLE)] = error.NOTRECOVERABLE; + errors[@intFromEnum(SystemErrno.ERFKILL)] = error.RFKILL; + errors[@intFromEnum(SystemErrno.EHWPOISON)] = error.HWPOISON; + errors[@intFromEnum(SystemErrno.EUNKNOWN)] = error.UNKNOWN; + errors[@intFromEnum(SystemErrno.ECHARSET)] = error.CHARSET; + errors[@intFromEnum(SystemErrno.EOF)] = error.OF; + break :brk errors; + }; + + pub fn fromError(err: anyerror) ?SystemErrno { + return switch (err) { + error.PERM => SystemErrno.EPERM, + error.NOENT => SystemErrno.ENOENT, + error.SRCH => SystemErrno.ESRCH, + error.INTR => SystemErrno.EINTR, + error.IO => SystemErrno.EIO, + error.NXIO => SystemErrno.ENXIO, + error.@"2BIG" => SystemErrno.E2BIG, + error.NOEXEC => SystemErrno.ENOEXEC, + error.BADF => SystemErrno.EBADF, + error.CHILD => SystemErrno.ECHILD, + error.AGAIN => SystemErrno.EAGAIN, + error.NOMEM => SystemErrno.ENOMEM, + error.ACCES => SystemErrno.EACCES, + error.FAULT => SystemErrno.EFAULT, + error.NOTBLK => SystemErrno.ENOTBLK, + error.BUSY => SystemErrno.EBUSY, + error.EXIST => SystemErrno.EEXIST, + error.XDEV => SystemErrno.EXDEV, + error.NODEV => SystemErrno.ENODEV, + error.NOTDIR => SystemErrno.ENOTDIR, + error.ISDIR => SystemErrno.EISDIR, + error.INVAL => SystemErrno.EINVAL, + error.NFILE => SystemErrno.ENFILE, + error.MFILE => SystemErrno.EMFILE, + error.NOTTY => SystemErrno.ENOTTY, + error.TXTBSY => SystemErrno.ETXTBSY, + error.FBIG => SystemErrno.EFBIG, + error.NOSPC => SystemErrno.ENOSPC, + error.SPIPE => SystemErrno.ESPIPE, + error.ROFS => SystemErrno.EROFS, + error.MLINK => SystemErrno.EMLINK, + error.PIPE => SystemErrno.EPIPE, + error.DOM => SystemErrno.EDOM, + error.RANGE => SystemErrno.ERANGE, + error.DEADLK => SystemErrno.EDEADLK, + error.NAMETOOLONG => SystemErrno.ENAMETOOLONG, + error.NOLCK => SystemErrno.ENOLCK, + error.NOSYS => SystemErrno.ENOSYS, + error.NOTEMPTY => SystemErrno.ENOTEMPTY, + error.LOOP => SystemErrno.ELOOP, + error.WOULDBLOCK => SystemErrno.EWOULDBLOCK, + error.NOMSG => SystemErrno.ENOMSG, + error.IDRM => SystemErrno.EIDRM, + error.CHRNG => SystemErrno.ECHRNG, + error.L2NSYNC => SystemErrno.EL2NSYNC, + error.L3HLT => SystemErrno.EL3HLT, + error.L3RST => SystemErrno.EL3RST, + error.LNRNG => SystemErrno.ELNRNG, + error.UNATCH => SystemErrno.EUNATCH, + error.NOCSI => SystemErrno.ENOCSI, + error.L2HLT => SystemErrno.EL2HLT, + error.BADE => SystemErrno.EBADE, + error.BADR => SystemErrno.EBADR, + error.XFULL => SystemErrno.EXFULL, + error.NOANO => SystemErrno.ENOANO, + error.BADRQC => SystemErrno.EBADRQC, + error.BADSLT => SystemErrno.EBADSLT, + error.DEADLOCK => SystemErrno.EDEADLOCK, + error.BFONT => SystemErrno.EBFONT, + error.NOSTR => SystemErrno.ENOSTR, + error.NODATA => SystemErrno.ENODATA, + error.TIME => SystemErrno.ETIME, + error.NOSR => SystemErrno.ENOSR, + error.NONET => SystemErrno.ENONET, + error.NOPKG => SystemErrno.ENOPKG, + error.REMOTE => SystemErrno.EREMOTE, + error.NOLINK => SystemErrno.ENOLINK, + error.ADV => SystemErrno.EADV, + error.SRMNT => SystemErrno.ESRMNT, + error.COMM => SystemErrno.ECOMM, + error.PROTO => SystemErrno.EPROTO, + error.MULTIHOP => SystemErrno.EMULTIHOP, + error.DOTDOT => SystemErrno.EDOTDOT, + error.BADMSG => SystemErrno.EBADMSG, + error.OVERFLOW => SystemErrno.EOVERFLOW, + error.NOTUNIQ => SystemErrno.ENOTUNIQ, + error.BADFD => SystemErrno.EBADFD, + error.REMCHG => SystemErrno.EREMCHG, + error.LIBACC => SystemErrno.ELIBACC, + error.LIBBAD => SystemErrno.ELIBBAD, + error.LIBSCN => SystemErrno.ELIBSCN, + error.LIBMAX => SystemErrno.ELIBMAX, + error.LIBEXEC => SystemErrno.ELIBEXEC, + error.ILSEQ => SystemErrno.EILSEQ, + error.RESTART => SystemErrno.ERESTART, + error.STRPIPE => SystemErrno.ESTRPIPE, + error.USERS => SystemErrno.EUSERS, + error.NOTSOCK => SystemErrno.ENOTSOCK, + error.DESTADDRREQ => SystemErrno.EDESTADDRREQ, + error.MSGSIZE => SystemErrno.EMSGSIZE, + error.PROTOTYPE => SystemErrno.EPROTOTYPE, + error.NOPROTOOPT => SystemErrno.ENOPROTOOPT, + error.PROTONOSUPPORT => SystemErrno.EPROTONOSUPPORT, + error.SOCKTNOSUPPORT => SystemErrno.ESOCKTNOSUPPORT, + error.NOTSUP => SystemErrno.ENOTSUP, + error.PFNOSUPPORT => SystemErrno.EPFNOSUPPORT, + error.AFNOSUPPORT => SystemErrno.EAFNOSUPPORT, + error.ADDRINUSE => SystemErrno.EADDRINUSE, + error.ADDRNOTAVAIL => SystemErrno.EADDRNOTAVAIL, + error.NETDOWN => SystemErrno.ENETDOWN, + error.NETUNREACH => SystemErrno.ENETUNREACH, + error.NETRESET => SystemErrno.ENETRESET, + error.CONNABORTED => SystemErrno.ECONNABORTED, + error.CONNRESET => SystemErrno.ECONNRESET, + error.NOBUFS => SystemErrno.ENOBUFS, + error.ISCONN => SystemErrno.EISCONN, + error.NOTCONN => SystemErrno.ENOTCONN, + error.SHUTDOWN => SystemErrno.ESHUTDOWN, + error.TOOMANYREFS => SystemErrno.ETOOMANYREFS, + error.TIMEDOUT => SystemErrno.ETIMEDOUT, + error.CONNREFUSED => SystemErrno.ECONNREFUSED, + error.HOSTDOWN => SystemErrno.EHOSTDOWN, + error.HOSTUNREACH => SystemErrno.EHOSTUNREACH, + error.ALREADY => SystemErrno.EALREADY, + error.INPROGRESS => SystemErrno.EINPROGRESS, + error.STALE => SystemErrno.ESTALE, + error.UCLEAN => SystemErrno.EUCLEAN, + error.NOTNAM => SystemErrno.ENOTNAM, + error.NAVAIL => SystemErrno.ENAVAIL, + error.ISNAM => SystemErrno.EISNAM, + error.REMOTEIO => SystemErrno.EREMOTEIO, + error.DQUOT => SystemErrno.EDQUOT, + error.NOMEDIUM => SystemErrno.ENOMEDIUM, + error.MEDIUMTYPE => SystemErrno.EMEDIUMTYPE, + error.CANCELED => SystemErrno.ECANCELED, + error.NOKEY => SystemErrno.ENOKEY, + error.KEYEXPIRED => SystemErrno.EKEYEXPIRED, + error.KEYREVOKED => SystemErrno.EKEYREVOKED, + error.KEYREJECTED => SystemErrno.EKEYREJECTED, + error.OWNERDEAD => SystemErrno.EOWNERDEAD, + error.NOTRECOVERABLE => SystemErrno.ENOTRECOVERABLE, + error.RFKILL => SystemErrno.ERFKILL, + error.HWPOISON => SystemErrno.EHWPOISON, + error.UNKNOWN => SystemErrno.EUNKNOWN, + error.CHARSET => SystemErrno.ECHARSET, + error.OF => SystemErrno.EOF, + else => return null, + }; + } + pub fn toError(this: SystemErrno) Error { + return error_map[@intFromEnum(this)]; + } + + pub fn init(code: anytype) ?SystemErrno { + if (comptime @TypeOf(code) == u16) { + if (code <= 3950) { + return init(@as(Win32Error, @enumFromInt(code))); + } else { + if (comptime bun.Environment.allow_assert) + bun.Output.debug("Unknown error code: {}\n", .{code}); + + return null; + } + } + + if (comptime @TypeOf(code) == Win32Error) { + return switch (code) { + Win32Error.NOACCESS => SystemErrno.EACCES, + @as(Win32Error, @enumFromInt(10013)) => SystemErrno.EACCES, + Win32Error.ELEVATION_REQUIRED => SystemErrno.EACCES, + Win32Error.CANT_ACCESS_FILE => SystemErrno.EACCES, + Win32Error.ADDRESS_ALREADY_ASSOCIATED => SystemErrno.EADDRINUSE, + Win32Error.WSAEADDRINUSE => SystemErrno.EADDRINUSE, + Win32Error.WSAEADDRNOTAVAIL => SystemErrno.EADDRNOTAVAIL, + Win32Error.WSAEAFNOSUPPORT => SystemErrno.EAFNOSUPPORT, + Win32Error.WSAEWOULDBLOCK => SystemErrno.EAGAIN, + Win32Error.WSAEALREADY => SystemErrno.EALREADY, + Win32Error.INVALID_FLAGS => SystemErrno.EBADF, + Win32Error.INVALID_HANDLE => SystemErrno.EBADF, + Win32Error.LOCK_VIOLATION => SystemErrno.EBUSY, + Win32Error.PIPE_BUSY => SystemErrno.EBUSY, + Win32Error.SHARING_VIOLATION => SystemErrno.EBUSY, + Win32Error.OPERATION_ABORTED => SystemErrno.ECANCELED, + Win32Error.WSAEINTR => SystemErrno.ECANCELED, + Win32Error.NO_UNICODE_TRANSLATION => SystemErrno.ECHARSET, + Win32Error.CONNECTION_ABORTED => SystemErrno.ECONNABORTED, + Win32Error.WSAECONNABORTED => SystemErrno.ECONNABORTED, + Win32Error.CONNECTION_REFUSED => SystemErrno.ECONNREFUSED, + Win32Error.WSAECONNREFUSED => SystemErrno.ECONNREFUSED, + Win32Error.NETNAME_DELETED => SystemErrno.ECONNRESET, + Win32Error.WSAECONNRESET => SystemErrno.ECONNRESET, + Win32Error.ALREADY_EXISTS => SystemErrno.EEXIST, + Win32Error.FILE_EXISTS => SystemErrno.EEXIST, + Win32Error.BUFFER_OVERFLOW => SystemErrno.EFAULT, + Win32Error.WSAEFAULT => SystemErrno.EFAULT, + Win32Error.HOST_UNREACHABLE => SystemErrno.EHOSTUNREACH, + Win32Error.WSAEHOSTUNREACH => SystemErrno.EHOSTUNREACH, + Win32Error.INSUFFICIENT_BUFFER => SystemErrno.EINVAL, + Win32Error.INVALID_DATA => SystemErrno.EINVAL, + Win32Error.INVALID_PARAMETER => SystemErrno.EINVAL, + Win32Error.SYMLINK_NOT_SUPPORTED => SystemErrno.EINVAL, + Win32Error.WSAEINVAL => SystemErrno.EINVAL, + Win32Error.WSAEPFNOSUPPORT => SystemErrno.EINVAL, + Win32Error.BEGINNING_OF_MEDIA => SystemErrno.EIO, + Win32Error.BUS_RESET => SystemErrno.EIO, + Win32Error.CRC => SystemErrno.EIO, + Win32Error.DEVICE_DOOR_OPEN => SystemErrno.EIO, + Win32Error.DEVICE_REQUIRES_CLEANING => SystemErrno.EIO, + Win32Error.DISK_CORRUPT => SystemErrno.EIO, + Win32Error.EOM_OVERFLOW => SystemErrno.EIO, + Win32Error.FILEMARK_DETECTED => SystemErrno.EIO, + Win32Error.GEN_FAILURE => SystemErrno.EIO, + Win32Error.INVALID_BLOCK_LENGTH => SystemErrno.EIO, + Win32Error.IO_DEVICE => SystemErrno.EIO, + Win32Error.NO_DATA_DETECTED => SystemErrno.EIO, + Win32Error.NO_SIGNAL_SENT => SystemErrno.EIO, + Win32Error.OPEN_FAILED => SystemErrno.EIO, + Win32Error.SETMARK_DETECTED => SystemErrno.EIO, + Win32Error.SIGNAL_REFUSED => SystemErrno.EIO, + Win32Error.WSAEISCONN => SystemErrno.EISCONN, + Win32Error.CANT_RESOLVE_FILENAME => SystemErrno.ELOOP, + Win32Error.TOO_MANY_OPEN_FILES => SystemErrno.EMFILE, + Win32Error.WSAEMFILE => SystemErrno.EMFILE, + Win32Error.WSAEMSGSIZE => SystemErrno.EMSGSIZE, + Win32Error.FILENAME_EXCED_RANGE => SystemErrno.ENAMETOOLONG, + Win32Error.NETWORK_UNREACHABLE => SystemErrno.ENETUNREACH, + Win32Error.WSAENETUNREACH => SystemErrno.ENETUNREACH, + Win32Error.WSAENOBUFS => SystemErrno.ENOBUFS, + Win32Error.BAD_PATHNAME => SystemErrno.ENOENT, + Win32Error.DIRECTORY => SystemErrno.ENOENT, + Win32Error.ENVVAR_NOT_FOUND => SystemErrno.ENOENT, + Win32Error.FILE_NOT_FOUND => SystemErrno.ENOENT, + Win32Error.INVALID_NAME => SystemErrno.ENOENT, + Win32Error.INVALID_DRIVE => SystemErrno.ENOENT, + Win32Error.INVALID_REPARSE_DATA => SystemErrno.ENOENT, + Win32Error.MOD_NOT_FOUND => SystemErrno.ENOENT, + Win32Error.PATH_NOT_FOUND => SystemErrno.ENOENT, + Win32Error.WSAHOST_NOT_FOUND => SystemErrno.ENOENT, + Win32Error.WSANO_DATA => SystemErrno.ENOENT, + Win32Error.NOT_ENOUGH_MEMORY => SystemErrno.ENOMEM, + Win32Error.OUTOFMEMORY => SystemErrno.ENOMEM, + Win32Error.CANNOT_MAKE => SystemErrno.ENOSPC, + Win32Error.DISK_FULL => SystemErrno.ENOSPC, + Win32Error.EA_TABLE_FULL => SystemErrno.ENOSPC, + Win32Error.END_OF_MEDIA => SystemErrno.ENOSPC, + Win32Error.HANDLE_DISK_FULL => SystemErrno.ENOSPC, + Win32Error.NOT_CONNECTED => SystemErrno.ENOTCONN, + Win32Error.WSAENOTCONN => SystemErrno.ENOTCONN, + Win32Error.DIR_NOT_EMPTY => SystemErrno.ENOTEMPTY, + Win32Error.WSAENOTSOCK => SystemErrno.ENOTSOCK, + Win32Error.NOT_SUPPORTED => SystemErrno.ENOTSUP, + Win32Error.BROKEN_PIPE => SystemErrno.EOF, + Win32Error.ACCESS_DENIED => SystemErrno.EPERM, + Win32Error.PRIVILEGE_NOT_HELD => SystemErrno.EPERM, + Win32Error.BAD_PIPE => SystemErrno.EPIPE, + Win32Error.NO_DATA => SystemErrno.EPIPE, + Win32Error.PIPE_NOT_CONNECTED => SystemErrno.EPIPE, + Win32Error.WSAESHUTDOWN => SystemErrno.EPIPE, + Win32Error.WSAEPROTONOSUPPORT => SystemErrno.EPROTONOSUPPORT, + Win32Error.WRITE_PROTECT => SystemErrno.EROFS, + Win32Error.SEM_TIMEOUT => SystemErrno.ETIMEDOUT, + Win32Error.WSAETIMEDOUT => SystemErrno.ETIMEDOUT, + Win32Error.NOT_SAME_DEVICE => SystemErrno.EXDEV, + Win32Error.INVALID_FUNCTION => SystemErrno.EISDIR, + Win32Error.META_EXPANSION_TOO_LONG => SystemErrno.E2BIG, + Win32Error.WSAESOCKTNOSUPPORT => SystemErrno.ESOCKTNOSUPPORT, + Win32Error.DELETE_PENDING => SystemErrno.EBUSY, + else => return null, + }; + } + + if (comptime std.meta.trait.isSignedInt(@TypeOf(code))) { + if (code < 0) + return init(-code); + } + + if (code >= max) return null; + return @as(SystemErrno, @enumFromInt(code)); + } + + pub fn label(this: SystemErrno) ?[]const u8 { + return labels.get(this) orelse null; + } + + const LabelMap = std.EnumMap(SystemErrno, []const u8); + pub const labels: LabelMap = brk: { + var map: LabelMap = LabelMap.initFull(""); + + map.put(.EPERM, "Operation not permitted"); + map.put(.ENOENT, "No such file or directory"); + map.put(.ESRCH, "No such process"); + map.put(.EINTR, "Interrupted system call"); + map.put(.EIO, "I/O error"); + map.put(.ENXIO, "No such device or address"); + map.put(.E2BIG, "Argument list too long"); + map.put(.ENOEXEC, "Exec format error"); + map.put(.EBADF, "Bad file number"); + map.put(.ECHILD, "No child processes"); + map.put(.EAGAIN, "Try again"); + map.put(.EOF, "End of file"); + map.put(.ENOMEM, "Out of memory"); + map.put(.EACCES, "Permission denied"); + map.put(.EFAULT, "Bad address"); + map.put(.ENOTBLK, "Block device required"); + map.put(.EBUSY, "Device or resource busy"); + map.put(.EEXIST, "File or folder exists"); + map.put(.EXDEV, "Cross-device link"); + map.put(.ENODEV, "No such device"); + map.put(.ENOTDIR, "Not a directory"); + map.put(.EISDIR, "Is a directory"); + map.put(.EINVAL, "Invalid argument"); + map.put(.ENFILE, "File table overflow"); + map.put(.EMFILE, "Too many open files"); + map.put(.ECHARSET, "Invalid or incomplete multibyte or wide character"); + map.put(.ENOTTY, "Not a typewriter"); + map.put(.ETXTBSY, "Text file busy"); + map.put(.EFBIG, "File too large"); + map.put(.ENOSPC, "No space left on device"); + map.put(.ESPIPE, "Illegal seek"); + map.put(.EROFS, "Read-only file system"); + map.put(.EMLINK, "Too many links"); + map.put(.EPIPE, "Broken pipe"); + map.put(.EDOM, "Math argument out of domain of func"); + map.put(.ERANGE, "Math result not representable"); + map.put(.EDEADLK, "Resource deadlock would occur"); + map.put(.ENAMETOOLONG, "File name too long"); + map.put(.ENOLCK, "No record locks available"); + map.put(.EUNKNOWN, "An unknown error occurred"); + map.put(.ENOSYS, "Function not implemented"); + map.put(.ENOTEMPTY, "Directory not empty"); + map.put(.ELOOP, "Too many symbolic links encountered"); + map.put(.ENOMSG, "No message of desired type"); + map.put(.EIDRM, "Identifier removed"); + map.put(.ECHRNG, "Channel number out of range"); + map.put(.EL2NSYNC, "Level 2 not synchronized"); + map.put(.EL3HLT, "Level 3 halted"); + map.put(.EL3RST, "Level 3 reset"); + map.put(.ELNRNG, "Link number out of range"); + map.put(.EUNATCH, "Protocol driver not attached"); + map.put(.ENOCSI, "No CSI structure available"); + map.put(.EL2HLT, "Level 2 halted"); + map.put(.EBADE, "Invalid exchange"); + map.put(.EBADR, "Invalid request descriptor"); + map.put(.EXFULL, "Exchange full"); + map.put(.ENOANO, "No anode"); + map.put(.EBADRQC, "Invalid request code"); + map.put(.EBADSLT, "Invalid slot"); + map.put(.EBFONT, "Bad font file format"); + map.put(.ENOSTR, "Device not a stream"); + map.put(.ENODATA, "No data available"); + map.put(.ETIME, "Timer expired"); + map.put(.ENOSR, "Out of streams resources"); + map.put(.ENONET, "Machine is not on the network"); + map.put(.ENOPKG, "Package not installed"); + map.put(.EREMOTE, "Object is remote"); + map.put(.ENOLINK, "Link has been severed"); + map.put(.EADV, "Advertise error"); + map.put(.ESRMNT, "Srmount error"); + map.put(.ECOMM, "Communication error on send"); + map.put(.EPROTO, "Protocol error"); + map.put(.EMULTIHOP, "Multihop attempted"); + map.put(.EDOTDOT, "RFS specific error"); + map.put(.EBADMSG, "Not a data message"); + map.put(.EOVERFLOW, "Value too large for defined data type"); + map.put(.ENOTUNIQ, "Name not unique on network"); + map.put(.EBADFD, "File descriptor in bad state"); + map.put(.EREMCHG, "Remote address changed"); + map.put(.ELIBACC, "Can not access a needed shared library"); + map.put(.ELIBBAD, "Accessing a corrupted shared library"); + map.put(.ELIBSCN, "lib section in a.out corrupted"); + map.put(.ELIBMAX, "Attempting to link in too many shared libraries"); + map.put(.ELIBEXEC, "Cannot exec a shared library directly"); + map.put(.EILSEQ, "Illegal byte sequence"); + map.put(.ERESTART, "Interrupted system call should be restarted"); + map.put(.ESTRPIPE, "Streams pipe error"); + map.put(.EUSERS, "Too many users"); + map.put(.ENOTSOCK, "Socket operation on non-socket"); + map.put(.EDESTADDRREQ, "Destination address required"); + map.put(.EMSGSIZE, "Message too long"); + map.put(.EPROTOTYPE, "Protocol wrong type for socket"); + map.put(.ENOPROTOOPT, "Protocol not available"); + map.put(.EPROTONOSUPPORT, "Protocol not supported"); + map.put(.ESOCKTNOSUPPORT, "Socket type not supported"); + map.put(.ENOTSUP, "Operation not supported on transport endpoint"); + map.put(.EPFNOSUPPORT, "Protocol family not supported"); + map.put(.EAFNOSUPPORT, "Address family not supported by protocol"); + map.put(.EADDRINUSE, "Address already in use"); + map.put(.EADDRNOTAVAIL, "Cannot assign requested address"); + map.put(.ENETDOWN, "Network is down"); + map.put(.ENETUNREACH, "Network is unreachable"); + map.put(.ENETRESET, "Network dropped connection because of reset"); + map.put(.ECONNABORTED, "Software caused connection abort"); + map.put(.ECONNRESET, "Connection reset by peer"); + map.put(.ENOBUFS, "No buffer space available"); + map.put(.EISCONN, "Transport endpoint is already connected"); + map.put(.ENOTCONN, "Transport endpoint is not connected"); + map.put(.ESHUTDOWN, "Cannot send after transport endpoint shutdown"); + map.put(.ETOOMANYREFS, "Too many references: cannot splice"); + map.put(.ETIMEDOUT, "Connection timed out"); + map.put(.ECONNREFUSED, "Connection refused"); + map.put(.EHOSTDOWN, "Host is down"); + map.put(.EHOSTUNREACH, "No route to host"); + map.put(.EALREADY, "Operation already in progress"); + map.put(.EINPROGRESS, "Operation now in progress"); + map.put(.ESTALE, "Stale NFS file handle"); + map.put(.EUCLEAN, "Structure needs cleaning"); + map.put(.ENOTNAM, "Not a XENIX named type file"); + map.put(.ENAVAIL, "No XENIX semaphores available"); + map.put(.EISNAM, "Is a named type file"); + map.put(.EREMOTEIO, "Remote I/O error"); + map.put(.EDQUOT, "Quota exceeded"); + map.put(.ENOMEDIUM, "No medium found"); + map.put(.EMEDIUMTYPE, "Wrong medium type"); + map.put(.ECANCELED, "Operation Canceled"); + map.put(.ENOKEY, "Required key not available"); + map.put(.EKEYEXPIRED, "Key has expired"); + map.put(.EKEYREVOKED, "Key has been revoked"); + map.put(.EKEYREJECTED, "Key was rejected by service"); + map.put(.EOWNERDEAD, "Owner died"); + map.put(.ENOTRECOVERABLE, "State not recoverable"); + break :brk map; + }; +}; + +pub const off_t = i64; +pub fn preallocate_file(_: os.fd_t, _: off_t, _: off_t) !void {} + +pub const E = enum(u8) { + SUCCESS = 0, + PERM = 1, + NOENT = 2, + SRCH = 3, + INTR = 4, + IO = 5, + NXIO = 6, + @"2BIG" = 7, + NOEXEC = 8, + BADF = 9, + CHILD = 10, + AGAIN = 11, + NOMEM = 12, + ACCES = 13, + FAULT = 14, + NOTBLK = 15, + BUSY = 16, + EXIST = 17, + XDEV = 18, + NODEV = 19, + NOTDIR = 20, + ISDIR = 21, + INVAL = 22, + NFILE = 23, + MFILE = 24, + NOTTY = 25, + TXTBSY = 26, + FBIG = 27, + NOSPC = 28, + SPIPE = 29, + ROFS = 30, + MLINK = 31, + PIPE = 32, + DOM = 33, + RANGE = 34, + DEADLK = 35, + NAMETOOLONG = 36, + NOLCK = 37, + NOSYS = 38, + NOTEMPTY = 39, + LOOP = 40, + WOULDBLOCK = 41, + NOMSG = 42, + IDRM = 43, + CHRNG = 44, + L2NSYNC = 45, + L3HLT = 46, + L3RST = 47, + LNRNG = 48, + UNATCH = 49, + NOCSI = 50, + L2HLT = 51, + BADE = 52, + BADR = 53, + XFULL = 54, + NOANO = 55, + BADRQC = 56, + BADSLT = 57, + DEADLOCK = 58, + BFONT = 59, + NOSTR = 60, + NODATA = 61, + TIME = 62, + NOSR = 63, + NONET = 64, + NOPKG = 65, + REMOTE = 66, + NOLINK = 67, + ADV = 68, + SRMNT = 69, + COMM = 70, + PROTO = 71, + MULTIHOP = 72, + DOTDOT = 73, + BADMSG = 74, + OVERFLOW = 75, + NOTUNIQ = 76, + BADFD = 77, + REMCHG = 78, + LIBACC = 79, + LIBBAD = 80, + LIBSCN = 81, + LIBMAX = 82, + LIBEXEC = 83, + ILSEQ = 84, + RESTART = 85, + STRPIPE = 86, + USERS = 87, + NOTSOCK = 88, + DESTADDRREQ = 89, + MSGSIZE = 90, + PROTOTYPE = 91, + NOPROTOOPT = 92, + PROTONOSUPPORT = 93, + SOCKTNOSUPPORT = 94, + NOTSUP = 95, + PFNOSUPPORT = 96, + AFNOSUPPORT = 97, + ADDRINUSE = 98, + ADDRNOTAVAIL = 99, + NETDOWN = 100, + NETUNREACH = 101, + NETRESET = 102, + CONNABORTED = 103, + CONNRESET = 104, + NOBUFS = 105, + ISCONN = 106, + NOTCONN = 107, + SHUTDOWN = 108, + TOOMANYREFS = 109, + TIMEDOUT = 110, + CONNREFUSED = 111, + HOSTDOWN = 112, + HOSTUNREACH = 113, + ALREADY = 114, + INPROGRESS = 115, + STALE = 116, + UCLEAN = 117, + NOTNAM = 118, + NAVAIL = 119, + ISNAM = 120, + REMOTEIO = 121, + DQUOT = 122, + NOMEDIUM = 123, + MEDIUMTYPE = 124, + CANCELED = 125, + NOKEY = 126, + KEYEXPIRED = 127, + KEYREVOKED = 128, + KEYREJECTED = 129, + OWNERDEAD = 130, + NOTRECOVERABLE = 131, + RFKILL = 132, + HWPOISON = 133, + UNKNOWN = 134, + CHARSET = 135, + OF = 136, +}; + +pub fn getErrno(_: anytype) E { + if (Win32Error.get().toSystemErrno()) |sys| { + return sys.toE(); + } + + return .SUCCESS; +} |