authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2026-06-23 19:44:36-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-06-24 20:15:50+02:00
logd3f7cf7345020410cbb0b3ff2e19947752283846
treefb158dc38b5a340426d1789c89b3f8094324fa4b
parentb52a2ff73bb5796995c54f2ba7b9cf5f8ee38297

Io.Threaded: Fix dirReadLinkWindows not handling its async handle correctly

NtCreateFile is called with `.IO = .ASYNCHRONOUS` but then `NtFsControlFile` is called without any handling of `PENDING`. By switching to the `deviceIoControl` helper function, `PENDING` is handled since we are passing `.nonblocking = true`. Fixes https://codeberg.org/ziglang/zig/issues/35871

1 files changed, 10 insertions(+), 25 deletions(-)

lib/std/Io/Threaded.zig+10-25
...@@ -8176,31 +8176,16 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink...@@ -8176,31 +8176,16 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink
8176 defer windows.CloseHandle(result_handle);8176 defer windows.CloseHandle(result_handle);
81778177
8178 var reparse_buf: [windows.MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 align(@alignOf(windows.REPARSE_DATA_BUFFER)) = undefined;8178 var reparse_buf: [windows.MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 align(@alignOf(windows.REPARSE_DATA_BUFFER)) = undefined;
81798179 switch ((try deviceIoControl(&.{
8180 syscall = try .start();8180 .file = .{ .handle = result_handle, .flags = .{ .nonblocking = true } },
8181 while (true) switch (windows.ntdll.NtFsControlFile(8181 .code = .GET_REPARSE_POINT,
8182 result_handle,8182 .out = &reparse_buf,
8183 null, // event8183 })).u.Status) {
8184 null, // APC routine8184 .SUCCESS => {},
8185 null, // APC context8185 .CANCELLED => unreachable,
8186 &io_status_block,8186 .NOT_A_REPARSE_POINT => return error.NotLink,
8187 .GET_REPARSE_POINT,8187 else => |status| return windows.unexpectedStatus(status),
8188 null, // input buffer8188 }
8189 0, // input buffer length
8190 &reparse_buf,
8191 reparse_buf.len,
8192 )) {
8193 .SUCCESS => {
8194 syscall.finish();
8195 break;
8196 },
8197 .CANCELLED => {
8198 try syscall.checkCancel();
8199 continue;
8200 },
8201 .NOT_A_REPARSE_POINT => return syscall.fail(error.NotLink),
8202 else => |status| return syscall.unexpectedNtstatus(status),
8203 };
82048189
8205 const reparse_struct: *const windows.REPARSE_DATA_BUFFER = @ptrCast(@alignCast(&reparse_buf));8190 const reparse_struct: *const windows.REPARSE_DATA_BUFFER = @ptrCast(@alignCast(&reparse_buf));
8206 const IoReparseTagInt = @typeInfo(windows.IO_REPARSE_TAG).@"struct".backing_integer.?;8191 const IoReparseTagInt = @typeInfo(windows.IO_REPARSE_TAG).@"struct".backing_integer.?;