mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
std: fix File.Writer sendfile with buffered contents
* File.Writer.seekBy passed wrong offset to setPosAdjustingBuffer.
* File.Writer.sendFile incorrectly used non-logical position.
Related to 1d764c1fdf
Test case provided by:
Co-authored-by: Kendall Condon <goon.pri.low@gmail.com>
This commit is contained in:
parent
acd6ffdf69
commit
5c0ac90721
2 changed files with 40 additions and 9 deletions
|
|
@ -1242,7 +1242,7 @@ pub const Reader = struct {
|
|||
pub fn seekBy(r: *Reader, offset: i64) Reader.SeekError!void {
|
||||
switch (r.mode) {
|
||||
.positional, .positional_reading => {
|
||||
setPosAdjustingBuffer(r, @intCast(@as(i64, @intCast(r.pos)) + offset));
|
||||
setLogicalPos(r, @intCast(@as(i64, @intCast(logicalPos(r))) + offset));
|
||||
},
|
||||
.streaming, .streaming_reading => {
|
||||
if (posix.SEEK == void) {
|
||||
|
|
@ -1251,7 +1251,7 @@ pub const Reader = struct {
|
|||
}
|
||||
const seek_err = r.seek_err orelse e: {
|
||||
if (posix.lseek_CUR(r.file.handle, offset)) |_| {
|
||||
setPosAdjustingBuffer(r, @intCast(@as(i64, @intCast(r.pos)) + offset));
|
||||
setLogicalPos(r, @intCast(@as(i64, @intCast(logicalPos(r))) + offset));
|
||||
return;
|
||||
} else |err| {
|
||||
r.seek_err = err;
|
||||
|
|
@ -1275,16 +1275,16 @@ pub const Reader = struct {
|
|||
pub fn seekTo(r: *Reader, offset: u64) Reader.SeekError!void {
|
||||
switch (r.mode) {
|
||||
.positional, .positional_reading => {
|
||||
setPosAdjustingBuffer(r, offset);
|
||||
setLogicalPos(r, offset);
|
||||
},
|
||||
.streaming, .streaming_reading => {
|
||||
if (offset >= r.pos) return Reader.seekBy(r, @intCast(offset - r.pos));
|
||||
if (offset >= r.pos) return Reader.seekBy(r, @intCast(offset - logicalPos(r)));
|
||||
if (r.seek_err) |err| return err;
|
||||
posix.lseek_SET(r.file.handle, offset) catch |err| {
|
||||
r.seek_err = err;
|
||||
return err;
|
||||
};
|
||||
setPosAdjustingBuffer(r, offset);
|
||||
setLogicalPos(r, offset);
|
||||
},
|
||||
.failure => return r.seek_err.?,
|
||||
}
|
||||
|
|
@ -1294,7 +1294,7 @@ pub const Reader = struct {
|
|||
return r.pos - r.interface.bufferedLen();
|
||||
}
|
||||
|
||||
fn setPosAdjustingBuffer(r: *Reader, offset: u64) void {
|
||||
fn setLogicalPos(r: *Reader, offset: u64) void {
|
||||
const logical_pos = logicalPos(r);
|
||||
if (offset < logical_pos or offset >= r.pos) {
|
||||
r.interface.seek = 0;
|
||||
|
|
@ -1855,7 +1855,7 @@ pub const Writer = struct {
|
|||
return error.EndOfStream;
|
||||
}
|
||||
const consumed = io_w.consume(@intCast(sbytes));
|
||||
file_reader.seekTo(file_reader.pos + consumed) catch return error.ReadFailed;
|
||||
file_reader.seekBy(@intCast(consumed)) catch return error.ReadFailed;
|
||||
return consumed;
|
||||
}
|
||||
|
||||
|
|
@ -1916,7 +1916,7 @@ pub const Writer = struct {
|
|||
return error.EndOfStream;
|
||||
}
|
||||
const consumed = io_w.consume(@bitCast(len));
|
||||
file_reader.seekTo(file_reader.pos + consumed) catch return error.ReadFailed;
|
||||
file_reader.seekBy(@intCast(consumed)) catch return error.ReadFailed;
|
||||
return consumed;
|
||||
}
|
||||
|
||||
|
|
@ -2049,7 +2049,7 @@ pub const Writer = struct {
|
|||
reader_buffered: []const u8,
|
||||
) std.Io.Writer.FileError!usize {
|
||||
const n = try drain(io_w, &.{reader_buffered}, 1);
|
||||
file_reader.seekTo(file_reader.pos + n) catch return error.ReadFailed;
|
||||
file_reader.seekBy(@intCast(n)) catch return error.ReadFailed;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2145,3 +2145,34 @@ test "seekBy" {
|
|||
try testing.expectEqual(15, n);
|
||||
try testing.expectEqualStrings("t's test seekBy", buffer[0..15]);
|
||||
}
|
||||
|
||||
test "File.Writer sendfile with buffered contents" {
|
||||
var tmp_dir = testing.tmpDir(.{});
|
||||
defer tmp_dir.cleanup();
|
||||
|
||||
{
|
||||
try tmp_dir.dir.writeFile(.{ .sub_path = "a", .data = "bcd" });
|
||||
const in = try tmp_dir.dir.openFile("a", .{});
|
||||
defer in.close();
|
||||
const out = try tmp_dir.dir.createFile("b", .{});
|
||||
defer out.close();
|
||||
|
||||
var in_buf: [2]u8 = undefined;
|
||||
var in_r = in.reader(&in_buf);
|
||||
_ = try in_r.getSize(); // Catch seeks past end by populating size
|
||||
try in_r.interface.fill(2);
|
||||
|
||||
var out_buf: [1]u8 = undefined;
|
||||
var out_w = out.writerStreaming(&out_buf);
|
||||
try out_w.interface.writeByte('a');
|
||||
try testing.expectEqual(3, try out_w.interface.sendFileAll(&in_r, .unlimited));
|
||||
try out_w.interface.flush();
|
||||
}
|
||||
|
||||
var check = try tmp_dir.dir.openFile("b", .{});
|
||||
defer check.close();
|
||||
var check_buf: [4]u8 = undefined;
|
||||
var check_r = check.reader(&check_buf);
|
||||
try testing.expectEqualStrings("abcd", try check_r.interface.take(4));
|
||||
try testing.expectError(error.EndOfStream, check_r.interface.takeByte());
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue