aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-12-06 14:14:27 -0800
committerGravatar GitHub <noreply@github.com> 2022-12-06 14:14:27 -0800
commit81317a52ea13b39de22d2cdeff8ecc231224f9e7 (patch)
tree677bc306ab6b56937f024a5bdf3e8b624b7137c6
parent7d29782896f31ae5249f00e9505fd978e9733644 (diff)
downloadbun-81317a52ea13b39de22d2cdeff8ecc231224f9e7.tar.gz
bun-81317a52ea13b39de22d2cdeff8ecc231224f9e7.tar.zst
bun-81317a52ea13b39de22d2cdeff8ecc231224f9e7.zip
Fix glibc symbol version issues preventing `bun install` from being used in older glibc versions (#1580)
* Prevent integer overflow in connectError * Add missing deepEquals() type to Bun * fix missing glibc symbols * Fix missing symbol issues * Try this * Update glibc-versions-hack.cpp * Update glibc-versions-hack.cpp * Update glibc-versions-hack.cpp Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
-rw-r--r--Makefile16
-rw-r--r--packages/bun-types/bun.d.ts7
-rw-r--r--src/bun.js/api/bun/socket.zig6
-rw-r--r--src/bun.js/bindings/BunJSCModule.cpp8
-rw-r--r--src/bun.js/bindings/ModuleLoader.cpp2
-rw-r--r--src/bun.js/bindings/glibc-versions-hack.cpp124
-rw-r--r--src/bun.js/node/node_fs.zig17
-rw-r--r--src/bun.zig4
-rw-r--r--src/c.zig36
-rw-r--r--src/cli/create_command.zig12
-rw-r--r--src/copy_file.zig86
-rw-r--r--src/install/install.zig13
-rw-r--r--src/linux_c.zig19
-rw-r--r--src/options.zig37
14 files changed, 317 insertions, 70 deletions
diff --git a/Makefile b/Makefile
index 80bdc1aab..f9e4b2c0e 100644
--- a/Makefile
+++ b/Makefile
@@ -432,6 +432,18 @@ ARCHIVE_FILES = $(ARCHIVE_FILES_WITHOUT_LIBCRYPTO)
STATIC_MUSL_FLAG ?=
ifeq ($(OS_NAME), linux)
+WRAP_SYMBOLS_ON_LINUX = -Wl,--wrap=fcntl -Wl,--wrap=fcntl64 -Wl,--wrap=stat64 -Wl,--wrap=pow -Wl,--wrap=exp -Wl,--wrap=log \
+ -Wl,--wrap=lstat \
+ -Wl,--wrap=stat \
+ -Wl,--wrap=fstat \
+ -Wl,--wrap=fstatat \
+ -Wl,--wrap=lstat64 \
+ -Wl,--wrap=stat64 \
+ -Wl,--wrap=fstat64 \
+ -Wl,--wrap=fstatat64 \
+ -Wl,--wrap=mknod \
+ -Wl,--wrap=mknodat
+
PLATFORM_LINKER_FLAGS = $(BUN_CFLAGS) \
-fuse-ld=lld \
-Wl,-z,now \
@@ -447,8 +459,8 @@ PLATFORM_LINKER_FLAGS = $(BUN_CFLAGS) \
-fno-semantic-interposition \
-flto \
-Wl,--allow-multiple-definition \
- -rdynamic
-
+ -rdynamic \
+ $(WRAP_SYMBOLS_ON_LINUX)
endif
diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts
index e4d95e715..265a8ed46 100644
--- a/packages/bun-types/bun.d.ts
+++ b/packages/bun-types/bun.d.ts
@@ -573,6 +573,13 @@ declare module "bun" {
export type JavaScriptLoader = "jsx" | "js" | "ts" | "tsx";
+ /**
+ * Fast deep-equality check two objects.
+ *
+ * This also powers expect().toEqual in `bun:test`
+ */
+ export function deepEquals(a: any, b: any): boolean;
+
export interface TranspilerOptions {
/**
* Replace key with value. Value must be a JSON string.
diff --git a/src/bun.js/api/bun/socket.zig b/src/bun.js/api/bun/socket.zig
index fa4411cc0..8fd6621f2 100644
--- a/src/bun.js/api/bun/socket.zig
+++ b/src/bun.js/api/bun/socket.zig
@@ -885,8 +885,10 @@ fn NewSocket(comptime ssl: bool) type {
.syscall = ZigString.init("connect"),
};
_ = handlers.rejectPromise(err.toErrorInstance(handlers.globalObject));
- this.reffer.unref(handlers.vm);
- handlers.markInactive(ssl, socket.context());
+ if (this.reffer.has) {
+ this.reffer.unref(handlers.vm);
+ handlers.markInactive(ssl, socket.context());
+ }
}
pub fn markActive(this: *This) void {
diff --git a/src/bun.js/bindings/BunJSCModule.cpp b/src/bun.js/bindings/BunJSCModule.cpp
index 92eefd106..a89bba52a 100644
--- a/src/bun.js/bindings/BunJSCModule.cpp
+++ b/src/bun.js/bindings/BunJSCModule.cpp
@@ -252,6 +252,8 @@ JSC_DEFINE_HOST_FUNCTION(functionNeverInlineFunction, (JSGlobalObject * globalOb
return JSValue::encode(setNeverInline(globalObject, callFrame));
}
+extern "C" bool Bun__mkdirp(JSC::JSGlobalObject*, const char*);
+
JSC_DECLARE_HOST_FUNCTION(functionStartSamplingProfiler);
JSC_DEFINE_HOST_FUNCTION(functionStartSamplingProfiler, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
@@ -267,11 +269,13 @@ JSC_DEFINE_HOST_FUNCTION(functionStartSamplingProfiler, (JSC::JSGlobalObject * g
auto path = directoryValue.toWTFString(globalObject);
if (!path.isEmpty()) {
StringPrintStream pathOut;
- if (!WTF::FileSystemImpl::makeAllDirectories(path)) {
+ const char* optionCString = toCString(String(optionString + path)).data();
+
+ if (!Bun__mkdirp(globalObject, optionCString)) {
throwVMError(globalObject, scope, createTypeError(globalObject, "directory couldn't be created"_s));
return JSC::JSValue::encode(jsUndefined());
}
- const char* optionCString = toCString(String(optionString + path)).data();
+
Options::setOption(optionCString);
samplingProfiler.registerForReportAtExit();
}
diff --git a/src/bun.js/bindings/ModuleLoader.cpp b/src/bun.js/bindings/ModuleLoader.cpp
index 45f3cc46b..c35627f25 100644
--- a/src/bun.js/bindings/ModuleLoader.cpp
+++ b/src/bun.js/bindings/ModuleLoader.cpp
@@ -475,7 +475,7 @@ static JSValue fetchSourceCode(
}
auto provider = Zig::SourceProvider::create(res->result.value);
- return rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(provider)));
+ return rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(WTFMove(provider))));
}
extern "C" JSC::EncodedJSValue jsFunctionOnLoadObjectResultResolve(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame)
diff --git a/src/bun.js/bindings/glibc-versions-hack.cpp b/src/bun.js/bindings/glibc-versions-hack.cpp
new file mode 100644
index 000000000..5da0b41fb
--- /dev/null
+++ b/src/bun.js/bindings/glibc-versions-hack.cpp
@@ -0,0 +1,124 @@
+// if linux
+#if defined(__linux__)
+
+#include <fcntl.h>
+//#include <sys/stat.h>
+#include <stdarg.h>
+#include <math.h>
+#include <errno.h>
+
+#ifndef _STAT_VER
+#if defined(__aarch64__)
+#define _STAT_VER 0
+#elif defined(__x86_64__)
+#define _STAT_VER 1
+#else
+#define _STAT_VER 3
+#endif
+#endif
+
+extern "C" int __real_fcntl(int fd, int cmd, ...);
+extern "C" double __real_pow(double x, double y);
+extern "C" double __real_exp(double x);
+extern "C" double __real_log(double x);
+
+extern "C" int __wrap_fcntl(int fd, int cmd, ...)
+{
+ va_list va;
+ va_start(va, cmd);
+ return __real_fcntl(fd, cmd, va_arg(va, void*));
+ va_end(va);
+}
+
+extern "C" int __wrap_fcntl64(int fd, int cmd, ...)
+{
+ va_list va;
+ va_start(va, cmd);
+ return __real_fcntl(fd, cmd, va_arg(va, void*));
+ va_end(va);
+}
+
+// I couldn't figure out what has changed in pow, exp, log in glibc 2.29.
+// Interestingly despite compiling with -fno-omit-frame-pointer, GCC
+// optimises the following to a jmp anyway.
+
+extern "C" double __wrap_pow(double x, double y)
+{
+ return __real_pow(x, y);
+}
+
+extern "C" double __wrap_exp(double x)
+{
+ return __real_exp(x);
+}
+
+extern "C" double __wrap_log(double x)
+{
+ return __real_log(x);
+}
+
+#ifndef _MKNOD_VER
+#define _MKNOD_VER 1
+#endif
+
+extern "C" int __lxstat(int ver, const char* filename, struct stat* stat);
+extern "C" int __wrap_lstat(const char* filename, struct stat* stat)
+{
+ return __lxstat(_STAT_VER, filename, stat);
+}
+
+extern "C" int __xstat(int ver, const char* filename, struct stat* stat);
+extern "C" int __wrap_stat(const char* filename, struct stat* stat)
+{
+ return __xstat(_STAT_VER, filename, stat);
+}
+
+extern "C" int __fxstat(int ver, int fd, struct stat* stat);
+extern "C" int __wrap_fstat(int fd, struct stat* stat)
+{
+ return __fxstat(_STAT_VER, fd, stat);
+}
+
+extern "C" int __fxstatat(int ver, int dirfd, const char* path, struct stat* stat, int flags);
+extern "C" int __wrap_fstatat(int dirfd, const char* path, struct stat* stat, int flags)
+{
+ return __fxstatat(_STAT_VER, dirfd, path, stat, flags);
+}
+
+extern "C" int __lxstat64(int ver, const char* filename, struct stat64* stat);
+extern "C" int __wrap_lstat64(const char* filename, struct stat64* stat)
+{
+ return __lxstat64(_STAT_VER, filename, stat);
+}
+
+extern "C" int __xstat64(int ver, const char* filename, struct stat64* stat);
+extern "C" int __wrap_stat64(const char* filename, struct stat64* stat)
+{
+ return __xstat64(_STAT_VER, filename, stat);
+}
+
+extern "C" int __fxstat64(int ver, int fd, struct stat64* stat);
+extern "C" int __wrap_fstat64(int fd, struct stat64* stat)
+{
+ return __fxstat64(_STAT_VER, fd, stat);
+}
+
+extern "C" int __fxstatat64(int ver, int dirfd, const char* path, struct stat64* stat, int flags);
+extern "C" int __wrap_fstatat64(int dirfd, const char* path, struct stat64* stat, int flags)
+{
+ return __fxstatat64(_STAT_VER, dirfd, path, stat, flags);
+}
+
+extern "C" int __xmknod(int ver, const char* path, __mode_t mode, __dev_t dev);
+extern "C" int __wrap_mknod(const char* path, __mode_t mode, __dev_t dev)
+{
+ return __xmknod(_MKNOD_VER, path, mode, dev);
+}
+
+extern "C" int __xmknodat(int ver, int dirfd, const char* path, __mode_t mode, __dev_t dev);
+extern "C" int __wrap_mknodat(int dirfd, const char* path, __mode_t mode, __dev_t dev)
+{
+ return __xmknodat(_MKNOD_VER, dirfd, path, mode, dev);
+}
+
+#endif \ No newline at end of file
diff --git a/src/bun.js/node/node_fs.zig b/src/bun.js/node/node_fs.zig
index dd11d40bf..75b50efed 100644
--- a/src/bun.js/node/node_fs.zig
+++ b/src/bun.js/node/node_fs.zig
@@ -2915,7 +2915,7 @@ pub const NodeFS = struct {
// TODO: windows
// TODO: verify this works correctly with unicode codepoints
- fn mkdirRecursive(this: *NodeFS, args: Arguments.Mkdir, comptime flavor: Flavor) Maybe(Return.Mkdir) {
+ pub fn mkdirRecursive(this: *NodeFS, args: Arguments.Mkdir, comptime flavor: Flavor) Maybe(Return.Mkdir) {
const Option = Maybe(Return.Mkdir);
if (comptime Environment.isWindows) @compileError("This needs to be implemented on Windows.");
@@ -3976,3 +3976,18 @@ pub const NodeFS = struct {
return Maybe(Return.CreateWriteStream).todo;
}
};
+
+pub export fn Bun__mkdirp(globalThis: *JSC.JSGlobalObject, path: [*:0]const u8) bool {
+ return globalThis.bunVM().nodeFS().mkdirRecursive(
+ Arguments.Mkdir{
+ .path = PathLike{ .string = PathString.init(bun.span(path)) },
+ .recursive = true,
+ },
+ .sync,
+ ) != .err;
+}
+
+comptime {
+ if (!JSC.is_bindgen)
+ _ = Bun__mkdirp;
+}
diff --git a/src/bun.zig b/src/bun.zig
index 92b8ff2b3..1bdf7151f 100644
--- a/src/bun.zig
+++ b/src/bun.zig
@@ -541,3 +541,7 @@ pub fn StringHashMap(comptime Type: type) type {
pub fn StringHashMapUnmanaged(comptime Type: type) type {
return std.HashMapUnmanaged([]const u8, Type, StringHashMapContext, std.hash_map.default_max_load_percentage);
}
+
+const CopyFile = @import("./copy_file.zig");
+pub const copyFileRange = CopyFile.copyFileRange;
+pub const copyFile = CopyFile.copyFile;
diff --git a/src/c.zig b/src/c.zig
index ec9e63944..3c94dadba 100644
--- a/src/c.zig
+++ b/src/c.zig
@@ -1,4 +1,5 @@
const std = @import("std");
+const bun = @import("bun");
const Environment = @import("./env.zig");
const PlatformSpecific = switch (@import("builtin").target.os.tag) {
@@ -399,3 +400,38 @@ pub fn getRelease(buf: []u8) []const u8 {
pub extern fn memmem(haystack: [*]const u8, haystacklen: usize, needle: [*]const u8, needlelen: usize) ?[*]const u8;
pub extern fn cfmakeraw(*std.os.termios) void;
+
+const LazyStatus = enum {
+ pending,
+ loaded,
+ failed,
+};
+pub fn dlsym(comptime Type: type, comptime name: [:0]const u8) ?Type {
+ const Wrapper = struct {
+ pub var function: Type = undefined;
+ pub var loaded: LazyStatus = LazyStatus.pending;
+ };
+
+ if (Wrapper.loaded == .pending) {
+ const RTLD_DEFAULT = if (bun.Environment.isMac)
+ @intToPtr(?*anyopaque, @bitCast(usize, @as(isize, -2)))
+ else
+ @intToPtr(?*anyopaque, @as(usize, 0));
+ const result = std.c.dlsym(RTLD_DEFAULT, name);
+
+ if (result) |ptr| {
+ Wrapper.function = bun.cast(Type, ptr);
+ Wrapper.loaded = .loaded;
+ return Wrapper.function;
+ } else {
+ Wrapper.loaded = .failed;
+ return null;
+ }
+ }
+
+ if (Wrapper.loaded == .loaded) {
+ return Wrapper.function;
+ }
+
+ return null;
+}
diff --git a/src/cli/create_command.zig b/src/cli/create_command.zig
index c500b8200..c40f4300f 100644
--- a/src/cli/create_command.zig
+++ b/src/cli/create_command.zig
@@ -619,15 +619,9 @@ pub const CreateCommand = struct {
const stat = infile.stat() catch continue;
_ = C.fchmod(outfile.handle, stat.mode);
- CopyFile.copy(infile.handle, outfile.handle) catch {
- entry.dir.copyFile(entry.basename, destination_dir_, entry.path, .{}) catch |err| {
- node_.end();
-
- progress_.refresh();
-
- Output.prettyErrorln("<r><red>{s}<r>: copying file {s}", .{ @errorName(err), entry.path });
- Global.exit(1);
- };
+ CopyFile.copyFile(infile.handle, outfile.handle) catch |err| {
+ Output.prettyErrorln("<r><red>{s}<r>: copying file {s}", .{ @errorName(err), entry.path });
+ Global.exit(1);
};
}
}
diff --git a/src/copy_file.zig b/src/copy_file.zig
index 7fe6dddb1..1596e4602 100644
--- a/src/copy_file.zig
+++ b/src/copy_file.zig
@@ -1,14 +1,29 @@
const std = @import("std");
const os = std.os;
const math = std.math;
+const bun = @import("bun");
-const CopyFileError = error{SystemResources} || os.CopyFileRangeError || os.SendFileError;
+pub const CopyFileRangeError = error{
+ FileTooBig,
+ InputOutput,
+ /// `fd_in` is not open for reading; or `fd_out` is not open for writing;
+ /// or the `O.APPEND` flag is set for `fd_out`.
+ FilesOpenedWithWrongFlags,
+ IsDir,
+ OutOfMemory,
+ NoSpaceLeft,
+ Unseekable,
+ PermissionDenied,
+ FileBusy,
+} || os.PReadError || os.PWriteError || os.UnexpectedError;
+
+const CopyFileError = error{SystemResources} || CopyFileRangeError || os.SendFileError;
// Transfer all the data between two file descriptors in the most efficient way.
// The copy starts at offset 0, the initial offsets are preserved.
// No metadata is transferred over.
-pub fn copy(fd_in: os.fd_t, fd_out: os.fd_t) CopyFileError!void {
- if (comptime @import("builtin").target.isDarwin()) {
+pub fn copyFile(fd_in: os.fd_t, fd_out: os.fd_t) CopyFileError!void {
+ if (comptime bun.Environment.isMac) {
const rc = os.system.fcopyfile(fd_in, fd_out, null, os.system.COPYFILE_DATA);
switch (os.errno(rc)) {
.SUCCESS => return,
@@ -21,7 +36,7 @@ pub fn copy(fd_in: os.fd_t, fd_out: os.fd_t) CopyFileError!void {
}
}
- if (comptime @import("builtin").target.os.tag == .linux) {
+ if (comptime bun.Environment.isLinux) {
// Try copy_file_range first as that works at the FS level and is the
// most efficient method (if available).
var offset: u64 = 0;
@@ -29,7 +44,7 @@ pub fn copy(fd_in: os.fd_t, fd_out: os.fd_t) CopyFileError!void {
// The kernel checks the u64 value `offset+count` for overflow, use
// a 32 bit value so that the syscall won't return EINVAL except for
// impossibly large files (> 2^64-1 - 2^32-1).
- const amt = try os.copy_file_range(fd_in, offset, fd_out, offset, math.maxInt(u32), 0);
+ const amt = try copyFileRange(fd_in, offset, fd_out, offset, math.maxInt(u32), 0);
// Terminate when no data was copied
if (amt == 0) break :cfr_loop;
offset += amt;
@@ -48,3 +63,64 @@ pub fn copy(fd_in: os.fd_t, fd_out: os.fd_t) CopyFileError!void {
offset += amt;
}
}
+
+const Platform = @import("bun").analytics.GenerateHeader.GeneratePlatform;
+
+var can_use_copy_file_range = std.atomic.Atomic(i32).init(0);
+fn canUseCopyFileRangeSyscall() bool {
+ const result = can_use_copy_file_range.load(.Monotonic);
+ if (result == 0) {
+ const kernel = Platform.kernelVersion();
+ if (kernel.orderWithoutTag(.{ .major = 4, .minor = 5 }).compare(.gte)) {
+ bun.Output.debug("copy_file_range is supported", .{});
+ can_use_copy_file_range.store(1, .Monotonic);
+ return true;
+ } else {
+ bun.Output.debug("copy_file_range is NOT supported", .{});
+ can_use_copy_file_range.store(-1, .Monotonic);
+ return false;
+ }
+ }
+
+ return result == 1;
+}
+
+const fd_t = std.os.fd_t;
+pub fn copyFileRange(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len: usize, flags: u32) CopyFileRangeError!usize {
+ if (canUseCopyFileRangeSyscall()) {
+ var off_in_copy = @bitCast(i64, off_in);
+ var off_out_copy = @bitCast(i64, off_out);
+
+ const rc = std.os.linux.copy_file_range(fd_in, &off_in_copy, fd_out, &off_out_copy, len, flags);
+ switch (std.os.linux.getErrno(rc)) {
+ .SUCCESS => return @intCast(usize, rc),
+ .BADF => return error.FilesOpenedWithWrongFlags,
+ .FBIG => return error.FileTooBig,
+ .IO => return error.InputOutput,
+ .ISDIR => return error.IsDir,
+ .NOMEM => return error.OutOfMemory,
+ .NOSPC => return error.NoSpaceLeft,
+ .OVERFLOW => return error.Unseekable,
+ .PERM => return error.PermissionDenied,
+ .TXTBSY => return error.FileBusy,
+ // these may not be regular files, try fallback
+ .INVAL => {},
+ // support for cross-filesystem copy added in Linux 5.3, use fallback
+ .XDEV => {},
+ // syscall added in Linux 4.5, use fallback
+ .NOSYS => {
+ bun.Output.debug("copy_file_range is NOT supported", .{});
+ can_use_copy_file_range.store(-1, .Monotonic);
+ },
+ else => |err| return os.unexpectedErrno(err),
+ }
+ }
+
+ var buf: [8 * 4096]u8 = undefined;
+ const adjusted_count = @minimum(buf.len, len);
+ const amt_read = try os.pread(fd_in, buf[0..adjusted_count], off_in);
+ // TODO without @as the line below fails to compile for wasm32-wasi:
+ // error: integer value 0 cannot be coerced to type 'os.PWriteError!usize'
+ if (amt_read == 0) return @as(usize, 0);
+ return os.pwrite(fd_out, buf[0..amt_read], off_out);
+}
diff --git a/src/install/install.zig b/src/install/install.zig
index c83f15fc5..cb5a350ca 100644
--- a/src/install/install.zig
+++ b/src/install/install.zig
@@ -1003,7 +1003,6 @@ const PackageInstall = struct {
}
fn installWithCopyfile(this: *PackageInstall) Result {
const Walker = @import("../walker_skippable.zig");
- const CopyFile = @import("../copy_file.zig");
var cached_package_dir = this.cache_dir.openDirZ(this.cache_dir_subpath, .{
.iterate = true,
@@ -1053,15 +1052,13 @@ const PackageInstall = struct {
const stat = infile.stat() catch continue;
_ = C.fchmod(outfile.handle, stat.mode);
- CopyFile.copy(infile.handle, outfile.handle) catch {
- entry.dir.copyFile(entry.basename, destination_dir_, entry.path, .{}) catch |err| {
- progress_.root.end();
+ bun.copyFile(infile.handle, outfile.handle) catch |err| {
+ progress_.root.end();
- progress_.refresh();
+ progress_.refresh();
- Output.prettyErrorln("<r><red>{s}<r>: copying file {s}", .{ @errorName(err), entry.path });
- Global.exit(1);
- };
+ Output.prettyErrorln("<r><red>{s}<r>: copying file {s}", .{ @errorName(err), entry.path });
+ Global.exit(1);
};
}
diff --git a/src/linux_c.zig b/src/linux_c.zig
index b200becdc..7758a9aa8 100644
--- a/src/linux_c.zig
+++ b/src/linux_c.zig
@@ -1,5 +1,6 @@
const std = @import("std");
const sysResource = @cImport(@cInclude("sys/resource.h"));
+const bun = @import("bun");
pub const SystemErrno = enum(u8) {
SUCCESS = 0,
EPERM = 1,
@@ -456,11 +457,21 @@ pub const POSIX_SPAWN_SETSIGMASK = @as(c_int, 0x08);
pub const POSIX_SPAWN_SETSCHEDPARAM = @as(c_int, 0x10);
pub const POSIX_SPAWN_SETSCHEDULER = @as(c_int, 0x20);
-pub extern "c" fn posix_spawn_file_actions_addfchdir_np(actions: *posix_spawn_file_actions_t, filedes: fd_t) c_int;
+const posix_spawn_file_actions_addfchdir_np_type = fn (actions: *posix_spawn_file_actions_t, filedes: fd_t) c_int;
+const posix_spawn_file_actions_addchdir_np_type = fn (actions: *posix_spawn_file_actions_t, path: [*:0]const u8) c_int;
-// not available in linux
-// pub extern "c" fn posix_spawn_file_actions_addinherit_np(actions: *posix_spawn_file_actions_t, filedes: fd_t) c_int;
+/// When not available, these functions will return 0.
+pub fn posix_spawn_file_actions_addfchdir_np(actions: *posix_spawn_file_actions_t, filedes: std.os.fd_t) c_int {
+ var function = bun.C.dlsym(posix_spawn_file_actions_addfchdir_np_type, "posix_spawn_file_actions_addfchdir_np") orelse
+ return 0;
+ return function(actions, filedes);
+}
-pub extern "c" fn posix_spawn_file_actions_addchdir_np(actions: *posix_spawn_file_actions_t, path: [*:0]const u8) c_int;
+/// When not available, these functions will return 0.
+pub fn posix_spawn_file_actions_addchdir_np(actions: *posix_spawn_file_actions_t, path: [*:0]const u8) c_int {
+ var function = bun.C.dlsym(posix_spawn_file_actions_addchdir_np_type, "posix_spawn_file_actions_addchdir_np") orelse
+ return 0;
+ return function(actions, path);
+}
pub extern fn vmsplice(fd: c_int, iovec: [*]const std.os.iovec, iovec_count: usize, flags: u32) isize;
diff --git a/src/options.zig b/src/options.zig
index 4f62ddfe5..97f0cf62f 100644
--- a/src/options.zig
+++ b/src/options.zig
@@ -1838,42 +1838,7 @@ pub const OutputFile = struct {
}
}
- const os = std.os;
-
- if (comptime @import("builtin").target.isDarwin()) {
- const rc = os.system.fcopyfile(fd_in, fd_out, null, os.system.COPYFILE_DATA);
- if (rc == 0) {
- return;
- }
- }
-
- if (@import("builtin").target.os.tag == .linux) {
- // Try copy_file_range first as that works at the FS level and is the
- // most efficient method (if available).
- var offset: u64 = 0;
- cfr_loop: while (true) {
- const math = std.math;
- // The kernel checks the u64 value `offset+count` for overflow, use
- // a 32 bit value so that the syscall won't return EINVAL except for
- // impossibly large files (> 2^64-1 - 2^32-1).
- const amt = try os.copy_file_range(fd_in, offset, fd_out, offset, math.maxInt(u32), 0);
- // Terminate when no data was copied
- if (amt == 0) break :cfr_loop;
- offset += amt;
- }
- return;
- }
-
- // Sendfile is a zero-copy mechanism iff the OS supports it, otherwise the
- // fallback code will copy the contents chunk by chunk.
- const empty_iovec = [0]os.iovec_const{};
- var offset: u64 = 0;
- sendfile_loop: while (true) {
- const amt = try os.sendfile(fd_out, fd_in, offset, 0, &empty_iovec, &empty_iovec, 0);
- // Terminate when no data was copied
- if (amt == 0) break :sendfile_loop;
- offset += amt;
- }
+ try bun.copyFile(fd_in, fd_out);
}
};