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>
This commit is contained in:
Andrew Kelley 2026-01-12 00:59:10 +01:00
commit 545982c029
3 changed files with 28 additions and 14 deletions

View file

@ -7987,6 +7987,9 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: File, data: []const []u
.LOCK_VIOLATION => return syscall.fail(error.LockViolation),
.ACCESS_DENIED => return syscall.fail(error.AccessDenied),
.INVALID_HANDLE => return syscall.fail(error.NotOpenForReading),
// TODO: Determine if INVALID_FUNCTION is possible in more scenarios than just passing
// a handle to a directory.
.INVALID_FUNCTION => return syscall.fail(error.IsDir),
else => |err| {
syscall.finish();
return windows.unexpectedError(err);
@ -8144,6 +8147,9 @@ fn fileReadPositionalWindows(userdata: ?*anyopaque, file: File, data: []const []
.LOCK_VIOLATION => return syscall.fail(error.LockViolation),
.ACCESS_DENIED => return syscall.fail(error.AccessDenied),
.INVALID_HANDLE => return syscall.fail(error.NotOpenForReading),
// TODO: Determine if INVALID_FUNCTION is possible in more scenarios than just passing
// a handle to a directory.
.INVALID_FUNCTION => return syscall.fail(error.IsDir),
else => |err| {
syscall.finish();
return windows.unexpectedError(err);

View file

@ -182,20 +182,21 @@ fn testWithPathTypeIfSupported(comptime path_type: PathType, comptime path_sep:
}
// For use in test setup. If the symlink creation fails on Windows with
// AccessDenied, then make the test failure silent (it is not a Zig failure).
// AccessDenied/PermissionDenied/FileSystem, then make the test failure silent (it is not a Zig failure).
fn setupSymlink(io: Io, dir: Dir, target: []const u8, link: []const u8, flags: SymLinkFlags) !void {
return dir.symLink(io, target, link, flags) catch |err| switch (err) {
// Symlink requires admin privileges on windows, so this test can legitimately fail.
error.AccessDenied => if (native_os == .windows) return error.SkipZigTest else return err,
// On Windows, symlinks require admin privileges and the underlying filesystem must support symlinks
error.AccessDenied, error.PermissionDenied, error.FileSystem => if (native_os == .windows) return error.SkipZigTest else return err,
else => return err,
};
}
// For use in test setup. If the symlink creation fails on Windows with
// AccessDenied, then make the test failure silent (it is not a Zig failure).
// AccessDeniedPermissionDenied/FileSystem, then make the test failure silent (it is not a Zig failure).
fn setupSymlinkAbsolute(io: Io, target: []const u8, link: []const u8, flags: SymLinkFlags) !void {
return Dir.symLinkAbsolute(io, target, link, flags) catch |err| switch (err) {
error.AccessDenied => if (native_os == .windows) return error.SkipZigTest else return err,
// On Windows, symlinks require admin privileges and the underlying filesystem must support symlinks
error.AccessDenied, error.PermissionDenied, error.FileSystem => if (native_os == .windows) return error.SkipZigTest else return err,
else => return err,
};
}
@ -847,7 +848,16 @@ test "file operations on directories" {
{
const handle = try ctx.dir.openFile(io, test_dir_name, .{ .allow_directory = true, .mode = .read_only });
handle.close(io);
defer handle.close(io);
// Reading from the handle should fail
const expected_err = switch (native_os) {
.wasi => error.NotOpenForReading,
else => error.IsDir,
};
var buf: [1]u8 = undefined;
try expectError(expected_err, handle.readStreaming(io, &.{&buf}));
try expectError(expected_err, handle.readPositional(io, &.{&buf}, 0));
}
try expectError(error.IsDir, ctx.dir.openFile(io, test_dir_name, .{ .allow_directory = false, .mode = .read_only }));
@ -2364,13 +2374,7 @@ test "readlinkat" {
try tmp.dir.writeFile(io, .{ .sub_path = "file.txt", .data = "nonsense" });
// create a symbolic link
tmp.dir.symLink(io, "file.txt", "link", .{}) catch |err| switch (err) {
error.AccessDenied => {
// Symlink requires admin privileges on windows, so this test can legitimately fail.
if (native_os == .windows) return error.SkipZigTest;
},
else => |e| return e,
};
try setupSymlink(io, tmp.dir, "file.txt", "link", .{});
// read the link
var buffer: [Dir.max_path_bytes]u8 = undefined;

View file

@ -267,7 +267,11 @@ pub const FILE = struct {
pub fn toBuffer(fri: *const RENAME_INFORMATION) []const u8 {
const start: [*]const u8 = @ptrCast(fri);
return start[0 .. @offsetOf(RENAME_INFORMATION, "FileName") + fri.FileNameLength];
// The ABI size of the documented struct is 24 bytes, and attempting to use any size
// less than that will trigger INFO_LENGTH_MISMATCH, so enforce a minimum in cases where,
// for example, FileNameLength is 1 so only 22 bytes are technically needed.
const size = @max(24, @offsetOf(RENAME_INFORMATION, "FileName") + fri.FileNameLength);
return start[0..size];
}
};