authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2026-01-08 16:51:20-08:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2026-01-11 02:08:18-08:00
logb4831403c929d429c7710d5004ec32fd0dfbd0a4
tree565fdd5440bacc37db9467df4fa1981cafabd0f5
parentd08098861f47fb0974066fce8cc3af7d5709d12f

fileRead functions: handle INVALID_FUNCTION on Windows and map it to error.IsDir

INVALID_FUNCTION may be possible in other scenarios as well, but it is verifiably returned when the handle refers to a directory.

2 files changed, 16 insertions(+), 1 deletions(-)

lib/std/Io/Threaded.zig+6
...@@ -7987,6 +7987,9 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: File, data: []const []u...@@ -7987,6 +7987,9 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: File, data: []const []u
7987 .LOCK_VIOLATION => return syscall.fail(error.LockViolation),7987 .LOCK_VIOLATION => return syscall.fail(error.LockViolation),
7988 .ACCESS_DENIED => return syscall.fail(error.AccessDenied),7988 .ACCESS_DENIED => return syscall.fail(error.AccessDenied),
7989 .INVALID_HANDLE => return syscall.fail(error.NotOpenForReading),7989 .INVALID_HANDLE => return syscall.fail(error.NotOpenForReading),
7990 // TODO: Determine if INVALID_FUNCTION is possible in more scenarios than just passing
7991 // a handle to a directory.
7992 .INVALID_FUNCTION => return syscall.fail(error.IsDir),
7990 else => |err| {7993 else => |err| {
7991 syscall.finish();7994 syscall.finish();
7992 return windows.unexpectedError(err);7995 return windows.unexpectedError(err);
...@@ -8144,6 +8147,9 @@ fn fileReadPositionalWindows(userdata: ?*anyopaque, file: File, data: []const []...@@ -8144,6 +8147,9 @@ fn fileReadPositionalWindows(userdata: ?*anyopaque, file: File, data: []const []
8144 .LOCK_VIOLATION => return syscall.fail(error.LockViolation),8147 .LOCK_VIOLATION => return syscall.fail(error.LockViolation),
8145 .ACCESS_DENIED => return syscall.fail(error.AccessDenied),8148 .ACCESS_DENIED => return syscall.fail(error.AccessDenied),
8146 .INVALID_HANDLE => return syscall.fail(error.NotOpenForReading),8149 .INVALID_HANDLE => return syscall.fail(error.NotOpenForReading),
8150 // TODO: Determine if INVALID_FUNCTION is possible in more scenarios than just passing
8151 // a handle to a directory.
8152 .INVALID_FUNCTION => return syscall.fail(error.IsDir),
8147 else => |err| {8153 else => |err| {
8148 syscall.finish();8154 syscall.finish();
8149 return windows.unexpectedError(err);8155 return windows.unexpectedError(err);
lib/std/fs/test.zig+10-1
...@@ -847,7 +847,16 @@ test "file operations on directories" {...@@ -847,7 +847,16 @@ test "file operations on directories" {
847847
848 {848 {
849 const handle = try ctx.dir.openFile(io, test_dir_name, .{ .allow_directory = true, .mode = .read_only });849 const handle = try ctx.dir.openFile(io, test_dir_name, .{ .allow_directory = true, .mode = .read_only });
850 handle.close(io);850 defer handle.close(io);
851
852 // Reading from the handle should fail
853 const expected_err = switch (native_os) {
854 .wasi => error.NotOpenForReading,
855 else => error.IsDir,
856 };
857 var buf: [1]u8 = undefined;
858 try expectError(expected_err, handle.readStreaming(io, &.{&buf}));
859 try expectError(expected_err, handle.readPositional(io, &.{&buf}, 0));
851 }860 }
852 try expectError(error.IsDir, ctx.dir.openFile(io, test_dir_name, .{ .allow_directory = false, .mode = .read_only }));861 try expectError(error.IsDir, ctx.dir.openFile(io, test_dir_name, .{ .allow_directory = false, .mode = .read_only }));
853862