zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit ede41759be736a1c4ce2a6dbdd8f2d0b5afceb5f (tree)
parent 37bc6ee54a388717095ab59959e5b0282d1ef8ef
Author: Andrew Kelley <andrew@ziglang.org>
Date:   Mon,  2 Nov 2020 18:46:17 -0700

std.fs.File.writeFileAll: support unseekable files

With this commit, the function tries to use more efficient syscalls, and
then falls back to non-positional reads.

The motivating use case for this change is to support something like the
following:

try io.getStdOut().writeFileAll(dest_file, .{});

Diffstat:
Mlib/std/fs/file.zig | 48++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 46 insertions(+), 2 deletions(-)

diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig @@ -690,10 +690,54 @@ pub const File = struct { header_count: usize = 0, }; - pub const WriteFileError = os.SendFileError; + pub const WriteFileError = ReadError || WriteError; - /// TODO integrate with async I/O pub fn writeFileAll(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void { + return self.writeFileAllSendfile(in_file, args) catch |err| switch (err) { + error.Unseekable, + error.FastOpenAlreadyInProgress, + error.MessageTooBig, + error.FileDescriptorNotASocket, + => return self.writeFileAllUnseekable(in_file, args), + + else => |e| return e, + }; + } + + /// Does not try seeking in either of the File parameters. + /// See `writeFileAll` as an alternative to calling this. + pub fn writeFileAllUnseekable(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void { + const headers = args.headers_and_trailers[0..args.header_count]; + const trailers = args.headers_and_trailers[args.header_count..]; + + try self.writevAll(headers); + + var buffer: [4096]u8 = undefined; + { + var index: usize = 0; + // Skip in_offset bytes. + while (index < args.in_offset) { + const ask = math.min(buffer.len, args.in_offset - index); + const amt = try in_file.read(buffer[0..ask]); + index += amt; + } + } + const in_len = args.in_len orelse math.maxInt(u64); + var index: usize = 0; + while (index < in_len) { + const ask = math.min(buffer.len, in_len - index); + const amt = try in_file.read(buffer[0..ask]); + if (amt == 0) break; + index += try self.write(buffer[0..amt]); + } + + try self.writevAll(trailers); + } + + /// Low level function which can fail for OS-specific reasons. + /// See `writeFileAll` as an alternative to calling this. + /// TODO integrate with async I/O + fn writeFileAllSendfile(self: File, in_file: File, args: WriteFileOptions) os.SendFileError!void { const count = blk: { if (args.in_len) |l| { if (l == 0) {