authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-21 18:13:45-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-21 18:14:21-07:00
logb35c55e2373ace674cd1eec7f5086b805d1c8256
treeb884a2c4c2e4133b4f40dc9499f66b430df60b1b
parentfe10c66d664ae7b1acb2bcf01600eeacc2958fc7

std.fs.File.Reader: fix seek position logic


2 files changed, 54 insertions(+), 7 deletions(-)

lib/std/fs/File.zig+10-4
...@@ -1135,7 +1135,7 @@ pub const Reader = struct {...@@ -1135,7 +1135,7 @@ pub const Reader = struct {
1135 err: ?ReadError = null,1135 err: ?ReadError = null,
1136 mode: Reader.Mode = .positional,1136 mode: Reader.Mode = .positional,
1137 /// Tracks the true seek position in the file. To obtain the logical1137 /// Tracks the true seek position in the file. To obtain the logical
1138 /// position, subtract the buffer size from this value.1138 /// position, use `logicalPos`.
1139 pos: u64 = 0,1139 pos: u64 = 0,
1140 size: ?u64 = null,1140 size: ?u64 = null,
1141 size_err: ?GetEndPosError = null,1141 size_err: ?GetEndPosError = null,
...@@ -1274,14 +1274,20 @@ pub const Reader = struct {...@@ -1274,14 +1274,20 @@ pub const Reader = struct {
1274 }1274 }
1275 }1275 }
12761276
1277 pub fn logicalPos(r: *const Reader) u64 {
1278 return r.pos - r.interface.bufferedLen();
1279 }
1280
1277 fn setPosAdjustingBuffer(r: *Reader, offset: u64) void {1281 fn setPosAdjustingBuffer(r: *Reader, offset: u64) void {
1278 if (offset < r.pos or offset >= r.pos + r.interface.bufferedLen()) {1282 const logical_pos = logicalPos(r);
1283 if (offset < logical_pos or offset >= r.pos) {
1279 r.interface.seek = 0;1284 r.interface.seek = 0;
1280 r.interface.end = 0;1285 r.interface.end = 0;
1286 r.pos = offset;
1281 } else {1287 } else {
1282 r.interface.seek += @intCast(offset - r.pos);1288 const logical_delta: usize = @intCast(offset - logical_pos);
1289 r.interface.seek += logical_delta;
1283 }1290 }
1284 r.pos = offset;
1285 }1291 }
12861292
1287 /// Number of slices to store on the stack, when trying to send as many byte1293 /// Number of slices to store on the stack, when trying to send as many byte
lib/std/fs/test.zig+44-3
...@@ -2060,7 +2060,7 @@ test "invalid UTF-8/WTF-8 paths" {...@@ -2060,7 +2060,7 @@ test "invalid UTF-8/WTF-8 paths" {
2060}2060}
20612061
2062test "read file non vectored" {2062test "read file non vectored" {
2063 var tmp_dir = std.testing.tmpDir(.{});2063 var tmp_dir = testing.tmpDir(.{});
2064 defer tmp_dir.cleanup();2064 defer tmp_dir.cleanup();
20652065
2066 const contents = "hello, world!\n";2066 const contents = "hello, world!\n";
...@@ -2085,6 +2085,47 @@ test "read file non vectored" {...@@ -2085,6 +2085,47 @@ test "read file non vectored" {
2085 else => |e| return e,2085 else => |e| return e,
2086 };2086 };
2087 }2087 }
2088 try std.testing.expectEqualStrings(contents, w.buffered());2088 try testing.expectEqualStrings(contents, w.buffered());
2089 try std.testing.expectEqual(contents.len, i);2089 try testing.expectEqual(contents.len, i);
2090}
2091
2092test "seek keeping partial buffer" {
2093 var tmp_dir = testing.tmpDir(.{});
2094 defer tmp_dir.cleanup();
2095
2096 const contents = "0123456789";
2097
2098 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });
2099 defer file.close();
2100 {
2101 var file_writer: std.fs.File.Writer = .init(file, &.{});
2102 try file_writer.interface.writeAll(contents);
2103 try file_writer.interface.flush();
2104 }
2105
2106 var read_buffer: [3]u8 = undefined;
2107 var file_reader: std.fs.File.Reader = .init(file, &read_buffer);
2108
2109 try testing.expectEqual(0, file_reader.logicalPos());
2110
2111 var buf: [4]u8 = undefined;
2112 try file_reader.interface.readSliceAll(&buf);
2113
2114 if (file_reader.interface.bufferedLen() != 3) {
2115 // Pass the test if the OS doesn't give us vectored reads.
2116 return;
2117 }
2118
2119 try testing.expectEqual(4, file_reader.logicalPos());
2120 try testing.expectEqual(7, file_reader.pos);
2121 try file_reader.seekTo(6);
2122 try testing.expectEqual(6, file_reader.logicalPos());
2123 try testing.expectEqual(7, file_reader.pos);
2124
2125 try testing.expectEqualStrings("0123", &buf);
2126
2127 const n = try file_reader.interface.readSliceShort(&buf);
2128 try testing.expectEqual(4, n);
2129
2130 try testing.expectEqualStrings("6789", &buf);
2090}2131}