commit 0e7d00776e5468b53c2ba07ebfe9fef5abda310a (tree)
parent 3a5fff45ec04f4b713acae51a38510c316e42445
Author: Andrew Kelley <andrew@ziglang.org>
Date: Wed, 4 Feb 2026 12:44:11 -0800
std.Io.Threaded: inline OpenFile into dirCreateDirWindows
Diffstat:
1 file changed, 112 insertions(+), 40 deletions(-)
diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig
@@ -1404,6 +1404,8 @@ const splat_buffer_size = 64;
/// posix systems.
const poll_buffer_len = 64;
const default_PATH = "/usr/local/bin:/bin/:/usr/bin";
+/// There are multiple kernel bugs being worked around with retries.
+const max_windows_kernel_bug_retries = 13;
comptime {
if (@TypeOf(posix.IOV_MAX) != void) assert(max_iovecs_len <= posix.IOV_MAX);
@@ -3256,28 +3258,114 @@ fn dirCreateDirWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permi
fn dirCreateDirWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permissions: Dir.Permissions) Dir.CreateDirError!void {
const t: *Threaded = @ptrCast(@alignCast(userdata));
_ = t;
-
- const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path);
_ = permissions; // TODO use this value
- const sub_dir_handle = OpenFile(sub_path_w.span(), .{
- .dir = dir.handle,
- .access_mask = .{
+ const sub_path_w_array = try sliceToPrefixedFileW(dir.handle, sub_path);
+ const sub_path_w = sub_path_w_array.span();
+ const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;
+
+ var nt_name: windows.UNICODE_STRING = .{
+ .Length = path_len_bytes,
+ .MaximumLength = path_len_bytes,
+ .Buffer = @constCast(sub_path_w.ptr),
+ };
+ const attr: windows.OBJECT_ATTRIBUTES = .{
+ .Length = @sizeOf(windows.OBJECT_ATTRIBUTES),
+ .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle,
+ .Attributes = .{
+ .INHERIT = false,
+ },
+ .ObjectName = &nt_name,
+ .SecurityDescriptor = null,
+ .SecurityQualityOfService = null,
+ };
+
+ var sub_dir_handle: windows.HANDLE = undefined;
+ var io_status_block: windows.IO_STATUS_BLOCK = undefined;
+ var attempt: u5 = 0;
+ var syscall: Syscall = try .start();
+ while (true) switch (windows.ntdll.NtCreateFile(
+ &sub_dir_handle,
+ .{
.GENERIC = .{ .READ = true },
.STANDARD = .{ .SYNCHRONIZE = true },
},
- .creation = .CREATE,
- .filter = .dir_only,
- }) catch |err| switch (err) {
- error.IsDir => return error.Unexpected,
- error.PipeBusy => return error.Unexpected,
- error.FileBusy => return error.Unexpected,
- error.NoDevice => return error.Unexpected,
- error.WouldBlock => return error.Unexpected,
- error.AntivirusInterference => return error.Unexpected,
- else => |e| return e,
+ &attr,
+ &io_status_block,
+ null,
+ .{ .NORMAL = true },
+ .VALID_FLAGS,
+ .CREATE,
+ .{
+ .DIRECTORY_FILE = true,
+ .NON_DIRECTORY_FILE = false,
+ .IO = .SYNCHRONOUS_NONALERT,
+ .OPEN_REPARSE_POINT = false,
+ },
+ null,
+ 0,
+ )) {
+ .SUCCESS => {
+ syscall.finish();
+ windows.CloseHandle(sub_dir_handle);
+ return;
+ },
+ .CANCELLED => {
+ try syscall.checkCancel();
+ continue;
+ },
+ .SHARING_VIOLATION => {
+ // This occurs if the file attempting to be opened is a running
+ // executable. However, there's a kernel bug: the error may be
+ // incorrectly returned for an indeterminate amount of time
+ // after an executable file is closed. Here we work around the
+ // kernel bug with retry attempts.
+ syscall.finish();
+ if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
+ try parking_sleep.sleep(.{ .duration = .{
+ .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
+ .clock = .awake,
+ } });
+ attempt += 1;
+ syscall = try .start();
+ continue;
+ },
+ .DELETE_PENDING => {
+ // This error means that there *was* a file in this location on
+ // the file system, but it was deleted. However, the OS is not
+ // finished with the deletion operation, and so this CreateFile
+ // call has failed. There is not really a sane way to handle
+ // this other than retrying the creation after the OS finishes
+ // the deletion.
+ syscall.finish();
+ if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
+ try parking_sleep.sleep(.{ .duration = .{
+ .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
+ .clock = .awake,
+ } });
+ attempt += 1;
+ syscall = try .start();
+ continue;
+ },
+ .OBJECT_NAME_INVALID => return syscall.fail(error.BadPathName),
+ .OBJECT_NAME_NOT_FOUND => return syscall.fail(error.FileNotFound),
+ .OBJECT_PATH_NOT_FOUND => return syscall.fail(error.FileNotFound),
+ .BAD_NETWORK_PATH => return syscall.fail(error.NetworkNotFound), // \\server was not found
+ .BAD_NETWORK_NAME => return syscall.fail(error.NetworkNotFound), // \\server was found but \\server\share wasn't
+ .NO_MEDIA_IN_DEVICE => return syscall.fail(error.NoDevice),
+ .ACCESS_DENIED => return syscall.fail(error.AccessDenied),
+ .PIPE_BUSY => return syscall.fail(error.PipeBusy),
+ .PIPE_NOT_AVAILABLE => return syscall.fail(error.NoDevice),
+ .OBJECT_NAME_COLLISION => return syscall.fail(error.PathAlreadyExists),
+ .FILE_IS_A_DIRECTORY => return syscall.fail(error.IsDir),
+ .NOT_A_DIRECTORY => return syscall.fail(error.NotDir),
+ .USER_MAPPED_FILE => return syscall.fail(error.AccessDenied),
+ .VIRUS_INFECTED, .VIRUS_DELETED => return syscall.fail(error.AntivirusInterference),
+ .INVALID_PARAMETER => |status| return syscall.ntstatusBug(status),
+ .OBJECT_PATH_SYNTAX_BAD => |status| return syscall.ntstatusBug(status),
+ .INVALID_HANDLE => |status| return syscall.ntstatusBug(status),
+ else => |status| return syscall.unexpectedNtstatus(status),
};
- windows.CloseHandle(sub_dir_handle);
}
fn dirCreateDirPath(
@@ -4307,11 +4395,7 @@ fn dirCreateFileWindows(
};
var io_status_block: windows.IO_STATUS_BLOCK = undefined;
-
- // There are multiple kernel bugs being worked around with retries.
- const max_attempts = 13;
var attempt: u5 = 0;
-
var handle: windows.HANDLE = undefined;
var syscall: Syscall = try .start();
while (true) switch (windows.ntdll.NtCreateFile(
@@ -4345,7 +4429,7 @@ fn dirCreateFileWindows(
// after an executable file is closed. Here we work around the
// kernel bug with retry attempts.
syscall.finish();
- if (max_attempts - attempt == 0) return error.FileBusy;
+ if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
try parking_sleep.sleep(.{ .duration = .{
.raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
.clock = .awake,
@@ -4361,7 +4445,7 @@ fn dirCreateFileWindows(
// call has failed. Here, we simulate the kernel bug being
// fixed by sleeping and retrying until the error goes away.
syscall.finish();
- if (max_attempts - attempt == 0) return error.FileBusy;
+ if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
try parking_sleep.sleep(.{ .duration = .{
.raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
.clock = .awake,
@@ -4903,11 +4987,7 @@ pub fn dirOpenFileWtf16(
.Buffer = @constCast(sub_path_w.ptr),
};
var io_status_block: w.IO_STATUS_BLOCK = undefined;
-
- // There are multiple kernel bugs being worked around with retries.
- const max_attempts = 13;
var attempt: u5 = 0;
-
var syscall: Syscall = try .start();
const handle = while (true) {
var result: w.HANDLE = undefined;
@@ -4959,7 +5039,7 @@ pub fn dirOpenFileWtf16(
// after an executable file is closed. Here we work around the
// kernel bug with retry attempts.
syscall.finish();
- if (max_attempts - attempt == 0) return error.FileBusy;
+ if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
try parking_sleep.sleep(.{ .duration = .{
.raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
.clock = .awake,
@@ -4984,7 +5064,7 @@ pub fn dirOpenFileWtf16(
// call has failed. Here, we simulate the kernel bug being
// fixed by sleeping and retrying until the error goes away.
syscall.finish();
- if (max_attempts - attempt == 0) return error.FileBusy;
+ if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
try parking_sleep.sleep(.{ .duration = .{
.raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
.clock = .awake,
@@ -7850,11 +7930,7 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink
};
var io_status_block: windows.IO_STATUS_BLOCK = undefined;
var result_handle: windows.HANDLE = undefined;
-
- // There are multiple kernel bugs being worked around with retries.
- const max_attempts = 13;
var attempt: u5 = 0;
-
var syscall: Syscall = try .start();
while (true) switch (windows.ntdll.NtCreateFile(
&result_handle,
@@ -7894,7 +7970,7 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink
// after an executable file is closed. Here we work around the
// kernel bug with retry attempts.
syscall.finish();
- if (max_attempts - attempt == 0) return error.FileBusy;
+ if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
try parking_sleep.sleep(.{ .duration = .{
.raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
.clock = .awake,
@@ -7910,7 +7986,7 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink
// call has failed. Here, we simulate the kernel bug being
// fixed by sleeping and retrying until the error goes away.
syscall.finish();
- if (max_attempts - attempt == 0) return error.FileBusy;
+ if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
try parking_sleep.sleep(.{ .duration = .{
.raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
.clock = .awake,
@@ -19079,11 +19155,7 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows
};
var iosb: windows.IO_STATUS_BLOCK = undefined;
-
- // There are multiple kernel bugs being worked around with retries.
- const max_attempts = 13;
var attempt: u5 = 0;
-
var syscall: Syscall = try .start();
while (true) {
switch (windows.ntdll.NtCreateFile(
@@ -19119,7 +19191,7 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows
// after an executable file is closed. Here we work around the
// kernel bug with retry attempts.
syscall.finish();
- if (max_attempts - attempt == 0) return error.FileBusy;
+ if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
try parking_sleep.sleep(.{ .duration = .{
.raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
.clock = .awake,
@@ -19136,7 +19208,7 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows
// this other than retrying the creation after the OS finishes
// the deletion.
syscall.finish();
- if (max_attempts - attempt == 0) return error.FileBusy;
+ if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
try parking_sleep.sleep(.{ .duration = .{
.raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
.clock = .awake,