authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-11-02 18:46:17-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-11-03 15:25:43-07:00
logede41759be736a1c4ce2a6dbdd8f2d0b5afceb5f
tree76107a498ce75f89ba4d3f514b1af1afd089de35
parent37bc6ee54a388717095ab59959e5b0282d1ef8ef

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, .{});

1 files changed, 46 insertions(+), 2 deletions(-)

lib/std/fs/file.zig+46-2
...@@ -690,10 +690,54 @@ pub const File = struct {...@@ -690,10 +690,54 @@ pub const File = struct {
690 header_count: usize = 0,690 header_count: usize = 0,
691 };691 };
692692
693 pub const WriteFileError = os.SendFileError;693 pub const WriteFileError = ReadError || WriteError;
694694
695 /// TODO integrate with async I/O
696 pub fn writeFileAll(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void {695 pub fn writeFileAll(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void {
696 return self.writeFileAllSendfile(in_file, args) catch |err| switch (err) {
697 error.Unseekable,
698 error.FastOpenAlreadyInProgress,
699 error.MessageTooBig,
700 error.FileDescriptorNotASocket,
701 => return self.writeFileAllUnseekable(in_file, args),
702
703 else => |e| return e,
704 };
705 }
706
707 /// Does not try seeking in either of the File parameters.
708 /// See `writeFileAll` as an alternative to calling this.
709 pub fn writeFileAllUnseekable(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void {
710 const headers = args.headers_and_trailers[0..args.header_count];
711 const trailers = args.headers_and_trailers[args.header_count..];
712
713 try self.writevAll(headers);
714
715 var buffer: [4096]u8 = undefined;
716 {
717 var index: usize = 0;
718 // Skip in_offset bytes.
719 while (index < args.in_offset) {
720 const ask = math.min(buffer.len, args.in_offset - index);
721 const amt = try in_file.read(buffer[0..ask]);
722 index += amt;
723 }
724 }
725 const in_len = args.in_len orelse math.maxInt(u64);
726 var index: usize = 0;
727 while (index < in_len) {
728 const ask = math.min(buffer.len, in_len - index);
729 const amt = try in_file.read(buffer[0..ask]);
730 if (amt == 0) break;
731 index += try self.write(buffer[0..amt]);
732 }
733
734 try self.writevAll(trailers);
735 }
736
737 /// Low level function which can fail for OS-specific reasons.
738 /// See `writeFileAll` as an alternative to calling this.
739 /// TODO integrate with async I/O
740 fn writeFileAllSendfile(self: File, in_file: File, args: WriteFileOptions) os.SendFileError!void {
697 const count = blk: {741 const count = blk: {
698 if (args.in_len) |l| {742 if (args.in_len) |l| {
699 if (l == 0) {743 if (l == 0) {