| ... | @@ -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 | }; |
| 692 | | 692 | |
| 693 | pub const WriteFileError = os.SendFileError; | 693 | pub const WriteFileError = ReadError || WriteError; |
| 694 | | 694 | |
| 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) { |