feature. See also
. The project being documented here (as the example) is the Zig library itself.
Threaded.fileWriteFilePositional
fn fileWriteFilePositional(
userdata: ?*anyopaque,
file: File,
header: []const u8,
file_reader: *File.Reader,
limit: Io.Limit,
offset: u64,
) File.WriteFilePositionalError!usize
File
Code
fn fileWriteFilePositional(
userdata: ?*anyopaque,
file: File,
header: []const u8,
file_reader: *File.Reader,
limit: Io.Limit,
offset: u64,
) File.WriteFilePositionalError!usize {
const t: *Threaded = @ptrCast(@alignCast(userdata));
const reader_buffered = file_reader.interface.buffered();
if (reader_buffered.len >= @backingInt(limit)) {
const n = try fileWritePositional(t, file, header, &.{limit.slice(reader_buffered)}, 1, offset);
file_reader.interface.toss(n -| header.len);
return n;
}
const out_fd = file.handle;
const in_fd = file_reader.file.handle;
if (file_reader.size) |size| {
if (size - file_reader.pos == 0) {
if (reader_buffered.len != 0) {
const n = try fileWritePositional(t, file, header, &.{limit.slice(reader_buffered)}, 1, offset);
file_reader.interface.toss(n -| header.len);
return n;
} else {
return error.EndOfStream;
}
}
}
if (have_copy_file_range) cfr: {
if (@atomicLoad(UseCopyFileRange, &t.use_copy_file_range, .monotonic) == .disabled) break :cfr;
if (header.len != 0 or reader_buffered.len != 0) {
const n = try fileWritePositional(t, file, header, &.{limit.slice(reader_buffered)}, 1, offset);
file_reader.interface.toss(n -| header.len);
return n;
}
var len: usize = @min(@backingInt(limit), std.math.maxInt(usize) - offset);
var off_in: i64 = undefined;
const off_in_ptr: ?*i64 = switch (file_reader.mode) {
.positional_simple, .streaming_simple => return error.Unimplemented,
.positional => p: {
len = @min(len, std.math.maxInt(usize) - file_reader.pos);
off_in = @intCast(file_reader.pos);
break :p &off_in;
},
.streaming => null,
.failure => return error.ReadFailed,
};
var off_out: i64 = @intCast(offset);
const n: usize = switch (native_os) {
.linux => n: {
const syscall: Syscall = try .start();
while (true) {
const rc = linux_copy_file_range_sys.copy_file_range(in_fd, off_in_ptr, out_fd, &off_out, len, 0);
switch (linux_copy_file_range_sys.errno(rc)) {
.SUCCESS => {
syscall.finish();
break :n @intCast(rc);
},
.INTR => {
try syscall.checkCancel();
continue;
},
.OPNOTSUPP, .INVAL, .NOSYS => {
// something else.
syscall.finish();
@atomicStore(UseCopyFileRange, &t.use_copy_file_range, .disabled, .monotonic);
return 0;
},
else => |e| {
syscall.finish();
assert(error.Unexpected == switch (e) {
.FBIG => return error.FileTooBig,
.IO => return error.InputOutput,
.NOMEM => return error.SystemResources,
.NOSPC => return error.NoSpaceLeft,
.OVERFLOW => |err| errnoBug(err),
.NXIO => return error.Unseekable,
.SPIPE => return error.Unseekable,
.PERM => return error.PermissionDenied,
.TXTBSY => return error.FileBusy,
// this pair of file descriptors.
.XDEV => return error.Unimplemented,
.ISDIR => |err| errnoBug(err),
.BADF => |err| errnoBug(err),
else => |err| posix.unexpectedErrno(err),
});
@atomicStore(UseCopyFileRange, &t.use_copy_file_range, .disabled, .monotonic);
return 0;
},
}
}
},
.freebsd => n: {
const syscall: Syscall = try .start();
while (true) {
const rc = std.c.copy_file_range(in_fd, off_in_ptr, out_fd, &off_out, @backingInt(limit), 0);
switch (std.c.errno(rc)) {
.SUCCESS => {
syscall.finish();
break :n @intCast(rc);
},
.INTR => {
try syscall.checkCancel();
continue;
},
.OPNOTSUPP, .INVAL, .NOSYS => {
// something else.
syscall.finish();
@atomicStore(UseCopyFileRange, &t.use_copy_file_range, .disabled, .monotonic);
return 0;
},
else => |e| {
syscall.finish();
assert(error.Unexpected == switch (e) {
.FBIG => return error.FileTooBig,
.IO => return error.InputOutput,
.INTEGRITY => return error.CorruptedData,
.NOSPC => return error.NoSpaceLeft,
.OVERFLOW => return error.Unseekable,
.NXIO => return error.Unseekable,
.SPIPE => return error.Unseekable,
.ISDIR => |err| errnoBug(err),
.BADF => |err| errnoBug(err),
else => |err| posix.unexpectedErrno(err),
});
@atomicStore(UseCopyFileRange, &t.use_copy_file_range, .disabled, .monotonic);
return 0;
},
}
}
},
else => comptime unreachable,
};
if (n == 0) {
file_reader.size = file_reader.pos;
return error.EndOfStream;
}
file_reader.pos += n;
return n;
}
if (is_darwin) fcf: {
if (@atomicLoad(UseFcopyfile, &t.use_fcopyfile, .monotonic) == .disabled) break :fcf;
if (file_reader.pos != 0) break :fcf;
if (offset != 0) break :fcf;
if (limit != .unlimited) break :fcf;
const size = file_reader.getSize() catch break :fcf;
if (header.len != 0 or reader_buffered.len != 0) {
const n = try fileWritePositional(t, file, header, &.{limit.slice(reader_buffered)}, 1, offset);
file_reader.interface.toss(n -| header.len);
return n;
}
const syscall: Syscall = try .start();
while (true) {
const rc = std.c.fcopyfile(in_fd, out_fd, null, .{ .DATA = true });
switch (posix.errno(rc)) {
.SUCCESS => {
syscall.finish();
break;
},
.INTR => {
try syscall.checkCancel();
continue;
},
.OPNOTSUPP => {
// something else.
syscall.finish();
@atomicStore(UseFcopyfile, &t.use_fcopyfile, .disabled, .monotonic);
return 0;
},
else => |e| {
syscall.finish();
assert(error.Unexpected == switch (e) {
.NOMEM => return error.SystemResources,
.INVAL => |err| errnoBug(err),
else => |err| posix.unexpectedErrno(err),
});
return 0;
},
}
}
file_reader.pos = size;
return size;
}
return error.Unimplemented;
}