embrace translate-c more, remove some more usingnamespace

This commit is contained in:
chloe caruso
2025-04-15 12:20:17 -07:00
parent be77711a4e
commit ec9d7091c0
24 changed files with 551 additions and 453 deletions

View File

@@ -4,7 +4,7 @@ const builtin = @import("builtin");
const Build = std.Build;
const Step = Build.Step;
const Compile = Step.Compile;
const LazyPath = Step.LazyPath;
const LazyPath = Build.LazyPath;
const Target = std.Target;
const ResolvedTarget = std.Build.ResolvedTarget;
const CrossTarget = std.zig.CrossTarget;
@@ -388,7 +388,22 @@ pub fn build(b: *Build) !void {
// zig build translate-c-headers
{
const step = b.step("translate-c", "Copy generated translated-c-headers.zig to zig-out");
step.dependOn(&b.addInstallFile(getTranslateC(b, b.graph.host, .Debug).getOutput(), "translated-c-headers.zig").step);
for ([_]TargetDescription{
.{ .os = .windows, .arch = .x86_64 },
.{ .os = .mac, .arch = .x86_64 },
.{ .os = .mac, .arch = .aarch64 },
.{ .os = .linux, .arch = .x86_64 },
.{ .os = .linux, .arch = .aarch64 },
.{ .os = .linux, .arch = .x86_64, .musl = true },
.{ .os = .linux, .arch = .aarch64, .musl = true },
}) |t| {
const resolved = t.resolveTarget(b);
step.dependOn(
&b.addInstallFile(getTranslateC(b, resolved, .Debug), b.fmt("translated-c-headers/{s}.zig", .{
resolved.result.zigTriple(b.allocator) catch @panic("OOM"),
})).step,
);
}
}
// zig build enum-extractor
@@ -405,23 +420,32 @@ pub fn build(b: *Build) !void {
}
}
pub fn addMultiCheck(
const TargetDescription = struct {
os: OperatingSystem,
arch: Arch,
musl: bool = false,
fn resolveTarget(desc: TargetDescription, b: *Build) std.Build.ResolvedTarget {
return b.resolveTargetQuery(.{
.os_tag = OperatingSystem.stdOSTag(desc.os),
.cpu_arch = desc.arch,
.cpu_model = getCpuModel(desc.os, desc.arch) orelse .determined_by_arch_os,
.os_version_min = getOSVersionMin(desc.os),
.glibc_version = if (desc.musl) null else getOSGlibCVersion(desc.os),
});
}
};
fn addMultiCheck(
b: *Build,
parent_step: *Step,
root_build_options: BunBuildOptions,
to_check: []const struct { os: OperatingSystem, arch: Arch, musl: bool = false },
to_check: []const TargetDescription,
optimize: []const std.builtin.OptimizeMode,
) void {
for (to_check) |check| {
for (optimize) |mode| {
const check_target = b.resolveTargetQuery(.{
.os_tag = OperatingSystem.stdOSTag(check.os),
.cpu_arch = check.arch,
.cpu_model = getCpuModel(check.os, check.arch) orelse .determined_by_arch_os,
.os_version_min = getOSVersionMin(check.os),
.glibc_version = if (check.musl) null else getOSGlibCVersion(check.os),
});
const check_target = check.resolveTarget(b);
var options: BunBuildOptions = .{
.target = check_target,
.os = check.os,
@@ -445,7 +469,7 @@ pub fn addMultiCheck(
}
}
fn getTranslateC(b: *Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *Step.TranslateC {
fn getTranslateC(b: *Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) LazyPath {
const translate_c = b.addTranslateC(.{
.root_source_file = b.path("src/c-headers-for-zig.h"),
.target = target,
@@ -461,7 +485,35 @@ fn getTranslateC(b: *Build, target: std.Build.ResolvedTarget, optimize: std.buil
const str, const value = entry;
translate_c.defineCMacroRaw(b.fmt("{s}={d}", .{ str, @intFromBool(value) }));
}
return translate_c;
if (target.result.os.tag == .windows) {
// translate-c is unable to translate the unsuffixed windows functions
// like `SetCurrentDirectory` since they are defined with an odd macro
// that translate-c doesn't handle.
//
// #define SetCurrentDirectory __MINGW_NAME_AW(SetCurrentDirectory)
//
// In these cases, it's better to just reference the underlying function
// directly: SetCurrentDirectoryW. To make the error better, a post
// processing step is applied to the translate-c file.
//
// Additionally, this step makes it so that decls like NTSTATUS and
// HANDLE point to the standard library structures.
const helper_exe = b.addExecutable(.{
.name = "process_windows_translate_c",
.root_module = b.createModule(.{
.root_source_file = b.path("src/codegen/process_windows_translate_c.zig"),
.target = b.graph.host,
.optimize = .Debug,
}),
});
const in = translate_c.getOutput();
const run = b.addRunArtifact(helper_exe);
run.addFileArg(in);
const out = run.addOutputFileArg("c-headers-for-zig.zig");
return out;
}
return translate_c.getOutput();
}
pub fn addBunObject(b: *Build, opts: *BunBuildOptions) *Compile {
@@ -526,7 +578,7 @@ fn configureObj(b: *Build, opts: *BunBuildOptions, obj: *Compile) void {
obj.root_module.addImport("build_options", opts.buildOptionsModule(b));
const translate_c = getTranslateC(b, opts.target, opts.optimize);
obj.root_module.addImport("translated-c-headers", translate_c.createModule());
obj.root_module.addImport("translated-c-headers", b.createModule(.{ .root_source_file = translate_c }));
}
const ObjectFormat = enum {

View File

@@ -61,7 +61,6 @@ zig_keywords = {
'try',
'union',
'unreachable',
'usingnamespace',
'var',
'volatile',
'while',

View File

@@ -1,9 +1,6 @@
const bun = @import("root").bun;
const std = @import("std");
pub const c = struct {
pub usingnamespace @import("./deps/brotli_decoder.zig");
pub usingnamespace @import("./deps/brotli_encoder.zig");
};
pub const c = @import("./deps/brotli_c.zig");
const BrotliDecoder = c.BrotliDecoder;
const BrotliEncoder = c.BrotliEncoder;

View File

@@ -2706,10 +2706,10 @@ const LifecycleScriptSubprocess = bun.install.LifecycleScriptSubprocess;
const Body = JSC.WebCore.Body;
const IPClog = Output.scoped(.IPC, false);
const PosixSpawn = bun.posix.spawn;
const Rusage = bun.posix.spawn.Rusage;
const Process = bun.posix.spawn.Process;
const WaiterThread = bun.posix.spawn.WaiterThread;
const PosixSpawn = bun.spawn;
const Rusage = bun.spawn.Rusage;
const Process = bun.spawn.Process;
const WaiterThread = bun.spawn.WaiterThread;
const Stdio = bun.spawn.Stdio;
const StdioResult = if (Environment.isWindows) bun.spawn.WindowsSpawnResult.StdioResult else ?bun.FileDescriptor;

View File

@@ -373,7 +373,7 @@ pub fn onJSCInvalidEnvVar(name: [*]const u8, len: usize) callconv(.C) void {
/// broke when I just used it. Not sure. ... but this works!
fn @"windows process.dlopen"(str: *bun.String) callconv(.C) ?*anyopaque {
if (comptime !bun.Environment.isWindows) {
unreachable;
@compileError(unreachable);
}
var buf: bun.WPathBuffer = undefined;
@@ -390,7 +390,7 @@ fn @"windows process.dlopen"(str: *bun.String) callconv(.C) ?*anyopaque {
};
buf[data.len] = 0;
const LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008;
return bun.windows.LoadLibraryExW(buf[0..data.len :0].ptr, null, LOAD_WITH_ALTERED_SEARCH_PATH);
return bun.windows.kernel32.LoadLibraryExW(buf[0..data.len :0].ptr, null, LOAD_WITH_ALTERED_SEARCH_PATH);
}
comptime {

View File

@@ -5,6 +5,7 @@ const std = @import("std");
const bun = @import("root").bun;
const strings = bun.strings;
const windows = bun.windows;
const c = bun.c;
const string = bun.string;
const JSC = bun.JSC;
const PathString = JSC.PathString;
@@ -761,8 +762,8 @@ pub fn NewAsyncCpTask(comptime is_shell: bool) type {
const dest = args.dest.osPath(&dest_buf);
if (Environment.isWindows) {
const attributes = windows.GetFileAttributesW(src);
if (attributes == windows.INVALID_FILE_ATTRIBUTES) {
const attributes = c.GetFileAttributesW(src);
if (attributes == c.INVALID_FILE_ATTRIBUTES) {
this.finishConcurrently(.{ .err = .{
.errno = @intFromEnum(C.SystemErrno.ENOENT),
.syscall = .copyfile,
@@ -770,7 +771,7 @@ pub fn NewAsyncCpTask(comptime is_shell: bool) type {
} });
return;
}
const file_or_symlink = (attributes & windows.FILE_ATTRIBUTE_DIRECTORY) == 0 or (attributes & windows.FILE_ATTRIBUTE_REPARSE_POINT) != 0;
const file_or_symlink = (attributes & c.FILE_ATTRIBUTE_DIRECTORY) == 0 or (attributes & c.FILE_ATTRIBUTE_REPARSE_POINT) != 0;
if (file_or_symlink) {
const r = nodefs._copySingleFileSync(
src,
@@ -3990,15 +3991,6 @@ pub const NodeFS = struct {
mode: Mode,
comptime return_path: bool,
) Maybe(Return.Mkdir) {
const callbacks = struct {
pub fn onCreateDir(c: Ctx, dirpath: bun.OSPathSliceZ) void {
if (Ctx != void) {
c.onCreateDir(dirpath);
}
return;
}
};
const Char = bun.OSPathChar;
const len: u16 = @truncate(path.len);
@@ -4042,7 +4034,7 @@ pub const NodeFS = struct {
}
},
.result => {
callbacks.onCreateDir(ctx, path);
if (Ctx != void) ctx.onCreateDir(path);
if (!return_path) {
return .{ .result = .{ .none = {} } };
}
@@ -4084,7 +4076,7 @@ pub const NodeFS = struct {
}
},
.result => {
callbacks.onCreateDir(ctx, parent);
if (Ctx != void) ctx.onCreateDir(parent);
// We found a parent that worked
working_mem[i] = std.fs.path.sep;
break;
@@ -4115,7 +4107,7 @@ pub const NodeFS = struct {
},
.result => {
callbacks.onCreateDir(ctx, parent);
if (Ctx != void) ctx.onCreateDir(parent);
working_mem[i] = std.fs.path.sep;
},
}
@@ -4141,7 +4133,7 @@ pub const NodeFS = struct {
.result => {},
}
callbacks.onCreateDir(ctx, working_mem[0..len :0]);
if (Ctx != void) ctx.onCreateDir(working_mem[0..len :0]);
if (!return_path) {
return .{ .result = .{ .none = {} } };
}
@@ -6048,8 +6040,8 @@ pub const NodeFS = struct {
const dest = dest_buf[0..dest_dir_len :0];
if (Environment.isWindows) {
const attributes = windows.GetFileAttributesW(src);
if (attributes == windows.INVALID_FILE_ATTRIBUTES) {
const attributes = bun.c.GetFileAttributesW(src);
if (attributes == bun.c.INVALID_FILE_ATTRIBUTES) {
return .{ .err = .{
.errno = @intFromEnum(C.SystemErrno.ENOENT),
.syscall = .copyfile,
@@ -6057,7 +6049,7 @@ pub const NodeFS = struct {
} };
}
if ((attributes & windows.FILE_ATTRIBUTE_DIRECTORY) == 0) {
if ((attributes & bun.c.FILE_ATTRIBUTE_DIRECTORY) == 0) {
const r = this._copySingleFileSync(
src,
dest,
@@ -6509,12 +6501,12 @@ pub const NodeFS = struct {
if (Environment.isWindows) {
const src_enoent_maybe = ret.initErrWithP(.ENOENT, .copyfile, this.osPathIntoSyncErrorBuf(src));
const dst_enoent_maybe = ret.initErrWithP(.ENOENT, .copyfile, this.osPathIntoSyncErrorBuf(dest));
const stat_ = reuse_stat orelse switch (windows.GetFileAttributesW(src)) {
windows.INVALID_FILE_ATTRIBUTES => return ret.errnoSysP(0, .copyfile, this.osPathIntoSyncErrorBuf(src)).?,
const stat_ = reuse_stat orelse switch (bun.c.GetFileAttributesW(src)) {
bun.c.INVALID_FILE_ATTRIBUTES => return ret.errnoSysP(0, .copyfile, this.osPathIntoSyncErrorBuf(src)).?,
else => |result| result,
};
if (stat_ & windows.FILE_ATTRIBUTE_REPARSE_POINT == 0) {
if (windows.CopyFileW(src, dest, @intFromBool(mode.shouldntOverwrite())) == 0) {
if (stat_ & bun.c.FILE_ATTRIBUTE_REPARSE_POINT == 0) {
if (bun.c.CopyFileW(src, dest, @intFromBool(mode.shouldntOverwrite())) == 0) {
var err = windows.GetLastError();
var errpath: bun.OSPathSliceZ = undefined;
switch (err) {

View File

@@ -1928,7 +1928,7 @@ pub const Process = struct {
buf2[len2] = 0;
break :str buf2[0..len2 :0].ptr;
} else null;
_ = bun.windows.SetEnvironmentVariableW(buf1[0..len1 :0].ptr, str2);
_ = bun.c.SetEnvironmentVariableW(buf1[0..len1 :0].ptr, str2);
}
comptime {

View File

@@ -16,6 +16,7 @@ pub const AbortSignal = @import("./bindings/bindings.zig").AbortSignal;
pub const JSValue = @import("./bindings/bindings.zig").JSValue;
const Environment = bun.Environment;
const UUID7 = @import("./uuid.zig").UUID7;
const c = bun.c;
pub const Lifetime = enum {
clone,
@@ -268,11 +269,11 @@ pub const Prompt = struct {
// unset `ENABLE_VIRTUAL_TERMINAL_INPUT` on windows. This prevents backspace from
// deleting the entire line
const original_mode: if (Environment.isWindows) ?bun.windows.DWORD else void = if (comptime Environment.isWindows)
bun.win32.updateStdioModeFlags(.std_in, .{ .unset = bun.windows.ENABLE_VIRTUAL_TERMINAL_INPUT }) catch null;
bun.windows.updateStdioModeFlags(.std_in, .{ .unset = c.ENABLE_VIRTUAL_TERMINAL_INPUT }) catch null;
defer if (comptime Environment.isWindows) {
if (original_mode) |mode| {
_ = bun.windows.SetConsoleMode(bun.FD.stdin().native(), mode);
_ = bun.c.SetConsoleMode(bun.FD.stdin().native(), mode);
}
};

View File

@@ -1547,7 +1547,7 @@ pub fn reloadProcess(
if (comptime Environment.isWindows) {
// on windows we assume that we have a parent process that is monitoring us and will restart us if we exit with a magic exit code
// see becomeWatcherManager
const rc = bun.windows.TerminateProcess(bun.windows.GetCurrentProcess(), win32.watcher_reload_exit);
const rc = c.TerminateProcess(c.GetCurrentProcess(), windows.watcher_reload_exit);
if (rc == 0) {
const err = bun.windows.GetLastError();
if (may_return) {
@@ -1564,7 +1564,6 @@ pub fn reloadProcess(
}
}
const PosixSpawn = posix.spawn;
const dupe_argv = allocator.allocSentinel(?[*:0]const u8, bun.argv.len, null) catch unreachable;
for (bun.argv, dupe_argv) |src, *dest| {
dest.* = (allocator.dupeZ(u8, src) catch unreachable).ptr;
@@ -1591,24 +1590,24 @@ pub fn reloadProcess(
// macOS doesn't have CLOEXEC, so we must go through posix_spawn
if (comptime Environment.isMac) {
var actions = PosixSpawn.Actions.init() catch unreachable;
var actions = spawn.Actions.init() catch unreachable;
actions.inherit(.stdin()) catch unreachable;
actions.inherit(.stdout()) catch unreachable;
actions.inherit(.stderr()) catch unreachable;
var attrs = PosixSpawn.Attr.init() catch unreachable;
var attrs = spawn.Attr.init() catch unreachable;
attrs.resetSignals() catch {};
attrs.set(
C.translated.POSIX_SPAWN_CLOEXEC_DEFAULT |
c.POSIX_SPAWN_CLOEXEC_DEFAULT |
// Apple Extension: If this bit is set, rather
// than returning to the caller, posix_spawn(2)
// and posix_spawnp(2) will behave as a more
// featureful execve(2).
C.translated.POSIX_SPAWN_SETEXEC |
C.translated.POSIX_SPAWN_SETSIGDEF | C.translated.POSIX_SPAWN_SETSIGMASK,
c.POSIX_SPAWN_SETEXEC |
c.POSIX_SPAWN_SETSIGDEF | c.POSIX_SPAWN_SETSIGMASK,
) catch unreachable;
switch (PosixSpawn.spawnZ(exec_path, actions, attrs, @as([*:null]?[*:0]const u8, @ptrCast(newargv)), @as([*:null]?[*:0]const u8, @ptrCast(envp)))) {
switch (spawn.spawnZ(exec_path, actions, attrs, @as([*:null]?[*:0]const u8, @ptrCast(newargv)), @as([*:null]?[*:0]const u8, @ptrCast(envp)))) {
.err => |err| {
if (may_return) {
Output.errGeneric("Failed to reload process: {s}", .{@tagName(err.getErrno())});
@@ -1931,8 +1930,8 @@ const WindowsStat = extern struct {
pub const Stat = if (Environment.isWindows) windows.libuv.uv_stat_t else std.posix.Stat;
pub const StatFS = switch (Environment.os) {
.mac => C.translated.struct_statfs,
.linux => C.translated.struct_statfs,
.mac => bun.c.struct_statfs,
.linux => bun.c.struct_statfs,
else => windows.libuv.uv_statfs_t,
};
@@ -1999,201 +1998,7 @@ pub fn initArgv(allocator: std.mem.Allocator) !void {
}
}
pub const posix = struct {
pub const spawn = @import("./bun.js/api/bun/spawn.zig").PosixSpawn;
};
pub const win32 = struct {
const w = std.os.windows;
/// Returns the original mode, or null on failure
pub fn updateStdioModeFlags(i: bun.FD.Stdio, opts: struct { set: w.DWORD = 0, unset: w.DWORD = 0 }) !w.DWORD {
const fd = i.fd();
var original_mode: w.DWORD = 0;
if (windows.GetConsoleMode(fd.cast(), &original_mode) != 0) {
if (windows.SetConsoleMode(fd.cast(), (original_mode | opts.set) & ~opts.unset) == 0) {
return windows.getLastError();
}
} else return windows.getLastError();
return original_mode;
}
const watcherChildEnv: [:0]const u16 = strings.toUTF16Literal("_BUN_WATCHER_CHILD");
// magic exit code to indicate to the watcher manager that the child process should be re-spawned
// this was randomly generated - we need to avoid using a common exit code that might be used by the script itself
const watcher_reload_exit: w.DWORD = 3224497970;
pub const spawn = @import("./bun.js/api/bun/spawn.zig").PosixSpawn;
pub fn isWatcherChild() bool {
var buf: [1]u16 = undefined;
return windows.GetEnvironmentVariableW(@constCast(watcherChildEnv.ptr), &buf, 1) > 0;
}
pub fn becomeWatcherManager(allocator: std.mem.Allocator) noreturn {
// this process will be the parent of the child process that actually runs the script
var procinfo: std.os.windows.PROCESS_INFORMATION = undefined;
C.windows_enable_stdio_inheritance();
const job = windows.CreateJobObjectA(null, null) orelse Output.panic(
"Could not create watcher Job Object: {s}",
.{@tagName(std.os.windows.kernel32.GetLastError())},
);
var jeli = std.mem.zeroes(windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION);
jeli.BasicLimitInformation.LimitFlags =
windows.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE |
windows.JOB_OBJECT_LIMIT_BREAKAWAY_OK |
windows.JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK |
windows.JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION;
if (windows.SetInformationJobObject(
job,
windows.JobObjectExtendedLimitInformation,
&jeli,
@sizeOf(windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION),
) == 0) {
Output.panic(
"Could not configure watcher Job Object: {s}",
.{@tagName(std.os.windows.kernel32.GetLastError())},
);
}
while (true) {
spawnWatcherChild(allocator, &procinfo, job) catch |err| {
handleErrorReturnTrace(err, @errorReturnTrace());
if (err == error.Win32Error) {
Output.panic("Failed to spawn process: {s}\n", .{@tagName(std.os.windows.kernel32.GetLastError())});
}
Output.panic("Failed to spawn process: {s}\n", .{@errorName(err)});
};
w.WaitForSingleObject(procinfo.hProcess, w.INFINITE) catch |err| {
Output.panic("Failed to wait for child process: {s}\n", .{@errorName(err)});
};
var exit_code: w.DWORD = 0;
if (w.kernel32.GetExitCodeProcess(procinfo.hProcess, &exit_code) == 0) {
const err = windows.GetLastError();
_ = std.os.windows.ntdll.NtClose(procinfo.hProcess);
Output.panic("Failed to get exit code of child process: {s}\n", .{@tagName(err)});
}
_ = std.os.windows.ntdll.NtClose(procinfo.hProcess);
// magic exit code to indicate that the child process should be re-spawned
if (exit_code == watcher_reload_exit) {
continue;
} else {
Global.exit(exit_code);
}
}
}
pub fn spawnWatcherChild(
allocator: std.mem.Allocator,
procinfo: *std.os.windows.PROCESS_INFORMATION,
job: w.HANDLE,
) !void {
// https://devblogs.microsoft.com/oldnewthing/20230209-00/?p=107812
var attr_size: usize = undefined;
_ = windows.InitializeProcThreadAttributeList(null, 1, 0, &attr_size);
const p = try allocator.alloc(u8, attr_size);
defer allocator.free(p);
if (windows.InitializeProcThreadAttributeList(p.ptr, 1, 0, &attr_size) == 0) {
return error.Win32Error;
}
if (windows.UpdateProcThreadAttribute(
p.ptr,
0,
windows.PROC_THREAD_ATTRIBUTE_JOB_LIST,
@ptrCast(&job),
@sizeOf(w.HANDLE),
null,
null,
) == 0) {
return error.Win32Error;
}
const flags: std.os.windows.DWORD = w.CREATE_UNICODE_ENVIRONMENT | windows.EXTENDED_STARTUPINFO_PRESENT;
const image_path = windows.exePathW();
var wbuf: WPathBuffer = undefined;
@memcpy(wbuf[0..image_path.len], image_path);
wbuf[image_path.len] = 0;
const image_pathZ = wbuf[0..image_path.len :0];
const kernelenv = w.kernel32.GetEnvironmentStringsW();
defer {
if (kernelenv) |envptr| {
_ = w.kernel32.FreeEnvironmentStringsW(envptr);
}
}
var size: usize = 0;
if (kernelenv) |pointer| {
// check that env is non-empty
if (pointer[0] != 0 or pointer[1] != 0) {
// array is terminated by two nulls
while (pointer[size] != 0 or pointer[size + 1] != 0) size += 1;
size += 1;
}
}
// now pointer[size] is the first null
const envbuf = try allocator.alloc(u16, size + watcherChildEnv.len + 4);
defer allocator.free(envbuf);
if (kernelenv) |pointer| {
@memcpy(envbuf[0..size], pointer);
}
@memcpy(envbuf[size .. size + watcherChildEnv.len], watcherChildEnv);
envbuf[size + watcherChildEnv.len] = '=';
envbuf[size + watcherChildEnv.len + 1] = '1';
envbuf[size + watcherChildEnv.len + 2] = 0;
envbuf[size + watcherChildEnv.len + 3] = 0;
var startupinfo = windows.STARTUPINFOEXW{
.StartupInfo = .{
.cb = @sizeOf(windows.STARTUPINFOEXW),
.lpReserved = null,
.lpDesktop = null,
.lpTitle = null,
.dwX = 0,
.dwY = 0,
.dwXSize = 0,
.dwYSize = 0,
.dwXCountChars = 0,
.dwYCountChars = 0,
.dwFillAttribute = 0,
.dwFlags = w.STARTF_USESTDHANDLES,
.wShowWindow = 0,
.cbReserved2 = 0,
.lpReserved2 = null,
.hStdInput = std.io.getStdIn().handle,
.hStdOutput = std.io.getStdOut().handle,
.hStdError = std.io.getStdErr().handle,
},
.lpAttributeList = p.ptr,
};
@memset(std.mem.asBytes(procinfo), 0);
const rc = w.kernel32.CreateProcessW(
image_pathZ.ptr,
bun.windows.GetCommandLineW(),
null,
null,
1,
flags,
envbuf.ptr,
null,
@ptrCast(&startupinfo),
procinfo,
);
if (rc == 0) {
return error.Win32Error;
}
var is_in_job: w.BOOL = 0;
_ = windows.IsProcessInJob(procinfo.hProcess, job, &is_in_job);
assert(is_in_job != 0);
_ = std.os.windows.ntdll.NtClose(procinfo.hThread);
}
};
pub usingnamespace if (@import("builtin").target.os.tag != .windows) posix else win32;
pub const spawn = @import("./bun.js/api/bun/spawn.zig").PosixSpawn;
pub fn isRegularFile(mode: anytype) bool {
return S.ISREG(@intCast(mode));

View File

@@ -42,3 +42,8 @@
#include <sys/socket.h>
#include <linux/fs.h>
#endif
#if WINDOWS
#include <windows.h>
#include <winternl.h>
#endif

View File

@@ -12,7 +12,7 @@ const std = @import("std");
const bun = @import("root").bun;
const Environment = @import("./env.zig");
pub const translated = @import("translated-c-headers");
const translated = @import("translated-c-headers");
const PlatformSpecific = switch (Environment.os) {
.mac => @import("./darwin_c.zig"),

View File

@@ -1627,9 +1627,9 @@ pub const Command = struct {
if (comptime Environment.isWindows) {
if (global_cli_ctx.debug.hot_reload == .watch) {
if (!bun.isWatcherChild()) {
if (!bun.windows.isWatcherChild()) {
// this is noreturn
bun.becomeWatcherManager(allocator);
bun.windows.becomeWatcherManager(allocator);
} else {
bun.auto_reload_on_crash = true;
}

View File

@@ -411,7 +411,7 @@ const AbortHandler = struct {
};
std.posix.sigaction(std.posix.SIG.INT, &action, null);
} else {
const res = bun.windows.SetConsoleCtrlHandler(windowsCtrlHandler, std.os.windows.TRUE);
const res = bun.c.SetConsoleCtrlHandler(windowsCtrlHandler, std.os.windows.TRUE);
if (res == 0) {
if (Environment.isDebug) {
Output.warn("Failed to set abort handler\n", .{});
@@ -424,7 +424,7 @@ const AbortHandler = struct {
// only necessary on Windows, as on posix we pass the SA_RESETHAND flag
if (Environment.isWindows) {
// restores default Ctrl+C behavior
_ = bun.windows.SetConsoleCtrlHandler(null, std.os.windows.FALSE);
_ = bun.c.SetConsoleCtrlHandler(null, std.os.windows.FALSE);
}
}
};

View File

@@ -41,11 +41,11 @@ pub const InitCommand = struct {
// unset `ENABLE_VIRTUAL_TERMINAL_INPUT` on windows. This prevents backspace from
// deleting the entire line
const original_mode: if (Environment.isWindows) ?bun.windows.DWORD else void = if (comptime Environment.isWindows)
bun.win32.updateStdioModeFlags(.std_in, .{ .unset = bun.windows.ENABLE_VIRTUAL_TERMINAL_INPUT }) catch null;
bun.windows.updateStdioModeFlags(.std_in, .{ .unset = bun.windows.ENABLE_VIRTUAL_TERMINAL_INPUT }) catch null;
defer if (comptime Environment.isWindows) {
if (original_mode) |mode| {
_ = bun.windows.SetConsoleMode(bun.FD.stdin().native(), mode);
_ = bun.c.SetConsoleMode(bun.FD.stdin().native(), mode);
}
};
@@ -206,7 +206,7 @@ pub const InitCommand = struct {
// Set raw mode to read single characters without echo
const original_mode: if (Environment.isWindows) ?bun.windows.DWORD else void = if (comptime Environment.isWindows)
bun.win32.updateStdioModeFlags(.std_in, .{
bun.windows.updateStdioModeFlags(.std_in, .{
// virtual terminal input enables arrow keys, processed input lets ctrl+c kill the program
.set = bun.windows.ENABLE_VIRTUAL_TERMINAL_INPUT | bun.windows.ENABLE_PROCESSED_INPUT,
// disabling line input sends keys immediately, disabling echo input makes sure it doesn't print to the terminal
@@ -219,7 +219,7 @@ pub const InitCommand = struct {
defer {
if (comptime Environment.isWindows) {
if (original_mode) |mode| {
_ = bun.windows.SetConsoleMode(
_ = bun.c.SetConsoleMode(
bun.FD.stdin().native(),
mode,
);

View File

@@ -680,11 +680,11 @@ pub const PublishCommand = struct {
// unset `ENABLE_VIRTUAL_TERMINAL_INPUT` on windows. This prevents backspace from
// deleting the entire line
const original_mode: if (Environment.isWindows) ?bun.windows.DWORD else void = if (comptime Environment.isWindows)
bun.win32.updateStdioModeFlags(.std_in, .{ .unset = bun.windows.ENABLE_VIRTUAL_TERMINAL_INPUT }) catch null;
bun.windows.updateStdioModeFlags(.std_in, .{ .unset = bun.windows.ENABLE_VIRTUAL_TERMINAL_INPUT }) catch null;
defer if (comptime Environment.isWindows) {
if (original_mode) |mode| {
_ = bun.windows.SetConsoleMode(bun.FD.stdin().native(), mode);
_ = bun.c.SetConsoleMode(bun.FD.stdin().native(), mode);
}
};

View File

@@ -0,0 +1,72 @@
// translate-c is unable to translate the unsuffixed windows functions
// like `SetCurrentDirectory` since they are defined with an odd macro
// that translate-c doesn't handle.
//
// #define SetCurrentDirectory __MINGW_NAME_AW(SetCurrentDirectory)
//
// In these cases, it's better to just reference the underlying function
// directly: SetCurrentDirectoryW. To make the error better, a post
// processing step is applied to the translate-c file.
const std = @import("std");
const mem = std.mem;
const symbol_replacements = std.StaticStringMap([]const u8).initComptime(&.{
&.{ "NTSTATUS", "@import(\"std\").os.windows.NTSTATUS" },
&.{ "HANDLE", "@import(\"std\").os.windows.HANDLE" },
&.{ "PHANDLE", "*HANDLE" },
});
pub fn main() !void {
const gpa = std.heap.smp_allocator;
var args = try std.process.argsWithAllocator(gpa);
errdefer args.deinit();
assert(args.skip());
const in = brk: {
const in_path = args.next() orelse @panic("missing argument");
const in = try std.fs.openFileAbsolute(in_path, .{});
defer in.close();
break :brk try in.readToEndAllocOptions(gpa, std.math.maxInt(u32), null, 1, 0);
};
defer gpa.free(in);
var out = try std.ArrayList(u8).initCapacity(gpa, in.len);
defer out.deinit();
const w = out.writer();
var i: usize = 0;
while (mem.indexOfPos(u8, in, i, "pub const ")) |pub_i| {
var tokenizer = std.zig.Tokenizer.init(in);
tokenizer.index = pub_i + "pub const ".len;
const symbol_name_token = tokenizer.next();
assert(symbol_name_token.tag == .identifier);
const symbol_name = in[symbol_name_token.loc.start..symbol_name_token.loc.end];
try w.writeAll(in[i..symbol_name_token.loc.end]);
i = symbol_name_token.loc.end;
var end_of_line = mem.indexOfScalarPos(u8, in, symbol_name_token.loc.end, '\n') orelse in.len;
if (in[end_of_line - 1] != ';') {
// skip multiline decl
try w.writeAll(in[i..end_of_line]);
i = end_of_line;
continue;
}
end_of_line += 1; // include the \n
if (symbol_replacements.get(symbol_name)) |replace| {
try w.print(" = {s};\n", .{replace});
} else if (mem.startsWith(u8, in[i..], " = __MINGW_NAME_AW(")) {
try w.print(" = @compileError(\"Use '{s}W' instead.\");\n", .{symbol_name});
} else {
try w.writeAll(in[i..end_of_line]);
}
i = end_of_line;
}
try w.writeAll(in[i..]);
try std.fs.cwd().writeFile(.{
.sub_path = args.next() orelse @panic("missing argument"),
.data = out.items,
});
}
fn assert(cond: bool) void {
if (!cond) @panic("unhandled");
}

View File

@@ -294,7 +294,7 @@ pub fn crashHandler(
if (std.os.windows.HRESULT_CODE(result) == .SUCCESS and name[0] != 0) {
writer.print("({})", .{bun.fmt.utf16(bun.span(name))}) catch std.posix.abort();
} else {
writer.print("(thread {d})", .{bun.windows.GetCurrentThreadId()}) catch std.posix.abort();
writer.print("(thread {d})", .{bun.c.GetCurrentThreadId()}) catch std.posix.abort();
}
},
.mac, .linux => {},

View File

@@ -1,3 +1,4 @@
// TODO: prefer generating this file via translate_c
const bun = @import("root").bun;
const std = @import("std");
@@ -195,9 +196,138 @@ pub const BrotliDecoderParameter = enum(c_uint) {
pub const BROTLI_UINT32_MAX = ~@import("std").zig.c_translation.cast(u32, @as(c_int, 0));
pub const BROTLI_SIZE_MAX = ~@import("std").zig.c_translation.cast(usize, @as(c_int, 0));
pub const SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH = @as(c_int, 4);
pub const SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH = @as(c_int, 31);
pub const SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS = @as(c_int, 64);
pub const SHARED_BROTLI_MAX_COMPOUND_DICTS = @as(c_int, 15);
pub const BROTLI_LAST_ERROR_CODE = BROTLI_DECODER_ERROR_UNREACHABLE;
pub const BrotliSharedDictionaryStruct = struct_BrotliSharedDictionaryStruct;
pub const struct_BrotliEncoderPreparedDictionaryStruct = opaque {};
pub const BrotliEncoderPreparedDictionary = struct_BrotliEncoderPreparedDictionaryStruct;
extern fn BrotliSharedDictionaryCreateInstance(alloc_func: brotli_alloc_func, free_func: brotli_free_func, @"opaque": ?*anyopaque) ?*BrotliSharedDictionary;
extern fn BrotliSharedDictionaryDestroyInstance(dict: ?*BrotliSharedDictionary) void;
extern fn BrotliSharedDictionaryAttach(dict: ?*BrotliSharedDictionary, @"type": BrotliSharedDictionaryType, data_size: usize, data: [*c]const u8) c_int;
pub const BROTLI_MODE_GENERIC: c_int = 0;
pub const BROTLI_MODE_TEXT: c_int = 1;
pub const BROTLI_MODE_FONT: c_int = 2;
pub const BrotliEncoderMode = enum(c_uint) {
generic = 0,
text = 1,
font = 2,
};
pub const BROTLI_OPERATION_PROCESS: c_int = 0;
pub const BROTLI_OPERATION_FLUSH: c_int = 1;
pub const BROTLI_OPERATION_FINISH: c_int = 2;
pub const BROTLI_OPERATION_EMIT_METADATA: c_int = 3;
pub const BROTLI_PARAM_MODE: c_int = 0;
pub const BROTLI_PARAM_QUALITY: c_int = 1;
pub const BROTLI_PARAM_LGWIN: c_int = 2;
pub const BROTLI_PARAM_LGBLOCK: c_int = 3;
pub const BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING: c_int = 4;
pub const BROTLI_PARAM_SIZE_HINT: c_int = 5;
pub const BROTLI_PARAM_LARGE_WINDOW: c_int = 6;
pub const BROTLI_PARAM_NPOSTFIX: c_int = 7;
pub const BROTLI_PARAM_NDIRECT: c_int = 8;
pub const BROTLI_PARAM_STREAM_OFFSET: c_int = 9;
pub const BrotliEncoderParameter = enum(c_uint) {
mode = 0,
quality = 1,
lgwin = 2,
lgblock = 3,
disable_literal_context_modeling = 4,
size_hint = 5,
large_window = 6,
npostfix = 7,
ndirect = 8,
stream_offset = 9,
// update kMaxBrotliParam in src/js/node/zlib.ts if this list changes
};
pub extern fn BrotliEncoderSetParameter(state: *BrotliEncoder, param: c_uint, value: u32) c_int;
pub extern fn BrotliEncoderCreateInstance(alloc_func: brotli_alloc_func, free_func: brotli_free_func, @"opaque": ?*anyopaque) ?*BrotliEncoder;
pub extern fn BrotliEncoderDestroyInstance(state: *BrotliEncoder) void;
pub extern fn BrotliEncoderPrepareDictionary(@"type": BrotliSharedDictionaryType, data_size: usize, data: [*c]const u8, quality: c_int, alloc_func: brotli_alloc_func, free_func: brotli_free_func, @"opaque": ?*anyopaque) *BrotliEncoderPreparedDictionary;
pub extern fn BrotliEncoderDestroyPreparedDictionary(dictionary: *BrotliEncoderPreparedDictionary) void;
pub extern fn BrotliEncoderAttachPreparedDictionary(state: *BrotliEncoder, dictionary: ?*const BrotliEncoderPreparedDictionary) c_int;
pub extern fn BrotliEncoderMaxCompressedSize(input_size: usize) usize;
pub extern fn BrotliEncoderCompress(quality: c_int, lgwin: c_int, mode: BrotliEncoderMode, input_size: usize, input_buffer: [*]const u8, encoded_size: *usize, encoded_buffer: [*]u8) c_int;
pub extern fn BrotliEncoderCompressStream(state: *BrotliEncoder, op: BrotliEncoder.Operation, available_in: *usize, next_in: *?[*]const u8, available_out: *usize, next_in: ?*?[*]u8, total_out: ?*usize) c_int;
pub extern fn BrotliEncoderIsFinished(state: *BrotliEncoder) c_int;
pub extern fn BrotliEncoderHasMoreOutput(state: *BrotliEncoder) c_int;
pub extern fn BrotliEncoderTakeOutput(state: *BrotliEncoder, size: *usize) ?[*]const u8;
pub extern fn BrotliEncoderEstimatePeakMemoryUsage(quality: c_int, lgwin: c_int, input_size: usize) usize;
pub extern fn BrotliEncoderGetPreparedDictionarySize(dictionary: ?*const BrotliEncoderPreparedDictionary) usize;
pub extern fn BrotliEncoderVersion() u32;
pub const BrotliEncoder = opaque {
pub const Operation = enum(c_uint) {
process = 0,
flush = 1,
finish = 2,
emit_metadata = 3,
};
pub fn createInstance(alloc_func: brotli_alloc_func, free_func: brotli_free_func, @"opaque": ?*anyopaque) callconv(.C) ?*BrotliEncoder {
return BrotliEncoderCreateInstance(alloc_func, free_func, @"opaque");
}
pub fn destroyInstance(state: *BrotliEncoder) callconv(.C) void {
return BrotliEncoderDestroyInstance(state);
}
pub fn hasMoreOutput(state: *BrotliEncoder) callconv(.C) bool {
return BrotliEncoderHasMoreOutput(state) > 0;
}
pub fn takeOutput(state: *BrotliEncoder) []const u8 {
var size: usize = 0;
if (BrotliEncoderTakeOutput(state, &size)) |ptr| {
return ptr[0..size];
}
return "";
}
pub const CompressionResult = struct {
success: bool = false,
has_more: bool = false,
output: []const u8 = "",
};
// https://github.com/google/brotli/blob/2ad58d8603294f5ee33d23bb725e0e6a17c1de50/go/cbrotli/writer.go#L23-L40
pub fn compressStream(state: *BrotliEncoder, op: Operation, data: []const u8) CompressionResult {
var available_in = data.len;
var next_in: ?[*]const u8 = data.ptr;
var available_out: usize = 0;
var result = CompressionResult{};
result.success = BrotliEncoderCompressStream(state, op, &available_in, &next_in, &available_out, null, null) > 0;
if (result.success) {
result.output = takeOutput(state);
}
result.has_more = BrotliEncoderHasMoreOutput(state) > 0;
return result;
}
pub fn setParameter(state: *BrotliEncoder, param: BrotliEncoderParameter, value: u32) bool {
return BrotliEncoderSetParameter(state, @intFromEnum(param), value) > 0;
}
};
pub const SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH = 4;
pub const SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH = 31;
pub const SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS = 64;
pub const SHARED_BROTLI_MAX_COMPOUND_DICTS = 15;
pub const BROTLI_MIN_WINDOW_BITS = 10;
pub const BROTLI_MAX_WINDOW_BITS = 24;
pub const BROTLI_LARGE_MAX_WINDOW_BITS = 30;
pub const BROTLI_MIN_INPUT_BLOCK_BITS = 16;
pub const BROTLI_MAX_INPUT_BLOCK_BITS = 24;
pub const BROTLI_MIN_QUALITY = 0;
pub const BROTLI_MAX_QUALITY = 11;
pub const BROTLI_DEFAULT_QUALITY = 11;
pub const BROTLI_DEFAULT_WINDOW = 22;
pub const BROTLI_DEFAULT_MODE = BROTLI_MODE_GENERIC;

View File

@@ -1,143 +0,0 @@
const bun = @import("root").bun;
const std = @import("std");
pub const brotli_alloc_func = ?*const fn (?*anyopaque, usize) callconv(.C) ?*anyopaque;
pub const brotli_free_func = ?*const fn (?*anyopaque, ?*anyopaque) callconv(.C) void;
pub const struct_BrotliSharedDictionaryStruct = opaque {};
pub const BrotliSharedDictionary = struct_BrotliSharedDictionaryStruct;
pub const BROTLI_SHARED_DICTIONARY_RAW: c_int = 0;
pub const BROTLI_SHARED_DICTIONARY_SERIALIZED: c_int = 1;
pub const enum_BrotliSharedDictionaryType = c_uint;
pub const BrotliSharedDictionaryType = enum_BrotliSharedDictionaryType;
pub const struct_BrotliEncoderPreparedDictionaryStruct = opaque {};
pub const BrotliEncoderPreparedDictionary = struct_BrotliEncoderPreparedDictionaryStruct;
extern fn BrotliSharedDictionaryCreateInstance(alloc_func: brotli_alloc_func, free_func: brotli_free_func, @"opaque": ?*anyopaque) ?*BrotliSharedDictionary;
extern fn BrotliSharedDictionaryDestroyInstance(dict: ?*BrotliSharedDictionary) void;
extern fn BrotliSharedDictionaryAttach(dict: ?*BrotliSharedDictionary, @"type": BrotliSharedDictionaryType, data_size: usize, data: [*c]const u8) c_int;
pub const BROTLI_MODE_GENERIC: c_int = 0;
pub const BROTLI_MODE_TEXT: c_int = 1;
pub const BROTLI_MODE_FONT: c_int = 2;
pub const BrotliEncoderMode = enum(c_uint) {
generic = 0,
text = 1,
font = 2,
};
pub const BROTLI_OPERATION_PROCESS: c_int = 0;
pub const BROTLI_OPERATION_FLUSH: c_int = 1;
pub const BROTLI_OPERATION_FINISH: c_int = 2;
pub const BROTLI_OPERATION_EMIT_METADATA: c_int = 3;
pub const BROTLI_PARAM_MODE: c_int = 0;
pub const BROTLI_PARAM_QUALITY: c_int = 1;
pub const BROTLI_PARAM_LGWIN: c_int = 2;
pub const BROTLI_PARAM_LGBLOCK: c_int = 3;
pub const BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING: c_int = 4;
pub const BROTLI_PARAM_SIZE_HINT: c_int = 5;
pub const BROTLI_PARAM_LARGE_WINDOW: c_int = 6;
pub const BROTLI_PARAM_NPOSTFIX: c_int = 7;
pub const BROTLI_PARAM_NDIRECT: c_int = 8;
pub const BROTLI_PARAM_STREAM_OFFSET: c_int = 9;
pub const BrotliEncoderParameter = enum(c_uint) {
mode = 0,
quality = 1,
lgwin = 2,
lgblock = 3,
disable_literal_context_modeling = 4,
size_hint = 5,
large_window = 6,
npostfix = 7,
ndirect = 8,
stream_offset = 9,
// update kMaxBrotliParam in src/js/node/zlib.ts if this list changes
};
pub extern fn BrotliEncoderSetParameter(state: *BrotliEncoder, param: c_uint, value: u32) c_int;
pub extern fn BrotliEncoderCreateInstance(alloc_func: brotli_alloc_func, free_func: brotli_free_func, @"opaque": ?*anyopaque) ?*BrotliEncoder;
pub extern fn BrotliEncoderDestroyInstance(state: *BrotliEncoder) void;
pub extern fn BrotliEncoderPrepareDictionary(@"type": BrotliSharedDictionaryType, data_size: usize, data: [*c]const u8, quality: c_int, alloc_func: brotli_alloc_func, free_func: brotli_free_func, @"opaque": ?*anyopaque) *BrotliEncoderPreparedDictionary;
pub extern fn BrotliEncoderDestroyPreparedDictionary(dictionary: *BrotliEncoderPreparedDictionary) void;
pub extern fn BrotliEncoderAttachPreparedDictionary(state: *BrotliEncoder, dictionary: ?*const BrotliEncoderPreparedDictionary) c_int;
pub extern fn BrotliEncoderMaxCompressedSize(input_size: usize) usize;
pub extern fn BrotliEncoderCompress(quality: c_int, lgwin: c_int, mode: BrotliEncoderMode, input_size: usize, input_buffer: [*]const u8, encoded_size: *usize, encoded_buffer: [*]u8) c_int;
pub extern fn BrotliEncoderCompressStream(state: *BrotliEncoder, op: BrotliEncoder.Operation, available_in: *usize, next_in: *?[*]const u8, available_out: *usize, next_in: ?*?[*]u8, total_out: ?*usize) c_int;
pub extern fn BrotliEncoderIsFinished(state: *BrotliEncoder) c_int;
pub extern fn BrotliEncoderHasMoreOutput(state: *BrotliEncoder) c_int;
pub extern fn BrotliEncoderTakeOutput(state: *BrotliEncoder, size: *usize) ?[*]const u8;
pub extern fn BrotliEncoderEstimatePeakMemoryUsage(quality: c_int, lgwin: c_int, input_size: usize) usize;
pub extern fn BrotliEncoderGetPreparedDictionarySize(dictionary: ?*const BrotliEncoderPreparedDictionary) usize;
pub extern fn BrotliEncoderVersion() u32;
pub const BrotliEncoder = opaque {
pub const Operation = enum(c_uint) {
process = 0,
flush = 1,
finish = 2,
emit_metadata = 3,
};
pub fn createInstance(alloc_func: brotli_alloc_func, free_func: brotli_free_func, @"opaque": ?*anyopaque) callconv(.C) ?*BrotliEncoder {
return BrotliEncoderCreateInstance(alloc_func, free_func, @"opaque");
}
pub fn destroyInstance(state: *BrotliEncoder) callconv(.C) void {
return BrotliEncoderDestroyInstance(state);
}
pub fn hasMoreOutput(state: *BrotliEncoder) callconv(.C) bool {
return BrotliEncoderHasMoreOutput(state) > 0;
}
pub fn takeOutput(state: *BrotliEncoder) []const u8 {
var size: usize = 0;
if (BrotliEncoderTakeOutput(state, &size)) |ptr| {
return ptr[0..size];
}
return "";
}
pub const CompressionResult = struct {
success: bool = false,
has_more: bool = false,
output: []const u8 = "",
};
// https://github.com/google/brotli/blob/2ad58d8603294f5ee33d23bb725e0e6a17c1de50/go/cbrotli/writer.go#L23-L40
pub fn compressStream(state: *BrotliEncoder, op: Operation, data: []const u8) CompressionResult {
var available_in = data.len;
var next_in: ?[*]const u8 = data.ptr;
var available_out: usize = 0;
var result = CompressionResult{};
result.success = BrotliEncoderCompressStream(state, op, &available_in, &next_in, &available_out, null, null) > 0;
if (result.success) {
result.output = takeOutput(state);
}
result.has_more = BrotliEncoderHasMoreOutput(state) > 0;
return result;
}
pub fn setParameter(state: *BrotliEncoder, param: BrotliEncoderParameter, value: u32) bool {
return BrotliEncoderSetParameter(state, @intFromEnum(param), value) > 0;
}
};
pub const SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH = 4;
pub const SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH = 31;
pub const SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS = 64;
pub const SHARED_BROTLI_MAX_COMPOUND_DICTS = 15;
pub const BROTLI_MIN_WINDOW_BITS = 10;
pub const BROTLI_MAX_WINDOW_BITS = 24;
pub const BROTLI_LARGE_MAX_WINDOW_BITS = 30;
pub const BROTLI_MIN_INPUT_BLOCK_BITS = 16;
pub const BROTLI_MAX_INPUT_BLOCK_BITS = 24;
pub const BROTLI_MIN_QUALITY = 0;
pub const BROTLI_MAX_QUALITY = 11;
pub const BROTLI_DEFAULT_QUALITY = 11;
pub const BROTLI_DEFAULT_WINDOW = 22;
pub const BROTLI_DEFAULT_MODE = BROTLI_MODE_GENERIC;

View File

@@ -266,7 +266,7 @@ pub const FD = packed struct(backing_int) {
null;
},
.windows => |handle| result: {
break :result switch (bun.windows.NtClose(handle)) {
break :result switch (bun.c.NtClose(handle)) {
.SUCCESS => null,
else => |rc| bun.sys.Error{
.errno = if (bun.windows.Win32Error.fromNTStatus(rc).toSystemErrno()) |errno| @intFromEnum(errno) else 1,

View File

@@ -10,6 +10,7 @@ const ComptimeStringMap = bun.ComptimeStringMap;
const use_mimalloc = bun.use_mimalloc;
const writeStream = std.json.writeStream;
const WriteStream = std.json.WriteStream;
const c = bun.c;
const SystemTimer = @import("./system_timer.zig").Timer;
@@ -170,15 +171,15 @@ pub const Source = struct {
const handles = &.{ &stdin, &stdout, &stderr };
inline for (console_mode, handles) |mode, handle| {
if (mode) |m| {
_ = w.SetConsoleMode(handle.*, m);
_ = c.SetConsoleMode(handle.*, m);
}
}
if (console_output_codepage != 0)
_ = w.kernel32.SetConsoleOutputCP(console_output_codepage);
_ = c.SetConsoleOutputCP(console_output_codepage);
if (console_codepage != 0)
_ = w.SetConsoleCP(console_codepage);
_ = c.SetConsoleCP(console_codepage);
}
pub fn init() void {
@@ -199,14 +200,14 @@ pub const Source = struct {
// https://learn.microsoft.com/en-us/windows/console/setconsoleoutputcp
const CP_UTF8 = 65001;
console_output_codepage = w.kernel32.GetConsoleOutputCP();
_ = w.kernel32.SetConsoleOutputCP(CP_UTF8);
console_output_codepage = c.GetConsoleOutputCP();
_ = c.SetConsoleOutputCP(CP_UTF8);
console_codepage = w.kernel32.GetConsoleOutputCP();
_ = w.SetConsoleCP(CP_UTF8);
console_codepage = c.GetConsoleOutputCP();
_ = c.SetConsoleCP(CP_UTF8);
var mode: w.DWORD = undefined;
if (w.kernel32.GetConsoleMode(stdin, &mode) != 0) {
if (c.GetConsoleMode(stdin, &mode) != 0) {
console_mode[0] = mode;
bun_stdio_tty[0] = 1;
// There are no flags to set on standard in, but just in case something
@@ -216,16 +217,16 @@ pub const Source = struct {
// intentionally set for any purpose, and instead only caused problems.
}
if (w.kernel32.GetConsoleMode(stdout, &mode) != 0) {
if (c.GetConsoleMode(stdout, &mode) != 0) {
console_mode[1] = mode;
bun_stdio_tty[1] = 1;
_ = w.SetConsoleMode(stdout, w.ENABLE_PROCESSED_OUTPUT | std.os.windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING | w.ENABLE_WRAP_AT_EOL_OUTPUT | mode);
_ = c.SetConsoleMode(stdout, w.ENABLE_PROCESSED_OUTPUT | std.os.windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING | w.ENABLE_WRAP_AT_EOL_OUTPUT | mode);
}
if (w.kernel32.GetConsoleMode(stderr, &mode) != 0) {
if (c.GetConsoleMode(stderr, &mode) != 0) {
console_mode[2] = mode;
bun_stdio_tty[2] = 1;
_ = w.SetConsoleMode(stderr, w.ENABLE_PROCESSED_OUTPUT | std.os.windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING | w.ENABLE_WRAP_AT_EOL_OUTPUT | mode);
_ = c.SetConsoleMode(stderr, w.ENABLE_PROCESSED_OUTPUT | std.os.windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING | w.ENABLE_WRAP_AT_EOL_OUTPUT | mode);
}
}
};
@@ -881,8 +882,7 @@ pub fn prettyFmt(comptime fmt: string, comptime is_enabled: bool) [:0]const u8 {
@setEvalBranchQuota(9999);
comptime var i: usize = 0;
comptime while (i < fmt.len) {
const c = fmt[i];
switch (c) {
switch (fmt[i]) {
'\\' => {
i += 1;
if (i < fmt.len) {

View File

@@ -8,7 +8,8 @@ const posix = std.posix;
const assertIsValidWindowsPath = bun.strings.assertIsValidWindowsPath;
const default_allocator = bun.default_allocator;
const kernel32 = bun.windows;
const kernel32 = bun.windows.kernel32;
const ntdll = bun.windows.ntdll;
const mem = std.mem;
const page_size_min = std.heap.page_size_min;
const mode_t = posix.mode_t;
@@ -43,7 +44,7 @@ pub const syscall = switch (Environment.os) {
else => @compileError("not implemented"),
};
/// Non-cancellable verisons of various libc functions are undocumented
/// Non-cancellable versions of various libc functions are undocumented
const darwin_nocancel = struct {
const c = std.c;
pub extern "c" fn @"recvfrom$NOCANCEL"(sockfd: c.fd_t, noalias buf: *anyopaque, len: usize, flags: u32, noalias src_addr: ?*c.sockaddr, noalias addrlen: ?*c.socklen_t) isize;
@@ -723,7 +724,7 @@ pub fn chdirOSPath(path: bun.stringZ, destination: if (Environment.isPosix) bun.
if (comptime Environment.isWindows) {
const wbuf = bun.WPathBufferPool.get();
defer bun.WPathBufferPool.put(wbuf);
if (kernel32.SetCurrentDirectory(bun.strings.toWDirPath(wbuf, destination)) == windows.FALSE) {
if (bun.c.SetCurrentDirectoryW(bun.strings.toWDirPath(wbuf, destination)) == windows.FALSE) {
log("SetCurrentDirectory({s}) = {d}", .{ destination, kernel32.GetLastError() });
return Maybe(void).errnoSysPD(0, .chdir, path, destination) orelse Maybe(void).success;
}
@@ -818,9 +819,9 @@ pub fn statfs(path: [:0]const u8) Maybe(bun.StatFS) {
} else {
var statfs_ = mem.zeroes(bun.StatFS);
const rc = if (Environment.isLinux)
C.translated.statfs(path, &statfs_)
bun.c.statfs(path, &statfs_)
else if (Environment.isMac)
C.translated.statfs(path, &statfs_)
bun.c.statfs(path, &statfs_)
else
@compileError("Unsupported platform");
@@ -980,8 +981,7 @@ pub fn mkdirOSPath(file_path: bun.OSPathSliceZ, flags: mode_t) Maybe(void) {
return switch (Environment.os) {
else => mkdir(file_path, flags),
.windows => {
const rc = kernel32.CreateDirectoryW(file_path, null);
const rc = bun.c.CreateDirectoryW(file_path, null);
if (Maybe(void).errnoSys(
rc,
.mkdir,
@@ -3341,21 +3341,21 @@ pub fn existsAtType(fd: bun.FileDescriptor, subpath: anytype) Maybe(ExistsAtType
.SecurityQualityOfService = null,
};
var basic_info: w.FILE_BASIC_INFORMATION = undefined;
const rc = kernel32.NtQueryAttributesFile(&attr, &basic_info);
const rc = ntdll.NtQueryAttributesFile(&attr, &basic_info);
if (JSC.Maybe(bool).errnoSys(rc, .access)) |err| {
syslog("NtQueryAttributesFile({}, O_RDONLY, 0) = {}", .{ bun.fmt.fmtOSPath(path, .{}), err });
return .{ .err = err.err };
}
const is_regular_file = basic_info.FileAttributes != kernel32.INVALID_FILE_ATTRIBUTES and
const is_regular_file = basic_info.FileAttributes != bun.c.INVALID_FILE_ATTRIBUTES and
// from libuv: directories cannot be read-only
// https://github.com/libuv/libuv/blob/eb5af8e3c0ea19a6b0196d5db3212dae1785739b/src/win/fs.c#L2144-L2146
(basic_info.FileAttributes & kernel32.FILE_ATTRIBUTE_DIRECTORY == 0 or
basic_info.FileAttributes & kernel32.FILE_ATTRIBUTE_READONLY == 0);
(basic_info.FileAttributes & bun.c.FILE_ATTRIBUTE_DIRECTORY == 0 or
basic_info.FileAttributes & bun.c.FILE_ATTRIBUTE_READONLY == 0);
const is_dir = basic_info.FileAttributes != kernel32.INVALID_FILE_ATTRIBUTES and
basic_info.FileAttributes & kernel32.FILE_ATTRIBUTE_DIRECTORY != 0 and
basic_info.FileAttributes & kernel32.FILE_ATTRIBUTE_READONLY == 0;
const is_dir = basic_info.FileAttributes != bun.c.INVALID_FILE_ATTRIBUTES and
basic_info.FileAttributes & bun.c.FILE_ATTRIBUTE_DIRECTORY != 0 and
basic_info.FileAttributes & bun.c.FILE_ATTRIBUTE_READONLY == 0;
return if (is_dir) {
syslog("NtQueryAttributesFile({}, O_RDONLY, 0) = directory", .{bun.fmt.fmtOSPath(path, .{})});
@@ -3746,7 +3746,7 @@ pub fn writeNonblocking(fd: bun.FileDescriptor, buf: []const u8) Maybe(usize) {
pub fn getFileSize(fd: bun.FileDescriptor) Maybe(usize) {
if (Environment.isWindows) {
var size: windows.LARGE_INTEGER = undefined;
if (windows.GetFileSizeEx(fd.cast(), &size) == windows.FALSE) {
if (windows.kernel32.GetFileSizeEx(fd.cast(), &size) == windows.FALSE) {
const err = Error.fromCode(windows.getLastErrno(), .fstat);
log("GetFileSizeEx({}) = {s}", .{ fd, err.name() });
return .{ .err = err };
@@ -3967,7 +3967,7 @@ pub const File = struct {
if (Environment.isWindows) {
const rt = windows.GetFileType(self.handle.cast());
if (rt == windows.FILE_TYPE_UNKNOWN) {
switch (bun.windows.GetLastError()) {
switch (windows.GetLastError()) {
.SUCCESS => {},
else => |err| {
return .{ .err = Error.fromCode((bun.C.SystemErrno.init(err) orelse bun.C.SystemErrno.EUNKNOWN).toE(), .fstat) };

View File

@@ -1,6 +1,13 @@
const bun = @import("root").bun;
const Output = bun.Output;
const windows = std.os.windows;
const win32 = windows;
const c = bun.c;
pub const ntdll = windows.ntdll;
pub const kernel32 = windows.kernel32;
pub const GetLastError = kernel32.GetLastError;
pub const PATH_MAX_WIDE = windows.PATH_MAX_WIDE;
pub const MAX_PATH = windows.MAX_PATH;
pub const WORD = windows.WORD;
@@ -38,7 +45,6 @@ pub const FILETIME = windows.FILETIME;
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_INFO_BY_HANDLE_CLASS = windows.FILE_INFO_BY_HANDLE_CLASS;
pub const FILE_SHARE_READ = windows.FILE_SHARE_READ;
@@ -62,9 +68,6 @@ 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;
@@ -3414,7 +3417,7 @@ pub fn GetFinalPathNameByHandle(
});
if (return_length == 0) {
bun.sys.syslog("GetFinalPathNameByHandleW({*p}) = {}", .{ hFile, bun.windows.GetLastError() });
bun.sys.syslog("GetFinalPathNameByHandleW({*p}) = {}", .{ hFile, GetLastError() });
return error.FileNotFound;
}
@@ -3478,7 +3481,6 @@ pub const ENABLE_VIRTUAL_TERMINAL_INPUT = 0x200;
pub const ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002;
pub const ENABLE_PROCESSED_OUTPUT = 0x0001;
const SetConsoleMode = kernel32.SetConsoleMode;
pub extern fn SetStdHandle(nStdHandle: u32, hHandle: *anyopaque) u32;
pub extern fn GetConsoleOutputCP() u32;
pub extern "kernel32" fn SetConsoleCP(wCodePageID: std.os.windows.UINT) callconv(std.os.windows.WINAPI) std.os.windows.BOOL;
@@ -3667,3 +3669,188 @@ pub extern "kernel32" fn GetCommandLineW() callconv(.winapi) LPWSTR;
pub extern "kernel32" fn CreateDirectoryW(lpPathName: [*:0]const u16, lpSecurityAttributes: ?*windows.SECURITY_ATTRIBUTES) callconv(.winapi) BOOL;
pub extern "kernel32" fn SetEndOfFile(hFile: HANDLE) callconv(.winapi) BOOL;
pub extern "kernel32" fn GetProcessTimes(in_hProcess: HANDLE, out_lpCreationTime: *FILETIME, out_lpExitTime: *FILETIME, out_lpKernelTime: *FILETIME, out_lpUserTime: *FILETIME) callconv(.winapi) BOOL;
/// Returns the original mode, or null on failure
pub fn updateStdioModeFlags(i: bun.FD.Stdio, opts: struct { set: DWORD = 0, unset: DWORD = 0 }) !DWORD {
const fd = i.fd();
var original_mode: DWORD = 0;
if (c.GetConsoleMode(fd.cast(), &original_mode) != 0) {
if (c.SetConsoleMode(fd.cast(), (original_mode | opts.set) & ~opts.unset) == 0) {
return getLastError();
}
} else return getLastError();
return original_mode;
}
const watcherChildEnv: [:0]const u16 = bun.strings.toUTF16Literal("_BUN_WATCHER_CHILD");
// magic exit code to indicate to the watcher manager that the child process should be re-spawned
// this was randomly generated - we need to avoid using a common exit code that might be used by the script itself
pub const watcher_reload_exit: DWORD = 3224497970;
pub const spawn = @import("./bun.js/api/bun/spawn.zig").PosixSpawn;
pub fn isWatcherChild() bool {
var buf: [1]u16 = undefined;
return c.GetEnvironmentVariableW(@constCast(watcherChildEnv.ptr), &buf, 1) > 0;
}
pub fn becomeWatcherManager(allocator: std.mem.Allocator) noreturn {
// this process will be the parent of the child process that actually runs the script
var procinfo: std.os.windows.PROCESS_INFORMATION = undefined;
bun.C.windows_enable_stdio_inheritance();
const job = CreateJobObjectA(null, null) orelse Output.panic(
"Could not create watcher Job Object: {s}",
.{@tagName(std.os.windows.kernel32.GetLastError())},
);
var jeli = std.mem.zeroes(c.JOBOBJECT_EXTENDED_LIMIT_INFORMATION);
jeli.BasicLimitInformation.LimitFlags =
c.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE |
c.JOB_OBJECT_LIMIT_BREAKAWAY_OK |
c.JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK |
c.JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION;
if (c.SetInformationJobObject(
job,
c.JobObjectExtendedLimitInformation,
&jeli,
@sizeOf(c.JOBOBJECT_EXTENDED_LIMIT_INFORMATION),
) == 0) {
Output.panic(
"Could not configure watcher Job Object: {s}",
.{@tagName(std.os.windows.kernel32.GetLastError())},
);
}
while (true) {
spawnWatcherChild(allocator, &procinfo, job) catch |err| {
bun.handleErrorReturnTrace(err, @errorReturnTrace());
if (err == error.Win32Error) {
Output.panic("Failed to spawn process: {s}\n", .{@tagName(GetLastError())});
}
Output.panic("Failed to spawn process: {s}\n", .{@errorName(err)});
};
windows.WaitForSingleObject(procinfo.hProcess, c.INFINITE) catch |err| {
Output.panic("Failed to wait for child process: {s}\n", .{@errorName(err)});
};
var exit_code: DWORD = 0;
if (c.GetExitCodeProcess(procinfo.hProcess, &exit_code) == 0) {
const err = windows.GetLastError();
_ = c.NtClose(procinfo.hProcess);
Output.panic("Failed to get exit code of child process: {s}\n", .{@tagName(err)});
}
_ = c.NtClose(procinfo.hProcess);
// magic exit code to indicate that the child process should be re-spawned
if (exit_code == watcher_reload_exit) {
continue;
} else {
bun.Global.exit(exit_code);
}
}
}
pub fn spawnWatcherChild(
allocator: std.mem.Allocator,
procinfo: *std.os.windows.PROCESS_INFORMATION,
job: HANDLE,
) !void {
// https://devblogs.microsoft.com/oldnewthing/20230209-00/?p=107812
var attr_size: usize = undefined;
_ = InitializeProcThreadAttributeList(null, 1, 0, &attr_size);
const p = try allocator.alloc(u8, attr_size);
defer allocator.free(p);
if (InitializeProcThreadAttributeList(p.ptr, 1, 0, &attr_size) == 0) {
return error.Win32Error;
}
if (UpdateProcThreadAttribute(
p.ptr,
0,
c.PROC_THREAD_ATTRIBUTE_JOB_LIST,
@ptrCast(&job),
@sizeOf(HANDLE),
null,
null,
) == 0) {
return error.Win32Error;
}
const flags: DWORD = c.CREATE_UNICODE_ENVIRONMENT | c.EXTENDED_STARTUPINFO_PRESENT;
const image_path = exePathW();
var wbuf: WPathBuffer = undefined;
@memcpy(wbuf[0..image_path.len], image_path);
wbuf[image_path.len] = 0;
const image_pathZ = wbuf[0..image_path.len :0];
const kernelenv = kernel32.GetEnvironmentStringsW();
defer if (kernelenv) |envptr| {
_ = kernel32.FreeEnvironmentStringsW(envptr);
};
var size: usize = 0;
if (kernelenv) |pointer| {
// check that env is non-empty
if (pointer[0] != 0 or pointer[1] != 0) {
// array is terminated by two nulls
while (pointer[size] != 0 or pointer[size + 1] != 0) size += 1;
size += 1;
}
}
// now pointer[size] is the first null
const envbuf = try allocator.alloc(u16, size + watcherChildEnv.len + 4);
defer allocator.free(envbuf);
if (kernelenv) |pointer| {
@memcpy(envbuf[0..size], pointer);
}
@memcpy(envbuf[size .. size + watcherChildEnv.len], watcherChildEnv);
envbuf[size + watcherChildEnv.len] = '=';
envbuf[size + watcherChildEnv.len + 1] = '1';
envbuf[size + watcherChildEnv.len + 2] = 0;
envbuf[size + watcherChildEnv.len + 3] = 0;
var startupinfo = STARTUPINFOEXW{
.StartupInfo = .{
.cb = @sizeOf(STARTUPINFOEXW),
.lpReserved = null,
.lpDesktop = null,
.lpTitle = null,
.dwX = 0,
.dwY = 0,
.dwXSize = 0,
.dwYSize = 0,
.dwXCountChars = 0,
.dwYCountChars = 0,
.dwFillAttribute = 0,
.dwFlags = c.STARTF_USESTDHANDLES,
.wShowWindow = 0,
.cbReserved2 = 0,
.lpReserved2 = null,
.hStdInput = std.io.getStdIn().handle,
.hStdOutput = std.io.getStdOut().handle,
.hStdError = std.io.getStdErr().handle,
},
.lpAttributeList = p.ptr,
};
@memset(std.mem.asBytes(procinfo), 0);
const rc = kernel32.CreateProcessW(
image_pathZ.ptr,
c.GetCommandLineW(),
null,
null,
1,
flags,
envbuf.ptr,
null,
@ptrCast(&startupinfo),
procinfo,
);
if (rc == 0) {
return error.Win32Error;
}
var is_in_job: c.BOOL = 0;
_ = c.IsProcessInJob(procinfo.hProcess, job, &is_in_job);
bun.debugAssert(is_in_job != 0);
_ = c.NtClose(procinfo.hThread);
}

View File

@@ -46,6 +46,7 @@ for (const file of files) {
if (file.isDirectory()) continue;
if (!file.name.endsWith(".zig")) continue;
if (file.parentPath.startsWith("src" + path.sep + "deps")) continue;
if (file.parentPath.startsWith("src" + path.sep + "codegen")) continue;
const content = await Bun.file(file.parentPath + path.sep + file.name).text();
for (const word of words_keys) {
let regex = words[word].regex ? new RegExp(word, "g") : undefined;