| ... | ... | @@ -690,10 +690,54 @@ pub const File = struct { |
| 690 | 690 | header_count: usize = 0, |
| 691 | 691 | }; |
| 692 | 692 | |
| 693 | | pub const WriteFileError = os.SendFileError; |
| 693 | pub const WriteFileError = ReadError || WriteError; |
| 694 | 694 | |
| 695 | | /// TODO integrate with async I/O |
| 696 | 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 | 741 | const count = blk: { |
| 698 | 742 | if (args.in_len) |l| { |
| 699 | 743 | if (l == 0) { |