authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-06 16:58:48-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-07 22:43:53-07:00
logfd7feed04b8d10fd8f77a3106f068c071d2ad24c
treeedbe58999bec9094a4ceb1afece65f6d13bd34ed
parent7e2a26c0c441a902968726442114e3590820433b

std.fs.File.Writer: implement positional writing


1 files changed, 91 insertions(+), 42 deletions(-)

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