diff options
author | 2022-12-06 14:14:27 -0800 | |
---|---|---|
committer | 2022-12-06 14:14:27 -0800 | |
commit | 81317a52ea13b39de22d2cdeff8ecc231224f9e7 (patch) | |
tree | 677bc306ab6b56937f024a5bdf3e8b624b7137c6 | |
parent | 7d29782896f31ae5249f00e9505fd978e9733644 (diff) | |
download | bun-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-- | Makefile | 16 | ||||
-rw-r--r-- | packages/bun-types/bun.d.ts | 7 | ||||
-rw-r--r-- | src/bun.js/api/bun/socket.zig | 6 | ||||
-rw-r--r-- | src/bun.js/bindings/BunJSCModule.cpp | 8 | ||||
-rw-r--r-- | src/bun.js/bindings/ModuleLoader.cpp | 2 | ||||
-rw-r--r-- | src/bun.js/bindings/glibc-versions-hack.cpp | 124 | ||||
-rw-r--r-- | src/bun.js/node/node_fs.zig | 17 | ||||
-rw-r--r-- | src/bun.zig | 4 | ||||
-rw-r--r-- | src/c.zig | 36 | ||||
-rw-r--r-- | src/cli/create_command.zig | 12 | ||||
-rw-r--r-- | src/copy_file.zig | 86 | ||||
-rw-r--r-- | src/install/install.zig | 13 | ||||
-rw-r--r-- | src/linux_c.zig | 19 | ||||
-rw-r--r-- | src/options.zig | 37 |
14 files changed, 317 insertions, 70 deletions
@@ -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; @@ -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); } }; |