diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2025-07-21 18:13:45 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2025-07-21 18:14:21 -0700 |
| commit | b35c55e2373ace674cd1eec7f5086b805d1c8256 (patch) | |
| tree | b884a2c4c2e4133b4f40dc9499f66b430df60b1b /lib/std/fs | |
| parent | fe10c66d664ae7b1acb2bcf01600eeacc2958fc7 (diff) | |
| download | zig-b35c55e2373ace674cd1eec7f5086b805d1c8256.tar.gz zig-b35c55e2373ace674cd1eec7f5086b805d1c8256.zip | |
std.fs.File.Reader: fix seek position logic
Diffstat (limited to 'lib/std/fs')
| -rw-r--r-- | lib/std/fs/File.zig | 14 | ||||
| -rw-r--r-- | lib/std/fs/test.zig | 47 |
2 files changed, 54 insertions, 7 deletions
diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig index 04b2f1dd94..a95bd1401a 100644 --- a/lib/std/fs/File.zig +++ b/lib/std/fs/File.zig @@ -1135,7 +1135,7 @@ pub const Reader = struct { err: ?ReadError = null, mode: Reader.Mode = .positional, /// Tracks the true seek position in the file. To obtain the logical - /// position, subtract the buffer size from this value. + /// position, use `logicalPos`. pos: u64 = 0, size: ?u64 = null, size_err: ?GetEndPosError = null, @@ -1274,14 +1274,20 @@ pub const Reader = struct { } } + pub fn logicalPos(r: *const Reader) u64 { + return r.pos - r.interface.bufferedLen(); + } + fn setPosAdjustingBuffer(r: *Reader, offset: u64) void { - if (offset < r.pos or offset >= r.pos + r.interface.bufferedLen()) { + const logical_pos = logicalPos(r); + if (offset < logical_pos or offset >= r.pos) { r.interface.seek = 0; r.interface.end = 0; + r.pos = offset; } else { - r.interface.seek += @intCast(offset - r.pos); + const logical_delta: usize = @intCast(offset - logical_pos); + r.interface.seek += logical_delta; } - r.pos = offset; } /// Number of slices to store on the stack, when trying to send as many byte diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 9fe2551738..4b63873af5 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -2060,7 +2060,7 @@ test "invalid UTF-8/WTF-8 paths" { } test "read file non vectored" { - var tmp_dir = std.testing.tmpDir(.{}); + var tmp_dir = testing.tmpDir(.{}); defer tmp_dir.cleanup(); const contents = "hello, world!\n"; @@ -2085,6 +2085,47 @@ test "read file non vectored" { else => |e| return e, }; } - try std.testing.expectEqualStrings(contents, w.buffered()); - try std.testing.expectEqual(contents.len, i); + try testing.expectEqualStrings(contents, w.buffered()); + try testing.expectEqual(contents.len, i); +} + +test "seek keeping partial buffer" { + var tmp_dir = testing.tmpDir(.{}); + defer tmp_dir.cleanup(); + + const contents = "0123456789"; + + const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true }); + defer file.close(); + { + var file_writer: std.fs.File.Writer = .init(file, &.{}); + try file_writer.interface.writeAll(contents); + try file_writer.interface.flush(); + } + + var read_buffer: [3]u8 = undefined; + var file_reader: std.fs.File.Reader = .init(file, &read_buffer); + + try testing.expectEqual(0, file_reader.logicalPos()); + + var buf: [4]u8 = undefined; + try file_reader.interface.readSliceAll(&buf); + + if (file_reader.interface.bufferedLen() != 3) { + // Pass the test if the OS doesn't give us vectored reads. + return; + } + + try testing.expectEqual(4, file_reader.logicalPos()); + try testing.expectEqual(7, file_reader.pos); + try file_reader.seekTo(6); + try testing.expectEqual(6, file_reader.logicalPos()); + try testing.expectEqual(7, file_reader.pos); + + try testing.expectEqualStrings("0123", &buf); + + const n = try file_reader.interface.readSliceShort(&buf); + try testing.expectEqual(4, n); + + try testing.expectEqualStrings("6789", &buf); } |
