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;...@@ -1404,6 +1404,8 @@ const splat_buffer_size = 64;
1404/// posix systems.1404/// posix systems.
1405const poll_buffer_len = 64;1405const poll_buffer_len = 64;
1406const default_PATH = "/usr/local/bin:/bin/:/usr/bin";1406const 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
1408comptime {1410comptime {
1409 if (@TypeOf(posix.IOV_MAX) != void) assert(max_iovecs_len <= posix.IOV_MAX);1411 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...@@ -3256,28 +3258,114 @@ fn dirCreateDirWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permi
3256fn dirCreateDirWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permissions: Dir.Permissions) Dir.CreateDirError!void {3258fn dirCreateDirWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permissions: Dir.Permissions) Dir.CreateDirError!void {
3257 const t: *Threaded = @ptrCast(@alignCast(userdata));3259 const t: *Threaded = @ptrCast(@alignCast(userdata));
3258 _ = t;3260 _ = t;
3259
3260 const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path);
3261 _ = permissions; // TODO use this value3261 _ = permissions; // TODO use this value
32623262
3263 const sub_dir_handle = OpenFile(sub_path_w.span(), .{3263 const sub_path_w_array = try sliceToPrefixedFileW(dir.handle, sub_path);
3264 .dir = dir.handle,3264 const sub_path_w = sub_path_w_array.span();
3265 .access_mask = .{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 .{
3266 .GENERIC = .{ .READ = true },3290 .GENERIC = .{ .READ = true },
3267 .STANDARD = .{ .SYNCHRONIZE = true },3291 .STANDARD = .{ .SYNCHRONIZE = true },
3268 },3292 },
3269 .creation = .CREATE,3293 &attr,
3270 .filter = .dir_only,3294 &io_status_block,
3271 }) catch |err| switch (err) {3295 null,
3272 error.IsDir => return error.Unexpected,3296 .{ .NORMAL = true },
3273 error.PipeBusy => return error.Unexpected,3297 .VALID_FLAGS,
3274 error.FileBusy => return error.Unexpected,3298 .CREATE,
3275 error.NoDevice => return error.Unexpected,3299 .{
3276 error.WouldBlock => return error.Unexpected,3300 .DIRECTORY_FILE = true,
3277 error.AntivirusInterference => return error.Unexpected,3301 .NON_DIRECTORY_FILE = false,
3278 else => |e| return e,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),
3279 };3368 };
3280 windows.CloseHandle(sub_dir_handle);
3281}3369}
32823370
3283fn dirCreateDirPath(3371fn dirCreateDirPath(
...@@ -4307,11 +4395,7 @@ fn dirCreateFileWindows(...@@ -4307,11 +4395,7 @@ fn dirCreateFileWindows(
4307 };4395 };
43084396
4309 var io_status_block: windows.IO_STATUS_BLOCK = undefined;4397 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;
4313 var attempt: u5 = 0;4398 var attempt: u5 = 0;
4314
4315 var handle: windows.HANDLE = undefined;4399 var handle: windows.HANDLE = undefined;
4316 var syscall: Syscall = try .start();4400 var syscall: Syscall = try .start();
4317 while (true) switch (windows.ntdll.NtCreateFile(4401 while (true) switch (windows.ntdll.NtCreateFile(
...@@ -4345,7 +4429,7 @@ fn dirCreateFileWindows(...@@ -4345,7 +4429,7 @@ fn dirCreateFileWindows(
4345 // after an executable file is closed. Here we work around the4429 // after an executable file is closed. Here we work around the
4346 // kernel bug with retry attempts.4430 // kernel bug with retry attempts.
4347 syscall.finish();4431 syscall.finish();
4348 if (max_attempts - attempt == 0) return error.FileBusy;4432 if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
4349 try parking_sleep.sleep(.{ .duration = .{4433 try parking_sleep.sleep(.{ .duration = .{
4350 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),4434 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
4351 .clock = .awake,4435 .clock = .awake,
...@@ -4361,7 +4445,7 @@ fn dirCreateFileWindows(...@@ -4361,7 +4445,7 @@ fn dirCreateFileWindows(
4361 // call has failed. Here, we simulate the kernel bug being4445 // call has failed. Here, we simulate the kernel bug being
4362 // fixed by sleeping and retrying until the error goes away.4446 // fixed by sleeping and retrying until the error goes away.
4363 syscall.finish();4447 syscall.finish();
4364 if (max_attempts - attempt == 0) return error.FileBusy;4448 if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
4365 try parking_sleep.sleep(.{ .duration = .{4449 try parking_sleep.sleep(.{ .duration = .{
4366 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),4450 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
4367 .clock = .awake,4451 .clock = .awake,
...@@ -4903,11 +4987,7 @@ pub fn dirOpenFileWtf16(...@@ -4903,11 +4987,7 @@ pub fn dirOpenFileWtf16(
4903 .Buffer = @constCast(sub_path_w.ptr),4987 .Buffer = @constCast(sub_path_w.ptr),
4904 };4988 };
4905 var io_status_block: w.IO_STATUS_BLOCK = undefined;4989 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;
4909 var attempt: u5 = 0;4990 var attempt: u5 = 0;
4910
4911 var syscall: Syscall = try .start();4991 var syscall: Syscall = try .start();
4912 const handle = while (true) {4992 const handle = while (true) {
4913 var result: w.HANDLE = undefined;4993 var result: w.HANDLE = undefined;
...@@ -4959,7 +5039,7 @@ pub fn dirOpenFileWtf16(...@@ -4959,7 +5039,7 @@ pub fn dirOpenFileWtf16(
4959 // after an executable file is closed. Here we work around the5039 // after an executable file is closed. Here we work around the
4960 // kernel bug with retry attempts.5040 // kernel bug with retry attempts.
4961 syscall.finish();5041 syscall.finish();
4962 if (max_attempts - attempt == 0) return error.FileBusy;5042 if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
4963 try parking_sleep.sleep(.{ .duration = .{5043 try parking_sleep.sleep(.{ .duration = .{
4964 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),5044 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
4965 .clock = .awake,5045 .clock = .awake,
...@@ -4984,7 +5064,7 @@ pub fn dirOpenFileWtf16(...@@ -4984,7 +5064,7 @@ pub fn dirOpenFileWtf16(
4984 // call has failed. Here, we simulate the kernel bug being5064 // call has failed. Here, we simulate the kernel bug being
4985 // fixed by sleeping and retrying until the error goes away.5065 // fixed by sleeping and retrying until the error goes away.
4986 syscall.finish();5066 syscall.finish();
4987 if (max_attempts - attempt == 0) return error.FileBusy;5067 if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
4988 try parking_sleep.sleep(.{ .duration = .{5068 try parking_sleep.sleep(.{ .duration = .{
4989 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),5069 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
4990 .clock = .awake,5070 .clock = .awake,
...@@ -7850,11 +7930,7 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink...@@ -7850,11 +7930,7 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink
7850 };7930 };
7851 var io_status_block: windows.IO_STATUS_BLOCK = undefined;7931 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
7852 var result_handle: windows.HANDLE = undefined;7932 var result_handle: windows.HANDLE = undefined;
7853
7854 // There are multiple kernel bugs being worked around with retries.
7855 const max_attempts = 13;
7856 var attempt: u5 = 0;7933 var attempt: u5 = 0;
7857
7858 var syscall: Syscall = try .start();7934 var syscall: Syscall = try .start();
7859 while (true) switch (windows.ntdll.NtCreateFile(7935 while (true) switch (windows.ntdll.NtCreateFile(
7860 &result_handle,7936 &result_handle,
...@@ -7894,7 +7970,7 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink...@@ -7894,7 +7970,7 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink
7894 // after an executable file is closed. Here we work around the7970 // after an executable file is closed. Here we work around the
7895 // kernel bug with retry attempts.7971 // kernel bug with retry attempts.
7896 syscall.finish();7972 syscall.finish();
7897 if (max_attempts - attempt == 0) return error.FileBusy;7973 if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
7898 try parking_sleep.sleep(.{ .duration = .{7974 try parking_sleep.sleep(.{ .duration = .{
7899 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),7975 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
7900 .clock = .awake,7976 .clock = .awake,
...@@ -7910,7 +7986,7 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink...@@ -7910,7 +7986,7 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink
7910 // call has failed. Here, we simulate the kernel bug being7986 // call has failed. Here, we simulate the kernel bug being
7911 // fixed by sleeping and retrying until the error goes away.7987 // fixed by sleeping and retrying until the error goes away.
7912 syscall.finish();7988 syscall.finish();
7913 if (max_attempts - attempt == 0) return error.FileBusy;7989 if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
7914 try parking_sleep.sleep(.{ .duration = .{7990 try parking_sleep.sleep(.{ .duration = .{
7915 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),7991 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
7916 .clock = .awake,7992 .clock = .awake,
...@@ -19079,11 +19155,7 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows...@@ -19079,11 +19155,7 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows
19079 };19155 };
1908019156
19081 var iosb: windows.IO_STATUS_BLOCK = undefined;19157 var iosb: windows.IO_STATUS_BLOCK = undefined;
19082
19083 // There are multiple kernel bugs being worked around with retries.
19084 const max_attempts = 13;
19085 var attempt: u5 = 0;19158 var attempt: u5 = 0;
19086
19087 var syscall: Syscall = try .start();19159 var syscall: Syscall = try .start();
19088 while (true) {19160 while (true) {
19089 switch (windows.ntdll.NtCreateFile(19161 switch (windows.ntdll.NtCreateFile(
...@@ -19119,7 +19191,7 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows...@@ -19119,7 +19191,7 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows
19119 // after an executable file is closed. Here we work around the19191 // after an executable file is closed. Here we work around the
19120 // kernel bug with retry attempts.19192 // kernel bug with retry attempts.
19121 syscall.finish();19193 syscall.finish();
19122 if (max_attempts - attempt == 0) return error.FileBusy;19194 if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
19123 try parking_sleep.sleep(.{ .duration = .{19195 try parking_sleep.sleep(.{ .duration = .{
19124 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),19196 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
19125 .clock = .awake,19197 .clock = .awake,
...@@ -19136,7 +19208,7 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows...@@ -19136,7 +19208,7 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows
19136 // this other than retrying the creation after the OS finishes19208 // this other than retrying the creation after the OS finishes
19137 // the deletion.19209 // the deletion.
19138 syscall.finish();19210 syscall.finish();
19139 if (max_attempts - attempt == 0) return error.FileBusy;19211 if (max_windows_kernel_bug_retries - attempt == 0) return error.FileBusy;
19140 try parking_sleep.sleep(.{ .duration = .{19212 try parking_sleep.sleep(.{ .duration = .{
19141 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),19213 .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1),
19142 .clock = .awake,19214 .clock = .awake,