authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-04 12:44:11-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-04 16:30:19-08:00
log0e7d00776e5468b53c2ba07ebfe9fef5abda310a
treed7167a62bfdefe09a837237859869bc657a04263
parent3a5fff45ec04f4b713acae51a38510c316e42445

std.Io.Threaded: inline OpenFile into dirCreateDirWindows


1 files changed, 112 insertions(+), 40 deletions(-)

lib/std/Io/Threaded.zig+112-40
......@@ -1404,6 +1404,8 @@ const splat_buffer_size = 64;
14041404/// posix systems.
14051405const poll_buffer_len = 64;
14061406const default_PATH = "/usr/local/bin:/bin/:/usr/bin";
1407/// There are multiple kernel bugs being worked around with retries.
1408const max_windows_kernel_bug_retries = 13;
14071409
14081410comptime {
14091411 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
32563258fn dirCreateDirWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permissions: Dir.Permissions) Dir.CreateDirError!void {
32573259 const t: *Threaded = @ptrCast(@alignCast(userdata));
32583260 _ = t;
3259
3260 const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path);
32613261 _ = permissions; // TODO use this value
32623262
3263 const sub_dir_handle = OpenFile(sub_path_w.span(), .{
3264 .dir = dir.handle,
3265 .access_mask = .{
3263 const sub_path_w_array = try sliceToPrefixedFileW(dir.handle, sub_path);
3264 const sub_path_w = sub_path_w_array.span();
3265 const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;
3266
3267 var nt_name: windows.UNICODE_STRING = .{
3268 .Length = path_len_bytes,
3269 .MaximumLength = path_len_bytes,
3270 .Buffer = @constCast(sub_path_w.ptr),
3271 };
3272 const attr: windows.OBJECT_ATTRIBUTES = .{
3273 .Length = @sizeOf(windows.OBJECT_ATTRIBUTES),
3274 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle,
3275 .Attributes = .{
3276 .INHERIT = false,
3277 },
3278 .ObjectName = &nt_name,
3279 .SecurityDescriptor = null,
3280 .SecurityQualityOfService = null,
3281 };
3282
3283 var sub_dir_handle: windows.HANDLE = undefined;
3284 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
3285 var attempt: u5 = 0;
3286 var syscall: Syscall = try .start();
3287 while (true) switch (windows.ntdll.NtCreateFile(
3288 &sub_dir_handle,
3289 .{
32663290 .GENERIC = .{ .READ = true },
32673291 .STANDARD = .{ .SYNCHRONIZE = true },
32683292 },
3269 .creation = .CREATE,
3270 .filter = .dir_only,
3271 }) catch |err| switch (err) {
3272 error.IsDir => return error.Unexpected,
3273 error.PipeBusy => return error.Unexpected,
3274 error.FileBusy => return error.Unexpected,
3275 error.NoDevice => return error.Unexpected,
3276 error.WouldBlock => return error.Unexpected,
3277 error.AntivirusInterference => return error.Unexpected,
3278 else => |e| return e,
3293 &attr,
3294 &io_status_block,
3295 null,
3296 .{ .NORMAL = true },
3297 .VALID_FLAGS,
3298 .CREATE,
3299 .{
3300 .DIRECTORY_FILE = true,
3301 .NON_DIRECTORY_FILE = false,
3302 .IO = .SYNCHRONOUS_NONALERT,
3303 .OPEN_REPARSE_POINT = false,
3304 },
3305 null,
3306 0,
3307 )) {
3308 .SUCCESS => {
3309 syscall.finish();
3310 windows.CloseHandle(sub_dir_handle);
3311 return;
3312 },
3313 .CANCELLED => {
3314 try syscall.checkCancel();
3315 continue;
3316 },
3317 .SHARING_VIOLATION => {
3318 // This occurs if the file attempting to be opened is a running
3319 // executable. However, there's a kernel bug: the error may be
3320 // incorrectly returned for an indeterminate amount of time
3321 // after an executable file is closed. Here we work around the
3322 // kernel bug with retry attempts.
3323 syscall.finish();
3324 if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
3325 try parking_sleep.sleep(.{ .duration = .{
3326 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
3327 .clock = .awake,
3328 } });
3329 attempt += 1;
3330 syscall = try .start();
3331 continue;
3332 },
3333 .DELETE_PENDING => {
3334 // This error means that there *was* a file in this location on
3335 // the file system, but it was deleted. However, the OS is not
3336 // finished with the deletion operation, and so this CreateFile
3337 // call has failed. There is not really a sane way to handle
3338 // this other than retrying the creation after the OS finishes
3339 // the deletion.
3340 syscall.finish();
3341 if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
3342 try parking_sleep.sleep(.{ .duration = .{
3343 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
3344 .clock = .awake,
3345 } });
3346 attempt += 1;
3347 syscall = try .start();
3348 continue;
3349 },
3350 .OBJECT_NAME_INVALID => return syscall.fail(error.BadPathName),
3351 .OBJECT_NAME_NOT_FOUND => return syscall.fail(error.FileNotFound),
3352 .OBJECT_PATH_NOT_FOUND => return syscall.fail(error.FileNotFound),
3353 .BAD_NETWORK_PATH => return syscall.fail(error.NetworkNotFound), // \\server was not found
3354 .BAD_NETWORK_NAME => return syscall.fail(error.NetworkNotFound), // \\server was found but \\server\share wasn't
3355 .NO_MEDIA_IN_DEVICE => return syscall.fail(error.NoDevice),
3356 .ACCESS_DENIED => return syscall.fail(error.AccessDenied),
3357 .PIPE_BUSY => return syscall.fail(error.PipeBusy),
3358 .PIPE_NOT_AVAILABLE => return syscall.fail(error.NoDevice),
3359 .OBJECT_NAME_COLLISION => return syscall.fail(error.PathAlreadyExists),
3360 .FILE_IS_A_DIRECTORY => return syscall.fail(error.IsDir),
3361 .NOT_A_DIRECTORY => return syscall.fail(error.NotDir),
3362 .USER_MAPPED_FILE => return syscall.fail(error.AccessDenied),
3363 .VIRUS_INFECTED, .VIRUS_DELETED => return syscall.fail(error.AntivirusInterference),
3364 .INVALID_PARAMETER => |status| return syscall.ntstatusBug(status),
3365 .OBJECT_PATH_SYNTAX_BAD => |status| return syscall.ntstatusBug(status),
3366 .INVALID_HANDLE => |status| return syscall.ntstatusBug(status),
3367 else => |status| return syscall.unexpectedNtstatus(status),
32793368 };
3280 windows.CloseHandle(sub_dir_handle);
32813369}
32823370
32833371fn dirCreateDirPath(
......@@ -4307,11 +4395,7 @@ fn dirCreateFileWindows(
43074395 };
43084396
43094397 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
4310
4311 // There are multiple kernel bugs being worked around with retries.
4312 const max_attempts = 13;
43134398 var attempt: u5 = 0;
4314
43154399 var handle: windows.HANDLE = undefined;
43164400 var syscall: Syscall = try .start();
43174401 while (true) switch (windows.ntdll.NtCreateFile(
......@@ -4345,7 +4429,7 @@ fn dirCreateFileWindows(
43454429 // after an executable file is closed. Here we work around the
43464430 // kernel bug with retry attempts.
43474431 syscall.finish();
4348 if (max_attempts - attempt == 0) return error.FileBusy;
4432 if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
43494433 try parking_sleep.sleep(.{ .duration = .{
43504434 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
43514435 .clock = .awake,
......@@ -4361,7 +4445,7 @@ fn dirCreateFileWindows(
43614445 // call has failed. Here, we simulate the kernel bug being
43624446 // fixed by sleeping and retrying until the error goes away.
43634447 syscall.finish();
4364 if (max_attempts - attempt == 0) return error.FileBusy;
4448 if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
43654449 try parking_sleep.sleep(.{ .duration = .{
43664450 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
43674451 .clock = .awake,
......@@ -4903,11 +4987,7 @@ pub fn dirOpenFileWtf16(
49034987 .Buffer = @constCast(sub_path_w.ptr),
49044988 };
49054989 var io_status_block: w.IO_STATUS_BLOCK = undefined;
4906
4907 // There are multiple kernel bugs being worked around with retries.
4908 const max_attempts = 13;
49094990 var attempt: u5 = 0;
4910
49114991 var syscall: Syscall = try .start();
49124992 const handle = while (true) {
49134993 var result: w.HANDLE = undefined;
......@@ -4959,7 +5039,7 @@ pub fn dirOpenFileWtf16(
49595039 // after an executable file is closed. Here we work around the
49605040 // kernel bug with retry attempts.
49615041 syscall.finish();
4962 if (max_attempts - attempt == 0) return error.FileBusy;
5042 if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
49635043 try parking_sleep.sleep(.{ .duration = .{
49645044 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
49655045 .clock = .awake,
......@@ -4984,7 +5064,7 @@ pub fn dirOpenFileWtf16(
49845064 // call has failed. Here, we simulate the kernel bug being
49855065 // fixed by sleeping and retrying until the error goes away.
49865066 syscall.finish();
4987 if (max_attempts - attempt == 0) return error.FileBusy;
5067 if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
49885068 try parking_sleep.sleep(.{ .duration = .{
49895069 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
49905070 .clock = .awake,
......@@ -7850,11 +7930,7 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink
78507930 };
78517931 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
78527932 var result_handle: windows.HANDLE = undefined;
7853
7854 // There are multiple kernel bugs being worked around with retries.
7855 const max_attempts = 13;
78567933 var attempt: u5 = 0;
7857
78587934 var syscall: Syscall = try .start();
78597935 while (true) switch (windows.ntdll.NtCreateFile(
78607936 &result_handle,
......@@ -7894,7 +7970,7 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink
78947970 // after an executable file is closed. Here we work around the
78957971 // kernel bug with retry attempts.
78967972 syscall.finish();
7897 if (max_attempts - attempt == 0) return error.FileBusy;
7973 if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
78987974 try parking_sleep.sleep(.{ .duration = .{
78997975 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
79007976 .clock = .awake,
......@@ -7910,7 +7986,7 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink
79107986 // call has failed. Here, we simulate the kernel bug being
79117987 // fixed by sleeping and retrying until the error goes away.
79127988 syscall.finish();
7913 if (max_attempts - attempt == 0) return error.FileBusy;
7989 if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
79147990 try parking_sleep.sleep(.{ .duration = .{
79157991 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
79167992 .clock = .awake,
......@@ -19079,11 +19155,7 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows
1907919155 };
1908019156
1908119157 var iosb: windows.IO_STATUS_BLOCK = undefined;
19082
19083 // There are multiple kernel bugs being worked around with retries.
19084 const max_attempts = 13;
1908519158 var attempt: u5 = 0;
19086
1908719159 var syscall: Syscall = try .start();
1908819160 while (true) {
1908919161 switch (windows.ntdll.NtCreateFile(
......@@ -19119,7 +19191,7 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows
1911919191 // after an executable file is closed. Here we work around the
1912019192 // kernel bug with retry attempts.
1912119193 syscall.finish();
19122 if (max_attempts - attempt == 0) return error.FileBusy;
19194 if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
1912319195 try parking_sleep.sleep(.{ .duration = .{
1912419196 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
1912519197 .clock = .awake,
......@@ -19136,7 +19208,7 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows
1913619208 // this other than retrying the creation after the OS finishes
1913719209 // the deletion.
1913819210 syscall.finish();
19139 if (max_attempts - attempt == 0) return error.FileBusy;
19211 if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
1914019212 try parking_sleep.sleep(.{ .duration = .{
1914119213 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
1914219214 .clock = .awake,