mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
embrace translate-c more, remove some more usingnamespace
This commit is contained in:
82
build.zig
82
build.zig
@@ -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 {
|
||||
|
||||
@@ -61,7 +61,6 @@ zig_keywords = {
|
||||
'try',
|
||||
'union',
|
||||
'unreachable',
|
||||
'usingnamespace',
|
||||
'var',
|
||||
'volatile',
|
||||
'while',
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
215
src/bun.zig
215
src/bun.zig
@@ -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));
|
||||
|
||||
@@ -42,3 +42,8 @@
|
||||
#include <sys/socket.h>
|
||||
#include <linux/fs.h>
|
||||
#endif
|
||||
|
||||
#if WINDOWS
|
||||
#include <windows.h>
|
||||
#include <winternl.h>
|
||||
#endif
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
72
src/codegen/process_windows_translate_c.zig
Normal file
72
src/codegen/process_windows_translate_c.zig
Normal 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");
|
||||
}
|
||||
@@ -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 => {},
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
32
src/sys.zig
32
src/sys.zig
@@ -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) };
|
||||
|
||||
199
src/windows.zig
199
src/windows.zig
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user