Skip to content

Commit d967f94

Browse files
committed
std.fs.File: fix streaming seekBy ignoring buffer
streaming seekBy completely ignored the buffer. the new logic checks if the seek offset is smaller than the buffer and adds the offset to r.interface.seek. otherwise the old logic is invoked.
1 parent 5ab3b5c commit d967f94

File tree

2 files changed

+49
-13
lines changed

2 files changed

+49
-13
lines changed

lib/std/fs/File.zig

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,22 +1198,28 @@ pub const Reader = struct {
11981198
}
11991199
const seek_err = r.seek_err orelse e: {
12001200
if (posix.lseek_CUR(r.file.handle, offset)) |_| {
1201-
setPosAdjustingBuffer(r, @intCast(@as(i64, @intCast(r.pos)) + offset));
1201+
setPosAdjustingBuffer(r, @intCast(@as(i64, @intCast(r.logicalPos())) + offset));
12021202
return;
12031203
} else |err| {
12041204
r.seek_err = err;
12051205
break :e err;
12061206
}
12071207
};
12081208
var remaining = std.math.cast(u64, offset) orelse return seek_err;
1209-
while (remaining > 0) {
1210-
remaining -= discard(&r.interface, .limited64(remaining)) catch |err| {
1211-
r.seek_err = err;
1212-
return err;
1213-
};
1209+
const bufferedLen = r.interface.bufferedLen();
1210+
if (remaining < bufferedLen) {
1211+
r.interface.seek += remaining;
1212+
} else {
1213+
remaining -= bufferedLen;
1214+
while (remaining > 0) {
1215+
remaining -= discard(&r.interface, .limited64(remaining)) catch |err| {
1216+
r.seek_err = err;
1217+
return err;
1218+
};
1219+
}
1220+
r.interface.seek = 0;
1221+
r.interface.end = 0;
12141222
}
1215-
r.interface.seek = 0;
1216-
r.interface.end = 0;
12171223
},
12181224
.failure => return r.seek_err.?,
12191225
}

lib/std/fs/test.zig

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2140,20 +2140,50 @@ test "seek keeping partial buffer" {
21402140
try testing.expectEqualStrings("6789", &buf);
21412141
}
21422142

2143+
test "seekBy streaming edge case" {
2144+
var tmp_dir = testing.tmpDir(.{});
2145+
defer tmp_dir.cleanup();
2146+
2147+
try tmp_dir.dir.writeFile(.{ .sub_path = "blah.txt", .data = "let's test seekBy" });
2148+
const f = try tmp_dir.dir.openFile("blah.txt", .{ .mode = .read_only });
2149+
defer f.close();
2150+
var read_buf: [10]u8 = undefined;
2151+
var reader = f.readerStreaming(&read_buf);
2152+
var buffer: [20]u8 = undefined;
2153+
const n1 = try reader.interface.readSliceShort(buffer[0..2]);
2154+
try testing.expectEqual(2, n1);
2155+
try testing.expectEqualStrings("le", buffer[0..2]);
2156+
// edge case seek: exactly up to buffer size
2157+
try reader.seekBy(10);
2158+
2159+
const n2 = try reader.interface.readSliceShort(&buffer);
2160+
try testing.expectEqual(5, n2);
2161+
try testing.expectEqualStrings("eekBy", buffer[0..5]);
2162+
}
2163+
21432164
test "seekBy streaming" {
21442165
var tmp_dir = testing.tmpDir(.{});
21452166
defer tmp_dir.cleanup();
21462167

21472168
try tmp_dir.dir.writeFile(.{ .sub_path = "blah.txt", .data = "let's test seekBy" });
21482169
const f = try tmp_dir.dir.openFile("blah.txt", .{ .mode = .read_only });
21492170
defer f.close();
2150-
var reader = f.readerStreaming(&.{});
2171+
var read_buf: [10]u8 = undefined;
2172+
var reader = f.readerStreaming(&read_buf);
2173+
var buffer: [20]u8 = undefined;
2174+
const n1 = try reader.interface.readSliceShort(buffer[0..2]);
2175+
try testing.expectEqual(2, n1);
2176+
try testing.expectEqualStrings("le", buffer[0..2]);
2177+
// seek within bufferedLen
21512178
try reader.seekBy(2);
2179+
try reader.interface.readSliceAll(buffer[0..2]);
2180+
try testing.expectEqualStrings("s ", buffer[0..2]);
2181+
// seek past bufferedLen: causing discard
2182+
try reader.seekBy(12);
21522183

2153-
var buffer: [20]u8 = undefined;
2154-
const n = try reader.interface.readSliceShort(&buffer);
2155-
try testing.expectEqual(15, n);
2156-
try testing.expectEqualStrings("t's test seekBy", buffer[0..15]);
2184+
const n2 = try reader.interface.readSliceShort(&buffer);
2185+
try testing.expectEqual(1, n2);
2186+
try testing.expectEqualStrings("y", buffer[0..1]);
21572187
}
21582188

21592189
test "seekBy positional" {

0 commit comments

Comments
 (0)