aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen van Rijn <Kelimion@users.noreply.github.com>2023-11-18 18:01:14 +0100
committerJeroen van Rijn <Kelimion@users.noreply.github.com>2023-11-18 18:01:14 +0100
commit0c97f6aa4e2c544bcaab8724f8e798e5998a31e5 (patch)
tree0f4de1deeeb2a6402d81f4ebbf144abec2173a9d
parentaf78ad2a8758c4a0b59bc86586b0f3c5bbd6e218 (diff)
Fix unhandled EOF in streaming io on Windows
-rw-r--r--core/os/file_windows.odin32
-rw-r--r--core/os/stream.odin9
2 files changed, 21 insertions, 20 deletions
diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin
index 9d62014af..0b0baeea3 100644
--- a/core/os/file_windows.odin
+++ b/core/os/file_windows.odin
@@ -149,7 +149,7 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) {
return
}
-read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
+read :: proc(fd: Handle, data: []byte) -> (total_read: int, err: Errno) {
if len(data) == 0 {
return 0, ERROR_NONE
}
@@ -158,32 +158,32 @@ read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
m: u32
is_console := win32.GetConsoleMode(handle, &m)
-
- single_read_length: win32.DWORD
- total_read: int
length := len(data)
// NOTE(Jeroen): `length` can't be casted to win32.DWORD here because it'll overflow if > 4 GiB and return 0 if exactly that.
to_read := min(i64(length), MAX_RW)
- e: win32.BOOL
if is_console {
- n, err := read_console(handle, data[total_read:][:to_read])
- total_read += n
+ total_read, err = read_console(handle, data[total_read:][:to_read])
if err != 0 {
- return int(total_read), err
+ return total_read, err
}
} else {
// NOTE(Jeroen): So we cast it here *after* we've ensured that `to_read` is at most MAX_RW (1 GiB)
- e = win32.ReadFile(handle, &data[total_read], win32.DWORD(to_read), &single_read_length, nil)
- }
- if single_read_length <= 0 || !e {
- err := Errno(win32.GetLastError())
- return int(total_read), err
+ bytes_read: win32.DWORD
+ if e := win32.ReadFile(handle, &data[total_read], win32.DWORD(to_read), &bytes_read, nil); e {
+ // Successful read can mean two things, including EOF, see:
+ // https://learn.microsoft.com/en-us/windows/win32/fileio/testing-for-the-end-of-a-file
+ if bytes_read == 0 {
+ return 0, ERROR_HANDLE_EOF
+ } else {
+ return int(bytes_read), ERROR_NONE
+ }
+ } else {
+ return 0, Errno(win32.GetLastError())
+ }
}
- total_read += int(single_read_length)
-
- return int(total_read), ERROR_NONE
+ return total_read, ERROR_NONE
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
diff --git a/core/os/stream.odin b/core/os/stream.odin
index 2b4c83663..a09c62e2b 100644
--- a/core/os/stream.odin
+++ b/core/os/stream.odin
@@ -27,9 +27,7 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
case .Read:
n_int, os_err = read(fd, p)
n = i64(n_int)
- if os_err != 0 {
- err = .Unknown
- }
+
case .Read_At:
when !(ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD) {
n_int, os_err = read_at(fd, p, offset)
@@ -57,7 +55,10 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
}
}
if err == nil && os_err != 0 {
- err = .Unknown
+ switch os_err {
+ case ERROR_HANDLE_EOF: err = .EOF
+ case: err = .Unknown
+ }
}
return
}