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 {
11351135 err: ?ReadError = null,
11361136 mode: Reader.Mode = .positional,
11371137 /// 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`.
11391139 pos: u64 = 0,
11401140 size: ?u64 = null,
11411141 size_err: ?GetEndPosError = null,
......@@ -1274,14 +1274,20 @@ pub const Reader = struct {
12741274 }
12751275 }
12761276
1277 pub fn logicalPos(r: *const Reader) u64 {
1278 return r.pos - r.interface.bufferedLen();
1279 }
1280
12771281 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) {
12791284 r.interface.seek = 0;
12801285 r.interface.end = 0;
1286 r.pos = offset;
12811287 } else {
1282 r.interface.seek += @intCast(offset - r.pos);
1288 const logical_delta: usize = @intCast(offset - logical_pos);
1289 r.interface.seek += logical_delta;
12831290 }
1284 r.pos = offset;
12851291 }
12861292
12871293 /// 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" {
20602060}
20612061
20622062test "read file non vectored" {
2063 var tmp_dir = std.testing.tmpDir(.{});
2063 var tmp_dir = testing.tmpDir(.{});
20642064 defer tmp_dir.cleanup();
20652065
20662066 const contents = "hello, world!\n";
......@@ -2085,6 +2085,47 @@ test "read file non vectored" {
20852085 else => |e| return e,
20862086 };
20872087 }
2088 try std.testing.expectEqualStrings(contents, w.buffered());
2089 try std.testing.expectEqual(contents.len, i);
2088 try testing.expectEqualStrings(contents, w.buffered());
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);
20902131}