Commit c065e12dbe

LemonBoy <thatlemon@gmail.com>
2021-05-07 15:24:37
std: Add more tests, fix broken code
It turns out that nothing in the test suite was exercising preadv/pwritev and so the previous commits silently broke them. Adding tests revealed readvAll and preadvAll were also broken and not covered by any test.
1 parent 31f1cc9
Changed files (3)
lib/std/fs/file.zig
@@ -482,7 +482,7 @@ pub const File = struct {
     /// order to handle partial reads from the underlying OS layer.
     /// See https://github.com/ziglang/zig/issues/7699
     pub fn readvAll(self: File, iovecs: []os.iovec) ReadError!usize {
-        if (iovecs.len == 0) return;
+        if (iovecs.len == 0) return 0;
 
         var i: usize = 0;
         var off: usize = 0;
@@ -524,8 +524,8 @@ pub const File = struct {
     /// The `iovecs` parameter is mutable because this function needs to mutate the fields in
     /// order to handle partial reads from the underlying OS layer.
     /// See https://github.com/ziglang/zig/issues/7699
-    pub fn preadvAll(self: File, iovecs: []const os.iovec, offset: u64) PReadError!void {
-        if (iovecs.len == 0) return;
+    pub fn preadvAll(self: File, iovecs: []os.iovec, offset: u64) PReadError!usize {
+        if (iovecs.len == 0) return 0;
 
         var i: usize = 0;
         var off: usize = 0;
lib/std/fs/test.zig
@@ -520,6 +520,89 @@ test "makePath, put some files in it, deleteTree" {
     }
 }
 
+test "writev, readv" {
+    var tmp = tmpDir(.{});
+    defer tmp.cleanup();
+
+    const line1 = "line1\n";
+    const line2 = "line2\n";
+
+    var buf1: [line1.len]u8 = undefined;
+    var buf2: [line2.len]u8 = undefined;
+    var write_vecs = [_]std.os.iovec_const{
+        .{
+            .iov_base = line1,
+            .iov_len = line1.len,
+        },
+        .{
+            .iov_base = line2,
+            .iov_len = line2.len,
+        },
+    };
+    var read_vecs = [_]std.os.iovec{
+        .{
+            .iov_base = &buf2,
+            .iov_len = buf2.len,
+        },
+        .{
+            .iov_base = &buf1,
+            .iov_len = buf1.len,
+        },
+    };
+
+    var src_file = try tmp.dir.createFile("test.txt", .{ .read = true });
+    defer src_file.close();
+
+    try src_file.writevAll(&write_vecs);
+    try testing.expectEqual(@as(u64, line1.len + line2.len), try src_file.getEndPos());
+    try src_file.seekTo(0);
+    const read = try src_file.readvAll(&read_vecs);
+    try testing.expectEqual(@as(usize, line1.len + line2.len), read);
+    try testing.expectEqualStrings(&buf1, "line2\n");
+    try testing.expectEqualStrings(&buf2, "line1\n");
+}
+
+test "pwritev, preadv" {
+    var tmp = tmpDir(.{});
+    defer tmp.cleanup();
+
+    const line1 = "line1\n";
+    const line2 = "line2\n";
+
+    var buf1: [line1.len]u8 = undefined;
+    var buf2: [line2.len]u8 = undefined;
+    var write_vecs = [_]std.os.iovec_const{
+        .{
+            .iov_base = line1,
+            .iov_len = line1.len,
+        },
+        .{
+            .iov_base = line2,
+            .iov_len = line2.len,
+        },
+    };
+    var read_vecs = [_]std.os.iovec{
+        .{
+            .iov_base = &buf2,
+            .iov_len = buf2.len,
+        },
+        .{
+            .iov_base = &buf1,
+            .iov_len = buf1.len,
+        },
+    };
+
+    var src_file = try tmp.dir.createFile("test.txt", .{ .read = true });
+    defer src_file.close();
+
+    try src_file.pwritevAll(&write_vecs, 16);
+    try testing.expectEqual(@as(u64, 16 + line1.len + line2.len), try src_file.getEndPos());
+    const read = try src_file.preadvAll(&read_vecs, 16);
+    try testing.expectEqual(@as(usize, line1.len + line2.len), read);
+    try testing.expectEqualStrings(&buf1, "line2\n");
+    try testing.expectEqualStrings(&buf2, "line1\n");
+}
+
 test "access file" {
     if (builtin.os.tag == .wasi) return error.SkipZigTest;
 
lib/std/os.zig
@@ -646,8 +646,9 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
     else
         system.preadv;
 
+    const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
     while (true) {
-        const rc = preadv_sym(fd, iov.ptr, iov_count, offset);
+        const rc = preadv_sym(fd, iov.ptr, iov_count, ioffset);
         switch (errno(rc)) {
             0 => return @bitCast(usize, rc),
             EINTR => continue,
@@ -998,8 +999,9 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
         system.pwritev;
 
     const iov_count = math.cast(u31, iov.len) catch math.maxInt(u31);
+    const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
     while (true) {
-        const rc = pwritev_sym(fd, iov.ptr, iov_count, offset);
+        const rc = pwritev_sym(fd, iov.ptr, iov_count, ioffset);
         switch (errno(rc)) {
             0 => return @intCast(usize, rc),
             EINTR => continue,