| ... | ... | @@ -1404,6 +1404,8 @@ const splat_buffer_size = 64; |
| 1404 | 1404 | /// posix systems. |
| 1405 | 1405 | const poll_buffer_len = 64; |
| 1406 | 1406 | const default_PATH = "/usr/local/bin:/bin/:/usr/bin"; |
| 1407 | /// There are multiple kernel bugs being worked around with retries. |
| 1408 | const max_windows_kernel_bug_retries = 13; |
| 1407 | 1409 | |
| 1408 | 1410 | comptime { |
| 1409 | 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 | 3258 | fn dirCreateDirWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permissions: Dir.Permissions) Dir.CreateDirError!void { |
| 3257 | 3259 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 3258 | 3260 | _ = t; |
| 3259 | | |
| 3260 | | const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path); |
| 3261 | 3261 | _ = permissions; // TODO use this value |
| 3262 | 3262 | |
| 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 | .{ |
| 3266 | 3290 | .GENERIC = .{ .READ = true }, |
| 3267 | 3291 | .STANDARD = .{ .SYNCHRONIZE = true }, |
| 3268 | 3292 | }, |
| 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), |
| 3279 | 3368 | }; |
| 3280 | | windows.CloseHandle(sub_dir_handle); |
| 3281 | 3369 | } |
| 3282 | 3370 | |
| 3283 | 3371 | fn dirCreateDirPath( |
| ... | ... | @@ -4307,11 +4395,7 @@ fn dirCreateFileWindows( |
| 4307 | 4395 | }; |
| 4308 | 4396 | |
| 4309 | 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 | 4398 | var attempt: u5 = 0; |
| 4314 | | |
| 4315 | 4399 | var handle: windows.HANDLE = undefined; |
| 4316 | 4400 | var syscall: Syscall = try .start(); |
| 4317 | 4401 | while (true) switch (windows.ntdll.NtCreateFile( |
| ... | ... | @@ -4345,7 +4429,7 @@ fn dirCreateFileWindows( |
| 4345 | 4429 | // after an executable file is closed. Here we work around the |
| 4346 | 4430 | // kernel bug with retry attempts. |
| 4347 | 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 | 4433 | try parking_sleep.sleep(.{ .duration = .{ |
| 4350 | 4434 | .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1), |
| 4351 | 4435 | .clock = .awake, |
| ... | ... | @@ -4361,7 +4445,7 @@ fn dirCreateFileWindows( |
| 4361 | 4445 | // call has failed. Here, we simulate the kernel bug being |
| 4362 | 4446 | // fixed by sleeping and retrying until the error goes away. |
| 4363 | 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 | 4449 | try parking_sleep.sleep(.{ .duration = .{ |
| 4366 | 4450 | .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1), |
| 4367 | 4451 | .clock = .awake, |
| ... | ... | @@ -4903,11 +4987,7 @@ pub fn dirOpenFileWtf16( |
| 4903 | 4987 | .Buffer = @constCast(sub_path_w.ptr), |
| 4904 | 4988 | }; |
| 4905 | 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 | 4990 | var attempt: u5 = 0; |
| 4910 | | |
| 4911 | 4991 | var syscall: Syscall = try .start(); |
| 4912 | 4992 | const handle = while (true) { |
| 4913 | 4993 | var result: w.HANDLE = undefined; |
| ... | ... | @@ -4959,7 +5039,7 @@ pub fn dirOpenFileWtf16( |
| 4959 | 5039 | // after an executable file is closed. Here we work around the |
| 4960 | 5040 | // kernel bug with retry attempts. |
| 4961 | 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 | 5043 | try parking_sleep.sleep(.{ .duration = .{ |
| 4964 | 5044 | .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1), |
| 4965 | 5045 | .clock = .awake, |
| ... | ... | @@ -4984,7 +5064,7 @@ pub fn dirOpenFileWtf16( |
| 4984 | 5064 | // call has failed. Here, we simulate the kernel bug being |
| 4985 | 5065 | // fixed by sleeping and retrying until the error goes away. |
| 4986 | 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 | 5068 | try parking_sleep.sleep(.{ .duration = .{ |
| 4989 | 5069 | .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1), |
| 4990 | 5070 | .clock = .awake, |
| ... | ... | @@ -7850,11 +7930,7 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink |
| 7850 | 7930 | }; |
| 7851 | 7931 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; |
| 7852 | 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 | 7933 | var attempt: u5 = 0; |
| 7857 | | |
| 7858 | 7934 | var syscall: Syscall = try .start(); |
| 7859 | 7935 | while (true) switch (windows.ntdll.NtCreateFile( |
| 7860 | 7936 | &result_handle, |
| ... | ... | @@ -7894,7 +7970,7 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink |
| 7894 | 7970 | // after an executable file is closed. Here we work around the |
| 7895 | 7971 | // kernel bug with retry attempts. |
| 7896 | 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 | 7974 | try parking_sleep.sleep(.{ .duration = .{ |
| 7899 | 7975 | .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1), |
| 7900 | 7976 | .clock = .awake, |
| ... | ... | @@ -7910,7 +7986,7 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink |
| 7910 | 7986 | // call has failed. Here, we simulate the kernel bug being |
| 7911 | 7987 | // fixed by sleeping and retrying until the error goes away. |
| 7912 | 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 | 7990 | try parking_sleep.sleep(.{ .duration = .{ |
| 7915 | 7991 | .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1), |
| 7916 | 7992 | .clock = .awake, |
| ... | ... | @@ -19079,11 +19155,7 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows |
| 19079 | 19155 | }; |
| 19080 | 19156 | |
| 19081 | 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 | 19158 | var attempt: u5 = 0; |
| 19086 | | |
| 19087 | 19159 | var syscall: Syscall = try .start(); |
| 19088 | 19160 | while (true) { |
| 19089 | 19161 | switch (windows.ntdll.NtCreateFile( |
| ... | ... | @@ -19119,7 +19191,7 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows |
| 19119 | 19191 | // after an executable file is closed. Here we work around the |
| 19120 | 19192 | // kernel bug with retry attempts. |
| 19121 | 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 | 19195 | try parking_sleep.sleep(.{ .duration = .{ |
| 19124 | 19196 | .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1), |
| 19125 | 19197 | .clock = .awake, |
| ... | ... | @@ -19136,7 +19208,7 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows |
| 19136 | 19208 | // this other than retrying the creation after the OS finishes |
| 19137 | 19209 | // the deletion. |
| 19138 | 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 | 19212 | try parking_sleep.sleep(.{ .duration = .{ |
| 19141 | 19213 | .raw = .fromMilliseconds((@as(u32, 1) << attempt) >> 1), |
| 19142 | 19214 | .clock = .awake, |