const std = @import("std"); pub const linux = struct { // On linux, bun overrides the libc symbols for various functions. // This is to compensate for older glibc versions. fn simulateLibcErrno(rc: usize) c_int { const signed: isize = @bitCast(rc); const int: c_int = @intCast(if (signed > -4096 and signed < 0) -signed else 0); std.c._errno().* = int; return if (signed > -4096 and signed < 0) -1 else int; } pub export fn stat(path: [*:0]const u8, buf: *std.os.linux.Stat) c_int { // https://git.musl-libc.org/cgit/musl/tree/src/stat/stat.c const rc = std.os.linux.fstatat(std.os.linux.AT.FDCWD, path, buf, 0); return simulateLibcErrno(rc); } pub const stat64 = stat; pub const lstat64 = lstat; pub const fstat64 = fstat; pub const fstatat64 = fstatat; pub export fn lstat(path: [*:0]const u8, buf: *std.os.linux.Stat) c_int { // https://git.musl-libc.org/cgit/musl/tree/src/stat/lstat.c const rc = std.os.linux.fstatat(std.os.linux.AT.FDCWD, path, buf, std.os.linux.AT.SYMLINK_NOFOLLOW); return simulateLibcErrno(rc); } pub export fn fstat(fd: c_int, buf: *std.os.linux.Stat) c_int { const rc = std.os.linux.fstat(fd, buf); return simulateLibcErrno(rc); } pub export fn fstatat(dirfd: i32, path: [*:0]const u8, buf: *std.os.linux.Stat, flags: u32) c_int { const rc = std.os.linux.fstatat(dirfd, path, buf, flags); return simulateLibcErrno(rc); } pub export fn statx(dirfd: i32, path: [*:0]const u8, flags: u32, mask: u32, buf: *std.os.linux.Statx) c_int { const rc = std.os.linux.statx(dirfd, path, flags, mask, buf); return simulateLibcErrno(rc); } pub const memmem = bun.c.memmem; comptime { _ = stat; _ = stat64; _ = lstat; _ = lstat64; _ = fstat; _ = fstat64; _ = fstatat; _ = statx; @export(&stat, .{ .name = "stat64" }); @export(&lstat, .{ .name = "lstat64" }); @export(&fstat, .{ .name = "fstat64" }); @export(&fstatat, .{ .name = "fstatat64" }); } }; pub const darwin = struct { pub const memmem = bun.c.memmem; // The symbol name depends on the arch. pub const lstat = blk: { const T = *const fn (?[*:0]const u8, ?*bun.Stat) callconv(.C) c_int; break :blk @extern(T, .{ .name = if (bun.Environment.isAarch64) "lstat" else "lstat64" }); }; pub const fstat = blk: { const T = *const fn (i32, ?*bun.Stat) callconv(.C) c_int; break :blk @extern(T, .{ .name = if (bun.Environment.isAarch64) "fstat" else "fstat64" }); }; pub const stat = blk: { const T = *const fn (?[*:0]const u8, ?*bun.Stat) callconv(.C) c_int; break :blk @extern(T, .{ .name = if (bun.Environment.isAarch64) "stat" else "stat64" }); }; }; pub const windows = struct { /// Windows doesn't have memmem, so we need to implement it /// This is used in src/string_immutable.zig pub export fn memmem(haystack: ?[*]const u8, haystacklen: usize, needle: ?[*]const u8, needlelen: usize) ?[*]const u8 { // Handle null pointers if (haystack == null or needle == null) return null; // Handle empty needle case if (needlelen == 0) return haystack; // Handle case where needle is longer than haystack if (needlelen > haystacklen) return null; const hay = haystack.?[0..haystacklen]; const nee = needle.?[0..needlelen]; const i = std.mem.indexOf(u8, hay, nee) orelse return null; return hay.ptr + i; } /// lstat is implemented in workaround-missing-symbols.cpp pub const lstat = blk: { const T = *const fn ([*c]const u8, [*c]std.c.Stat) callconv(.C) c_int; break :blk @extern(T, .{ .name = "lstat64" }); }; /// fstat is implemented in workaround-missing-symbols.cpp pub const fstat = blk: { const T = *const fn ([*c]const u8, [*c]std.c.Stat) callconv(.C) c_int; break :blk @extern(T, .{ .name = "fstat64" }); }; /// stat is implemented in workaround-missing-symbols.cpp pub const stat = blk: { const T = *const fn ([*c]const u8, [*c]std.c.Stat) callconv(.C) c_int; break :blk @extern(T, .{ .name = "stat64" }); }; }; pub const current = switch (bun.Environment.os) { .linux => linux, .windows => windows, .mac => darwin, else => struct {}, }; const bun = @import("bun");