From 47693da4aa1a03d5871ddb6aa109db23836a72a6 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Sat, 6 May 2023 17:14:11 -0700 Subject: [PATCH 1/3] Make read_at and write_at more consistent between platforms --- core/os/file_windows.odin | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index a5f329d45..099a7e863 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -220,6 +220,7 @@ file_size :: proc(fd: Handle) -> (i64, Errno) { @(private) MAX_RW :: 1<<30 +ERROR_EOF :: 38 @(private) pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { @@ -228,11 +229,6 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { buf = buf[:MAX_RW] } - curr_offset, e := seek(fd, offset, 1) - if e != 0 { - return 0, e - } - defer seek(fd, curr_offset, 0) o := win32.OVERLAPPED{ OffsetHigh = u32(offset>>32), @@ -246,6 +242,11 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) { e = Errno(win32.GetLastError()) done = 0 + + // this makes behavior between *nix and windows consistent when EOF is hit + if e == ERROR_EOF { + e = 0 + } } return int(done), e } @@ -256,11 +257,6 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { buf = buf[:MAX_RW] } - curr_offset, e := seek(fd, offset, 1) - if e != 0 { - return 0, e - } - defer seek(fd, curr_offset, 0) o := win32.OVERLAPPED{ OffsetHigh = u32(offset>>32), @@ -276,6 +272,16 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { return int(done), e } +/* +read_at returns n: 0, err: 0 on EOF +on Windows, read_at changes the position of the file cursor, on *nix, it does not. + + bytes: [8]u8{} + read_at(fd, bytes, 0) + read(fd, bytes) + +will read from the location twice on *nix, and from two different locations on Windows +*/ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) { if offset < 0 { return 0, ERROR_NEGATIVE_OFFSET @@ -294,6 +300,16 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) { } return } + +/* +on Windows, write_at changes the position of the file cursor, on *nix, it does not. + + bytes: [8]u8{} + write_at(fd, bytes, 0) + write(fd, bytes) + +will write to the location twice on *nix, and to two different locations on Windows +*/ write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) { if offset < 0 { return 0, ERROR_NEGATIVE_OFFSET From 291111e6268eb169f8299ff6fd67b3d9b3806639 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Sat, 6 May 2023 17:23:44 -0700 Subject: [PATCH 2/3] oops. define e --- core/os/file_windows.odin | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index 099a7e863..9b1050cb0 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -239,6 +239,7 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { h := win32.HANDLE(fd) done: win32.DWORD + e: Errno if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) { e = Errno(win32.GetLastError()) done = 0 @@ -265,6 +266,7 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { h := win32.HANDLE(fd) done: win32.DWORD + e: Errno if !win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o) { e = Errno(win32.GetLastError()) done = 0 From b0eda47b26d41e767a26523cc316a990e6067679 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Sat, 6 May 2023 17:52:08 -0700 Subject: [PATCH 3/3] prevent infinite-loop on EOF --- core/os/file_windows.odin | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index 9b1050cb0..9d62014af 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -243,11 +243,6 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) { e = Errno(win32.GetLastError()) done = 0 - - // this makes behavior between *nix and windows consistent when EOF is hit - if e == ERROR_EOF { - e = 0 - } } return int(done), e } @@ -292,6 +287,10 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) { b, offset := data, offset for len(b) > 0 { m, e := pread(fd, b, offset) + if e == ERROR_EOF { + err = 0 + break + } if e != 0 { err = e break