| ... | ... | @@ -1240,6 +1240,8 @@ pub const Reader = struct { |
| 1240 | 1240 | file: File, |
| 1241 | 1241 | err: ?ReadError = null, |
| 1242 | 1242 | mode: Reader.Mode = .positional, |
| 1243 | /// Tracks the true seek position in the file. To obtain the logical |
| 1244 | /// position, subtract the buffer size from this value. |
| 1243 | 1245 | pos: u64 = 0, |
| 1244 | 1246 | size: ?u64 = null, |
| 1245 | 1247 | size_err: ?GetEndPosError = null, |
| ... | ... | @@ -1407,10 +1409,14 @@ pub const Reader = struct { |
| 1407 | 1409 | const n = posix.preadv(r.file.handle, dest, r.pos) catch |err| switch (err) { |
| 1408 | 1410 | error.Unseekable => { |
| 1409 | 1411 | r.mode = r.mode.toStreaming(); |
| 1410 | | if (r.pos != 0) r.seekBy(@intCast(r.pos)) catch { |
| 1411 | | r.mode = .failure; |
| 1412 | | return error.ReadFailed; |
| 1413 | | }; |
| 1412 | const pos = r.pos; |
| 1413 | if (pos != 0) { |
| 1414 | r.pos = 0; |
| 1415 | r.seekBy(@intCast(pos)) catch { |
| 1416 | r.mode = .failure; |
| 1417 | return error.ReadFailed; |
| 1418 | }; |
| 1419 | } |
| 1414 | 1420 | return 0; |
| 1415 | 1421 | }, |
| 1416 | 1422 | else => |e| { |
| ... | ... | @@ -1535,10 +1541,14 @@ pub const Reader = struct { |
| 1535 | 1541 | const n = r.file.pread(dest, r.pos) catch |err| switch (err) { |
| 1536 | 1542 | error.Unseekable => { |
| 1537 | 1543 | r.mode = r.mode.toStreaming(); |
| 1538 | | if (r.pos != 0) r.seekBy(@intCast(r.pos)) catch { |
| 1539 | | r.mode = .failure; |
| 1540 | | return error.ReadFailed; |
| 1541 | | }; |
| 1544 | const pos = r.pos; |
| 1545 | if (pos != 0) { |
| 1546 | r.pos = 0; |
| 1547 | r.seekBy(@intCast(pos)) catch { |
| 1548 | r.mode = .failure; |
| 1549 | return error.ReadFailed; |
| 1550 | }; |
| 1551 | } |
| 1542 | 1552 | return 0; |
| 1543 | 1553 | }, |
| 1544 | 1554 | else => |e| { |
| ... | ... | @@ -1586,6 +1596,8 @@ pub const Writer = struct { |
| 1586 | 1596 | file: File, |
| 1587 | 1597 | err: ?WriteError = null, |
| 1588 | 1598 | mode: Writer.Mode = .positional, |
| 1599 | /// Tracks the true seek position in the file. To obtain the logical |
| 1600 | /// position, add the buffer size to this value. |
| 1589 | 1601 | pos: u64 = 0, |
| 1590 | 1602 | sendfile_err: ?SendfileError = null, |
| 1591 | 1603 | copy_file_range_err: ?CopyFileRangeError = null, |
| ... | ... | @@ -1652,32 +1664,36 @@ pub const Writer = struct { |
| 1652 | 1664 | const w: *Writer = @fieldParentPtr("interface", io_w); |
| 1653 | 1665 | const handle = w.file.handle; |
| 1654 | 1666 | const buffered = io_w.buffered(); |
| 1655 | | if (is_windows) { |
| 1656 | | var i: usize = 0; |
| 1657 | | while (i < buffered.len) { |
| 1658 | | const n = windows.WriteFile(handle, buffered[i..], null) catch |err| { |
| 1659 | | w.err = err; |
| 1660 | | w.pos += i; |
| 1661 | | _ = io_w.consume(i); |
| 1662 | | return error.WriteFailed; |
| 1663 | | }; |
| 1664 | | i += n; |
| 1665 | | if (data.len > 0 and buffered.len - i < n) { |
| 1667 | if (is_windows) switch (w.mode) { |
| 1668 | .positional, .positional_reading => @panic("TODO"), |
| 1669 | .streaming, .streaming_reading => { |
| 1670 | var i: usize = 0; |
| 1671 | while (i < buffered.len) { |
| 1672 | const n = windows.WriteFile(handle, buffered[i..], null) catch |err| { |
| 1673 | w.err = err; |
| 1674 | w.pos += i; |
| 1675 | _ = io_w.consume(i); |
| 1676 | return error.WriteFailed; |
| 1677 | }; |
| 1678 | i += n; |
| 1679 | if (data.len > 0 and buffered.len - i < n) { |
| 1680 | w.pos += i; |
| 1681 | return io_w.consume(i); |
| 1682 | } |
| 1683 | } |
| 1684 | if (i != 0 or data.len == 0 or (data.len == 1 and splat == 0)) { |
| 1666 | 1685 | w.pos += i; |
| 1667 | 1686 | return io_w.consume(i); |
| 1668 | 1687 | } |
| 1669 | | } |
| 1670 | | if (i != 0 or data.len == 0 or (data.len == 1 and splat == 0)) { |
| 1671 | | w.pos += i; |
| 1672 | | return io_w.consume(i); |
| 1673 | | } |
| 1674 | | const n = windows.WriteFile(handle, data[0], null) catch |err| { |
| 1675 | | w.err = err; |
| 1676 | | return 0; |
| 1677 | | }; |
| 1678 | | w.pos += n; |
| 1679 | | return n; |
| 1680 | | } |
| 1688 | const n = windows.WriteFile(handle, data[0], null) catch |err| { |
| 1689 | w.err = err; |
| 1690 | return 0; |
| 1691 | }; |
| 1692 | w.pos += n; |
| 1693 | return n; |
| 1694 | }, |
| 1695 | .failure => return error.WriteFailed, |
| 1696 | }; |
| 1681 | 1697 | var iovecs: [max_buffers_len]std.posix.iovec_const = undefined; |
| 1682 | 1698 | var len: usize = 0; |
| 1683 | 1699 | if (buffered.len > 0) { |
| ... | ... | @@ -1733,12 +1749,39 @@ pub const Writer = struct { |
| 1733 | 1749 | }, |
| 1734 | 1750 | }, |
| 1735 | 1751 | } |
| 1736 | | const n = std.posix.writev(handle, iovecs[0..len]) catch |err| { |
| 1737 | | w.err = err; |
| 1738 | | return error.WriteFailed; |
| 1739 | | }; |
| 1740 | | w.pos += n; |
| 1741 | | return io_w.consume(n); |
| 1752 | switch (w.mode) { |
| 1753 | .positional, .positional_reading => { |
| 1754 | const n = std.posix.pwritev(handle, iovecs[0..len], w.pos) catch |err| switch (err) { |
| 1755 | error.Unseekable => { |
| 1756 | w.mode = w.mode.toStreaming(); |
| 1757 | const pos = w.pos; |
| 1758 | if (pos != 0) { |
| 1759 | w.pos = 0; |
| 1760 | w.seekTo(@intCast(pos)) catch { |
| 1761 | w.mode = .failure; |
| 1762 | return error.WriteFailed; |
| 1763 | }; |
| 1764 | } |
| 1765 | return 0; |
| 1766 | }, |
| 1767 | else => |e| { |
| 1768 | w.err = e; |
| 1769 | return error.WriteFailed; |
| 1770 | }, |
| 1771 | }; |
| 1772 | w.pos += n; |
| 1773 | return io_w.consume(n); |
| 1774 | }, |
| 1775 | .streaming, .streaming_reading => { |
| 1776 | const n = std.posix.writev(handle, iovecs[0..len]) catch |err| { |
| 1777 | w.err = err; |
| 1778 | return error.WriteFailed; |
| 1779 | }; |
| 1780 | w.pos += n; |
| 1781 | return io_w.consume(n); |
| 1782 | }, |
| 1783 | .failure => return error.WriteFailed, |
| 1784 | } |
| 1742 | 1785 | } |
| 1743 | 1786 | |
| 1744 | 1787 | pub fn sendFile( |
| ... | ... | @@ -1781,10 +1824,14 @@ pub const Writer = struct { |
| 1781 | 1824 | const n = std.os.linux.wrapped.sendfile(out_fd, in_fd, off_ptr, count) catch |err| switch (err) { |
| 1782 | 1825 | error.Unseekable => { |
| 1783 | 1826 | file_reader.mode = file_reader.mode.toStreaming(); |
| 1784 | | if (file_reader.pos != 0) file_reader.seekBy(@intCast(file_reader.pos)) catch { |
| 1785 | | file_reader.mode = .failure; |
| 1786 | | return error.ReadFailed; |
| 1787 | | }; |
| 1827 | const pos = file_reader.pos; |
| 1828 | if (pos != 0) { |
| 1829 | file_reader.pos = 0; |
| 1830 | file_reader.seekBy(@intCast(pos)) catch { |
| 1831 | file_reader.mode = .failure; |
| 1832 | return error.ReadFailed; |
| 1833 | }; |
| 1834 | } |
| 1788 | 1835 | return 0; |
| 1789 | 1836 | }, |
| 1790 | 1837 | else => |e| { |
| ... | ... | @@ -1877,17 +1924,19 @@ pub const Writer = struct { |
| 1877 | 1924 | } |
| 1878 | 1925 | |
| 1879 | 1926 | pub fn seekTo(w: *Writer, offset: u64) SeekError!void { |
| 1880 | | if (w.seek_err) |err| return err; |
| 1881 | 1927 | switch (w.mode) { |
| 1882 | 1928 | .positional, .positional_reading => { |
| 1883 | 1929 | w.pos = offset; |
| 1884 | 1930 | }, |
| 1885 | 1931 | .streaming, .streaming_reading => { |
| 1932 | if (w.seek_err) |err| return err; |
| 1886 | 1933 | posix.lseek_SET(w.file.handle, offset) catch |err| { |
| 1887 | 1934 | w.seek_err = err; |
| 1888 | 1935 | return err; |
| 1889 | 1936 | }; |
| 1937 | w.pos = offset; |
| 1890 | 1938 | }, |
| 1939 | .failure => return w.seek_err.?, |
| 1891 | 1940 | } |
| 1892 | 1941 | } |
| 1893 | 1942 | |