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

This commit is contained in:
Andrew Kelley 2025-07-21 18:13:45 -07:00
parent fe10c66d66
commit b35c55e237
2 changed files with 54 additions and 7 deletions

View File

@ -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

View File

@ -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);
}