mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
fix: handle EINVAL from copy_file_range on eCryptfs (#25534)
## Summary - Add `EINVAL` and `OPNOTSUPP` to the list of errors that trigger fallback from `copy_file_range` to `sendfile`/read-write loop - Fixes `Bun.write` and `fs.copyFile` failing on eCryptfs filesystems ## Test plan - [x] Existing `copyFile` tests pass (`bun bd test test/js/node/fs/fs.test.ts -t "copyFile"`) - [x] Existing `copy_file_range` fallback tests pass (`bun bd test test/js/bun/io/bun-write.test.js -t "should work when copyFileRange is not available"`) Fixes #13968 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Bot <claude-bot@bun.sh> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
This commit is contained in:
@@ -3678,8 +3678,12 @@ pub const NodeFS = struct {
|
||||
if (ret.errnoSysP(written, .copy_file_range, dest)) |err| {
|
||||
return switch (err.getErrno()) {
|
||||
.INTR => continue,
|
||||
inline .XDEV, .NOSYS => |errno| brk: {
|
||||
if (comptime errno == .NOSYS) {
|
||||
// EINVAL: eCryptfs and other filesystems may not support copy_file_range
|
||||
// XDEV: cross-device copy not supported
|
||||
// NOSYS: syscall not available
|
||||
// OPNOTSUPP: filesystem doesn't support this operation
|
||||
inline .XDEV, .NOSYS, .INVAL, .OPNOTSUPP => |errno| brk: {
|
||||
if (comptime errno == .NOSYS or errno == .OPNOTSUPP) {
|
||||
bun.disableCopyFileRangeSyscall();
|
||||
}
|
||||
break :brk copyFileUsingSendfileOnLinuxWithReadWriteFallback(src, dest, src_fd, dest_fd, size, &wrote);
|
||||
@@ -3699,8 +3703,12 @@ pub const NodeFS = struct {
|
||||
if (ret.errnoSysP(written, .copy_file_range, dest)) |err| {
|
||||
return switch (err.getErrno()) {
|
||||
.INTR => continue,
|
||||
inline .XDEV, .NOSYS => |errno| brk: {
|
||||
if (comptime errno == .NOSYS) {
|
||||
// EINVAL: eCryptfs and other filesystems may not support copy_file_range
|
||||
// XDEV: cross-device copy not supported
|
||||
// NOSYS: syscall not available
|
||||
// OPNOTSUPP: filesystem doesn't support this operation
|
||||
inline .XDEV, .NOSYS, .INVAL, .OPNOTSUPP => |errno| brk: {
|
||||
if (comptime errno == .NOSYS or errno == .OPNOTSUPP) {
|
||||
bun.disableCopyFileRangeSyscall();
|
||||
}
|
||||
break :brk copyFileUsingSendfileOnLinuxWithReadWriteFallback(src, dest, src_fd, dest_fd, size, &wrote);
|
||||
@@ -6431,8 +6439,12 @@ pub const NodeFS = struct {
|
||||
const written = linux.copy_file_range(src_fd.cast(), &off_in_copy, dest_fd.cast(), &off_out_copy, std.heap.pageSize(), 0);
|
||||
if (ret.errnoSysP(written, .copy_file_range, dest)) |err| {
|
||||
return switch (err.getErrno()) {
|
||||
inline .XDEV, .NOSYS => |errno| brk: {
|
||||
if (comptime errno == .NOSYS) {
|
||||
// EINVAL: eCryptfs and other filesystems may not support copy_file_range
|
||||
// XDEV: cross-device copy not supported
|
||||
// NOSYS: syscall not available
|
||||
// OPNOTSUPP: filesystem doesn't support this operation
|
||||
inline .XDEV, .NOSYS, .INVAL, .OPNOTSUPP => |errno| brk: {
|
||||
if (comptime errno == .NOSYS or errno == .OPNOTSUPP) {
|
||||
bun.disableCopyFileRangeSyscall();
|
||||
}
|
||||
break :brk copyFileUsingSendfileOnLinuxWithReadWriteFallback(src, dest, src_fd, dest_fd, size, &wrote);
|
||||
@@ -6451,8 +6463,12 @@ pub const NodeFS = struct {
|
||||
const written = linux.copy_file_range(src_fd.cast(), &off_in_copy, dest_fd.cast(), &off_out_copy, size, 0);
|
||||
if (ret.errnoSysP(written, .copy_file_range, dest)) |err| {
|
||||
return switch (err.getErrno()) {
|
||||
inline .XDEV, .NOSYS => |errno| brk: {
|
||||
if (comptime errno == .NOSYS) {
|
||||
// EINVAL: eCryptfs and other filesystems may not support copy_file_range
|
||||
// XDEV: cross-device copy not supported
|
||||
// NOSYS: syscall not available
|
||||
// OPNOTSUPP: filesystem doesn't support this operation
|
||||
inline .XDEV, .NOSYS, .INVAL, .OPNOTSUPP => |errno| brk: {
|
||||
if (comptime errno == .NOSYS or errno == .OPNOTSUPP) {
|
||||
bun.disableCopyFileRangeSyscall();
|
||||
}
|
||||
break :brk copyFileUsingSendfileOnLinuxWithReadWriteFallback(src, dest, src_fd, dest_fd, size, &wrote);
|
||||
|
||||
@@ -257,7 +257,10 @@ pub const CopyFile = struct {
|
||||
switch (bun.sys.getErrno(written)) {
|
||||
.SUCCESS => {},
|
||||
|
||||
.NOSYS, .XDEV => {
|
||||
// XDEV: cross-device copy not supported
|
||||
// NOSYS: syscall not available
|
||||
// OPNOTSUPP: filesystem doesn't support this operation
|
||||
.NOSYS, .XDEV, .OPNOTSUPP => {
|
||||
// TODO: this should use non-blocking I/O.
|
||||
switch (jsc.Node.fs.NodeFS.copyFileUsingReadWriteLoop("", "", src_fd, dest_fd, if (unknown_size) 0 else remain, &total_written)) {
|
||||
.err => |err| {
|
||||
@@ -271,6 +274,8 @@ pub const CopyFile = struct {
|
||||
}
|
||||
},
|
||||
|
||||
// EINVAL: eCryptfs and other filesystems may not support copy_file_range.
|
||||
// Also returned when the file descriptor is incompatible with the syscall.
|
||||
.INVAL => {
|
||||
if (comptime clear_append_if_invalid) {
|
||||
if (!has_unset_append) {
|
||||
@@ -287,7 +292,7 @@ pub const CopyFile = struct {
|
||||
}
|
||||
|
||||
// If the Linux machine doesn't support
|
||||
// copy_file_range or the file descrpitor is
|
||||
// copy_file_range or the file descriptor is
|
||||
// incompatible with the chosen syscall, fall back
|
||||
// to a read/write loop
|
||||
if (total_written == 0) {
|
||||
|
||||
Reference in New Issue
Block a user