authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-12 00:59:10+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-12 00:59:10+01:00
log545982c0298812869712a58b9f16772f9b09abcd
tree21a0d65aad839acf6e891cccea4a1565813bb1ef
parent514f6e589ca441c3ac115b8c764bdc9f6d4aca01
parent4cf7dc22fa6796d231397ee38a54536d4e94f5bc

Merge pull request 'A few Windows fixes' (#30757) from squeek502/zig:windows-misc-fixes into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/30757 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

3 files changed, 28 insertions(+), 14 deletions(-)

lib/std/Io/Threaded.zig+6
......@@ -7987,6 +7987,9 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: File, data: []const []u
79877987 .LOCK_VIOLATION => return syscall.fail(error.LockViolation),
79887988 .ACCESS_DENIED => return syscall.fail(error.AccessDenied),
79897989 .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),
79907993 else => |err| {
79917994 syscall.finish();
79927995 return windows.unexpectedError(err);
......@@ -8144,6 +8147,9 @@ fn fileReadPositionalWindows(userdata: ?*anyopaque, file: File, data: []const []
81448147 .LOCK_VIOLATION => return syscall.fail(error.LockViolation),
81458148 .ACCESS_DENIED => return syscall.fail(error.AccessDenied),
81468149 .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),
81478153 else => |err| {
81488154 syscall.finish();
81498155 return windows.unexpectedError(err);
lib/std/fs/test.zig+17-13
......@@ -182,20 +182,21 @@ fn testWithPathTypeIfSupported(comptime path_type: PathType, comptime path_sep:
182182}
183183
184184// For use in test setup. If the symlink creation fails on Windows with
185// AccessDenied, then make the test failure silent (it is not a Zig failure).
185// AccessDenied/PermissionDenied/FileSystem, then make the test failure silent (it is not a Zig failure).
186186fn setupSymlink(io: Io, dir: Dir, target: []const u8, link: []const u8, flags: SymLinkFlags) !void {
187187 return dir.symLink(io, target, link, flags) catch |err| switch (err) {
188 // Symlink requires admin privileges on windows, so this test can legitimately fail.
189 error.AccessDenied => if (native_os == .windows) return error.SkipZigTest else return err,
188 // On Windows, symlinks require admin privileges and the underlying filesystem must support symlinks
189 error.AccessDenied, error.PermissionDenied, error.FileSystem => if (native_os == .windows) return error.SkipZigTest else return err,
190190 else => return err,
191191 };
192192}
193193
194194// For use in test setup. If the symlink creation fails on Windows with
195// AccessDenied, then make the test failure silent (it is not a Zig failure).
195// AccessDeniedPermissionDenied/FileSystem, then make the test failure silent (it is not a Zig failure).
196196fn setupSymlinkAbsolute(io: Io, target: []const u8, link: []const u8, flags: SymLinkFlags) !void {
197197 return Dir.symLinkAbsolute(io, target, link, flags) catch |err| switch (err) {
198 error.AccessDenied => if (native_os == .windows) return error.SkipZigTest else return err,
198 // On Windows, symlinks require admin privileges and the underlying filesystem must support symlinks
199 error.AccessDenied, error.PermissionDenied, error.FileSystem => if (native_os == .windows) return error.SkipZigTest else return err,
199200 else => return err,
200201 };
201202}
......@@ -847,7 +848,16 @@ test "file operations on directories" {
847848
848849 {
849850 const handle = try ctx.dir.openFile(io, test_dir_name, .{ .allow_directory = true, .mode = .read_only });
850 handle.close(io);
851 defer handle.close(io);
852
853 // Reading from the handle should fail
854 const expected_err = switch (native_os) {
855 .wasi => error.NotOpenForReading,
856 else => error.IsDir,
857 };
858 var buf: [1]u8 = undefined;
859 try expectError(expected_err, handle.readStreaming(io, &.{&buf}));
860 try expectError(expected_err, handle.readPositional(io, &.{&buf}, 0));
851861 }
852862 try expectError(error.IsDir, ctx.dir.openFile(io, test_dir_name, .{ .allow_directory = false, .mode = .read_only }));
853863
......@@ -2364,13 +2374,7 @@ test "readlinkat" {
23642374 try tmp.dir.writeFile(io, .{ .sub_path = "file.txt", .data = "nonsense" });
23652375
23662376 // create a symbolic link
2367 tmp.dir.symLink(io, "file.txt", "link", .{}) catch |err| switch (err) {
2368 error.AccessDenied => {
2369 // Symlink requires admin privileges on windows, so this test can legitimately fail.
2370 if (native_os == .windows) return error.SkipZigTest;
2371 },
2372 else => |e| return e,
2373 };
2377 try setupSymlink(io, tmp.dir, "file.txt", "link", .{});
23742378
23752379 // read the link
23762380 var buffer: [Dir.max_path_bytes]u8 = undefined;
lib/std/os/windows.zig+5-1
......@@ -267,7 +267,11 @@ pub const FILE = struct {
267267
268268 pub fn toBuffer(fri: *const RENAME_INFORMATION) []const u8 {
269269 const start: [*]const u8 = @ptrCast(fri);
270 return start[0 .. @offsetOf(RENAME_INFORMATION, "FileName") + fri.FileNameLength];
270 // The ABI size of the documented struct is 24 bytes, and attempting to use any size
271 // less than that will trigger INFO_LENGTH_MISMATCH, so enforce a minimum in cases where,
272 // for example, FileNameLength is 1 so only 22 bytes are technically needed.
273 const size = @max(24, @offsetOf(RENAME_INFORMATION, "FileName") + fri.FileNameLength);
274 return start[0..size];
271275 }
272276 };
273277