| ... | @@ -1404,6 +1404,8 @@ const splat_buffer_size = 64; | ... | @@ -1404,6 +1404,8 @@ const splat_buffer_size = 64; |
| 1404 | /// posix systems. | 1404 | /// posix systems. |
| 1405 | const poll_buffer_len = 64; | 1405 | const poll_buffer_len = 64; |
| 1406 | const default_PATH = "/usr/local/bin:/bin/:/usr/bin"; | 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 | comptime { | 1410 | comptime { |
| 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 |
| 3256 | fn dirCreateDirWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permissions: Dir.Permissions) Dir.CreateDirError!void { | 3258 | fn 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 value | 3261 | _ = permissions; // TODO use this value |
| 3262 | | 3262 | |
| 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 | } |
| 3282 | | 3370 | |
| 3283 | fn dirCreateDirPath( | 3371 | fn dirCreateDirPath( |
| ... | @@ -4307,11 +4395,7 @@ fn dirCreateFileWindows( | ... | @@ -4307,11 +4395,7 @@ fn dirCreateFileWindows( |
| 4307 | }; | 4395 | }; |
| 4308 | | 4396 | |
| 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 the | 4429 | // 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 being | 4445 | // 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 the | 5039 | // 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 being | 5064 | // 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 the | 7970 | // 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 being | 7986 | // 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 | }; |
| 19080 | | 19156 | |
| 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 the | 19191 | // 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 finishes | 19208 | // 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, |