authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-29 08:40:37+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-29 08:40:37+01:00
log37a9ca71634ea256ddc9466b7773feb394e02a8d
tree65cb6c2fbfabd6be770c3574f01efd53bb6cc5df
parent757ec185f0eb91a15c4bdbe0201f0d998f30258c
parent18c6abc0ba9a58a3d25908c47df3bb9374d51c35

Merge pull request 'std: finish moving os.windows.ReadLink logic to Io.Threaded' (#31044) from windows-OpenFile into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31044

7 files changed, 219 insertions(+), 292 deletions(-)

lib/std/Io/Dir.zig+5-1
...@@ -940,6 +940,7 @@ pub const RenameError = error{...@@ -940,6 +940,7 @@ pub const RenameError = error{
940 /// Attempted to replace a nonempty directory.940 /// Attempted to replace a nonempty directory.
941 DirNotEmpty,941 DirNotEmpty,
942 PermissionDenied,942 PermissionDenied,
943 /// The file attempted to be moved or replaced is a running executable.
943 FileBusy,944 FileBusy,
944 DiskQuota,945 DiskQuota,
945 IsDir,946 IsDir,
...@@ -952,7 +953,6 @@ pub const RenameError = error{...@@ -952,7 +953,6 @@ pub const RenameError = error{
952 ReadOnlyFileSystem,953 ReadOnlyFileSystem,
953 CrossDevice,954 CrossDevice,
954 NoDevice,955 NoDevice,
955 SharingViolation,
956 PipeBusy,956 PipeBusy,
957 /// On Windows, `\\server` or `\\server\share` was not found.957 /// On Windows, `\\server` or `\\server\share` was not found.
958 NetworkNotFound,958 NetworkNotFound,
...@@ -1167,6 +1167,8 @@ pub const ReadLinkError = error{...@@ -1167,6 +1167,8 @@ pub const ReadLinkError = error{
1167 /// intercepts file system operations and makes them significantly slower1167 /// intercepts file system operations and makes them significantly slower
1168 /// in addition to possibly failing with this error code.1168 /// in addition to possibly failing with this error code.
1169 AntivirusInterference,1169 AntivirusInterference,
1170 /// File attempted to be opened is a running executable.
1171 FileBusy,
1170} || PathNameError || Io.Cancelable || Io.UnexpectedError;1172} || PathNameError || Io.Cancelable || Io.UnexpectedError;
11711173
1172/// Obtain target of a symbolic link.1174/// Obtain target of a symbolic link.
...@@ -1791,6 +1793,8 @@ pub const CreateFileAtomicError = error{...@@ -1791,6 +1793,8 @@ pub const CreateFileAtomicError = error{
1791 NotDir,1793 NotDir,
1792 WouldBlock,1794 WouldBlock,
1793 ReadOnlyFileSystem,1795 ReadOnlyFileSystem,
1796 /// The file attempted to be created is a running executable.
1797 FileBusy,
1794} || Io.Dir.PathNameError || Io.Cancelable || Io.UnexpectedError;1798} || Io.Dir.PathNameError || Io.Cancelable || Io.UnexpectedError;
17951799
1796/// Create an unnamed ephemeral file that can eventually be atomically1800/// Create an unnamed ephemeral file that can eventually be atomically
lib/std/Io/File.zig+1-2
...@@ -249,7 +249,6 @@ pub const CreateFlags = struct {...@@ -249,7 +249,6 @@ pub const CreateFlags = struct {
249};249};
250250
251pub const OpenError = error{251pub const OpenError = error{
252 SharingViolation,
253 PipeBusy,252 PipeBusy,
254 NoDevice,253 NoDevice,
255 /// On Windows, `\\server` or `\\server\share` was not found.254 /// On Windows, `\\server` or `\\server\share` was not found.
...@@ -757,7 +756,7 @@ pub const RealPathError = error{...@@ -757,7 +756,7 @@ pub const RealPathError = error{
757 NoSpaceLeft,756 NoSpaceLeft,
758 FileSystem,757 FileSystem,
759 DeviceBusy,758 DeviceBusy,
760 SharingViolation,759 FileBusy,
761 PipeBusy,760 PipeBusy,
762 /// On Windows, `\\server` or `\\server\share` was not found.761 /// On Windows, `\\server` or `\\server\share` was not found.
763 NetworkNotFound,762 NetworkNotFound,
lib/std/Io/Threaded.zig+202-74
...@@ -3635,7 +3635,7 @@ fn dirCreateFileWindows(...@@ -3635,7 +3635,7 @@ fn dirCreateFileWindows(
3635 // after an executable file is closed. Here we work around the3635 // after an executable file is closed. Here we work around the
3636 // kernel bug with retry attempts.3636 // kernel bug with retry attempts.
3637 syscall.finish();3637 syscall.finish();
3638 if (max_attempts - attempt == 0) return error.SharingViolation;3638 if (max_attempts - attempt == 0) return error.FileBusy;
3639 try parking_sleep.windowsRetrySleep((@as(u32, 1) << attempt) >> 1);3639 try parking_sleep.windowsRetrySleep((@as(u32, 1) << attempt) >> 1);
3640 attempt += 1;3640 attempt += 1;
3641 syscall = try .start();3641 syscall = try .start();
...@@ -3648,7 +3648,7 @@ fn dirCreateFileWindows(...@@ -3648,7 +3648,7 @@ fn dirCreateFileWindows(
3648 // call has failed. Here, we simulate the kernel bug being3648 // call has failed. Here, we simulate the kernel bug being
3649 // fixed by sleeping and retrying until the error goes away.3649 // fixed by sleeping and retrying until the error goes away.
3650 syscall.finish();3650 syscall.finish();
3651 if (max_attempts - attempt == 0) return error.SharingViolation;3651 if (max_attempts - attempt == 0) return error.FileBusy;
3652 try parking_sleep.windowsRetrySleep((@as(u32, 1) << attempt) >> 1);3652 try parking_sleep.windowsRetrySleep((@as(u32, 1) << attempt) >> 1);
3653 attempt += 1;3653 attempt += 1;
3654 syscall = try .start();3654 syscall = try .start();
...@@ -3668,10 +3668,10 @@ fn dirCreateFileWindows(...@@ -3668,10 +3668,10 @@ fn dirCreateFileWindows(
3668 .NOT_A_DIRECTORY => return syscall.fail(error.NotDir),3668 .NOT_A_DIRECTORY => return syscall.fail(error.NotDir),
3669 .USER_MAPPED_FILE => return syscall.fail(error.AccessDenied),3669 .USER_MAPPED_FILE => return syscall.fail(error.AccessDenied),
3670 .VIRUS_INFECTED, .VIRUS_DELETED => return syscall.fail(error.AntivirusInterference),3670 .VIRUS_INFECTED, .VIRUS_DELETED => return syscall.fail(error.AntivirusInterference),
3671 .INVALID_PARAMETER => |err| return syscall.ntstatusBug(err),3671 .INVALID_PARAMETER => |status| return syscall.ntstatusBug(status),
3672 .OBJECT_PATH_SYNTAX_BAD => |err| return syscall.ntstatusBug(err),3672 .OBJECT_PATH_SYNTAX_BAD => |status| return syscall.ntstatusBug(status),
3673 .INVALID_HANDLE => |err| return syscall.ntstatusBug(err),3673 .INVALID_HANDLE => |status| return syscall.ntstatusBug(status),
3674 else => |err| return syscall.unexpectedNtstatus(err),3674 else => |status| return syscall.unexpectedNtstatus(status),
3675 };3675 };
3676 errdefer windows.CloseHandle(handle);3676 errdefer windows.CloseHandle(handle);
36773677
...@@ -3819,7 +3819,6 @@ fn dirCreateFileAtomic(...@@ -3819,7 +3819,6 @@ fn dirCreateFileAtomic(
3819 error.DiskQuota,3819 error.DiskQuota,
3820 error.PathAlreadyExists,3820 error.PathAlreadyExists,
3821 error.LinkQuotaExceeded,3821 error.LinkQuotaExceeded,
3822 error.SharingViolation,
3823 error.PipeBusy,3822 error.PipeBusy,
3824 error.FileTooBig,3823 error.FileTooBig,
3825 error.DeviceBusy,3824 error.DeviceBusy,
...@@ -3889,11 +3888,9 @@ fn dirCreateFileAtomic(...@@ -3889,11 +3888,9 @@ fn dirCreateFileAtomic(
3889 error.DiskQuota,3888 error.DiskQuota,
3890 error.PathAlreadyExists,3889 error.PathAlreadyExists,
3891 error.LinkQuotaExceeded,3890 error.LinkQuotaExceeded,
3892 error.SharingViolation,
3893 error.PipeBusy,3891 error.PipeBusy,
3894 error.FileTooBig,3892 error.FileTooBig,
3895 error.FileLocksUnsupported,3893 error.FileLocksUnsupported,
3896 error.FileBusy,
3897 error.DeviceBusy,3894 error.DeviceBusy,
3898 => return error.Unexpected,3895 => return error.Unexpected,
38993896
...@@ -3926,7 +3923,6 @@ fn atomicFileInit(...@@ -3926,7 +3923,6 @@ fn atomicFileInit(
3926 error.PathAlreadyExists => continue,3923 error.PathAlreadyExists => continue,
3927 error.DeviceBusy => continue,3924 error.DeviceBusy => continue,
3928 error.FileBusy => continue,3925 error.FileBusy => continue,
3929 error.SharingViolation => continue,
39303926
3931 error.IsDir => return error.Unexpected, // No path components.3927 error.IsDir => return error.Unexpected, // No path components.
3932 error.FileTooBig => return error.Unexpected, // Creating, not opening.3928 error.FileTooBig => return error.Unexpected, // Creating, not opening.
...@@ -4236,7 +4232,7 @@ pub fn dirOpenFileWtf16(...@@ -4236,7 +4232,7 @@ pub fn dirOpenFileWtf16(
4236 // after an executable file is closed. Here we work around the4232 // after an executable file is closed. Here we work around the
4237 // kernel bug with retry attempts.4233 // kernel bug with retry attempts.
4238 syscall.finish();4234 syscall.finish();
4239 if (max_attempts - attempt == 0) return error.SharingViolation;4235 if (max_attempts - attempt == 0) return error.FileBusy;
4240 try parking_sleep.windowsRetrySleep((@as(u32, 1) << attempt) >> 1);4236 try parking_sleep.windowsRetrySleep((@as(u32, 1) << attempt) >> 1);
4241 attempt += 1;4237 attempt += 1;
4242 syscall = try .start();4238 syscall = try .start();
...@@ -4258,7 +4254,7 @@ pub fn dirOpenFileWtf16(...@@ -4258,7 +4254,7 @@ pub fn dirOpenFileWtf16(
4258 // call has failed. Here, we simulate the kernel bug being4254 // call has failed. Here, we simulate the kernel bug being
4259 // fixed by sleeping and retrying until the error goes away.4255 // fixed by sleeping and retrying until the error goes away.
4260 syscall.finish();4256 syscall.finish();
4261 if (max_attempts - attempt == 0) return error.SharingViolation;4257 if (max_attempts - attempt == 0) return error.FileBusy;
4262 try parking_sleep.windowsRetrySleep((@as(u32, 1) << attempt) >> 1);4258 try parking_sleep.windowsRetrySleep((@as(u32, 1) << attempt) >> 1);
4263 attempt += 1;4259 attempt += 1;
4264 syscall = try .start();4260 syscall = try .start();
...@@ -6353,8 +6349,7 @@ fn dirSymLinkWindows(...@@ -6353,8 +6349,7 @@ fn dirSymLinkWindows(
63536349
6354 // Target path does not use sliceToPrefixedFileW because certain paths6350 // Target path does not use sliceToPrefixedFileW because certain paths
6355 // are handled differently when creating a symlink than they would be6351 // are handled differently when creating a symlink than they would be
6356 // when converting to an NT namespaced path. CreateSymbolicLink in6352 // when converting to an NT namespaced path.
6357 // symLinkW will handle the necessary conversion.
6358 var target_path_w: w.PathSpace = undefined;6353 var target_path_w: w.PathSpace = undefined;
6359 target_path_w.len = try w.wtf8ToWtf16Le(&target_path_w.data, target_path);6354 target_path_w.len = try w.wtf8ToWtf16Le(&target_path_w.data, target_path);
6360 target_path_w.data[target_path_w.len] = 0;6355 target_path_w.data[target_path_w.len] = 0;
...@@ -6465,7 +6460,7 @@ fn dirSymLinkWindows(...@@ -6465,7 +6460,7 @@ fn dirSymLinkWindows(
6465 @memcpy(buffer[@sizeOf(SYMLINK_DATA)..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path)));6460 @memcpy(buffer[@sizeOf(SYMLINK_DATA)..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path)));
6466 const paths_start = @sizeOf(SYMLINK_DATA) + final_target_path.len * 2;6461 const paths_start = @sizeOf(SYMLINK_DATA) + final_target_path.len * 2;
6467 @memcpy(buffer[paths_start..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path)));6462 @memcpy(buffer[paths_start..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path)));
6468 const rc = w.DeviceIoControl(symlink_handle, w.FSCTL.SET_REPARSE_POINT, .{ .in = buffer[0..buf_len] });6463 const rc = w.DeviceIoControl(symlink_handle, .SET_REPARSE_POINT, .{ .in = buffer[0..buf_len] });
6469 switch (rc) {6464 switch (rc) {
6470 .SUCCESS => {},6465 .SUCCESS => {},
6471 .PRIVILEGE_NOT_HELD => return error.PermissionDenied,6466 .PRIVILEGE_NOT_HELD => return error.PermissionDenied,
...@@ -6572,44 +6567,189 @@ fn dirSymLinkPosix(...@@ -6572,44 +6567,189 @@ fn dirSymLinkPosix(
6572 }6567 }
6573}6568}
65746569
6575const dirReadLink = switch (native_os) {6570fn dirReadLink(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLinkError!usize {
6576 .windows => dirReadLinkWindows,
6577 .wasi => dirReadLinkWasi,
6578 else => dirReadLinkPosix,
6579};
6580
6581fn dirReadLinkWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLinkError!usize {
6582 const t: *Threaded = @ptrCast(@alignCast(userdata));6571 const t: *Threaded = @ptrCast(@alignCast(userdata));
6583 _ = t;6572 _ = t;
6584 const w = windows;6573 switch (native_os) {
6574 .windows => return dirReadLinkWindows(dir, sub_path, buffer),
6575 .wasi => return dirReadLinkWasi(dir, sub_path, buffer),
6576 else => return dirReadLinkPosix(dir, sub_path, buffer),
6577 }
6578}
65856579
6580fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLinkError!usize {
6581 // This gets used once for `sub_path` and then reused again temporarily
6582 // before converting back to `buffer`.
6586 var sub_path_w_buf = try windows.sliceToPrefixedFileW(dir.handle, sub_path);6583 var sub_path_w_buf = try windows.sliceToPrefixedFileW(dir.handle, sub_path);
6584 const sub_path_w = sub_path_w_buf.span();
6585 const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;
6586 var nt_name: windows.UNICODE_STRING = .{
6587 .Length = path_len_bytes,
6588 .MaximumLength = path_len_bytes,
6589 .Buffer = @constCast(sub_path_w.ptr),
6590 };
6591 const attr: windows.OBJECT_ATTRIBUTES = .{
6592 .Length = @sizeOf(windows.OBJECT_ATTRIBUTES),
6593 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle,
6594 .Attributes = .{
6595 .INHERIT = false,
6596 },
6597 .ObjectName = &nt_name,
6598 .SecurityDescriptor = null,
6599 .SecurityQualityOfService = null,
6600 };
6601 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
6602 var result_handle: windows.HANDLE = undefined;
65876603
6588 const syscall: Syscall = try .start();6604 // There are multiple kernel bugs being worked around with retries.
6589 const result_w = while (true) {6605 const max_attempts = 13;
6590 if (w.ReadLink(dir.handle, sub_path_w_buf.span(), &sub_path_w_buf.data)) |res| {6606 var attempt: u5 = 0;
6607
6608 var syscall: Syscall = try .start();
6609 while (true) switch (windows.ntdll.NtCreateFile(
6610 &result_handle,
6611 .{
6612 .SPECIFIC = .{ .FILE = .{
6613 .READ_ATTRIBUTES = true,
6614 } },
6615 .STANDARD = .{ .SYNCHRONIZE = true },
6616 },
6617 &attr,
6618 &io_status_block,
6619 null,
6620 .{ .NORMAL = true },
6621 .VALID_FLAGS,
6622 .OPEN,
6623 .{
6624 .DIRECTORY_FILE = false,
6625 .NON_DIRECTORY_FILE = false,
6626 .IO = .ASYNCHRONOUS,
6627 .OPEN_REPARSE_POINT = true,
6628 },
6629 null,
6630 0,
6631 )) {
6632 .SUCCESS => {
6591 syscall.finish();6633 syscall.finish();
6592 break res;6634 break;
6593 } else |err| switch (err) {6635 },
6594 error.OperationCanceled => {6636 .CANCELLED => {
6595 try syscall.checkCancel();6637 try syscall.checkCancel();
6596 continue;6638 continue;
6597 },6639 },
6598 else => |e| return syscall.fail(e),6640 .SHARING_VIOLATION => {
6599 }6641 // This occurs if the file attempting to be opened is a running
6642 // executable. However, there's a kernel bug: the error may be
6643 // incorrectly returned for an indeterminate amount of time
6644 // after an executable file is closed. Here we work around the
6645 // kernel bug with retry attempts.
6646 syscall.finish();
6647 if (max_attempts - attempt == 0) return error.FileBusy;
6648 try parking_sleep.windowsRetrySleep((@as(u32, 1) << attempt) >> 1);
6649 attempt += 1;
6650 syscall = try .start();
6651 continue;
6652 },
6653 .DELETE_PENDING => {
6654 // This error means that there *was* a file in this location on
6655 // the file system, but it was deleted. However, the OS is not
6656 // finished with the deletion operation, and so this CreateFile
6657 // call has failed. Here, we simulate the kernel bug being
6658 // fixed by sleeping and retrying until the error goes away.
6659 syscall.finish();
6660 if (max_attempts - attempt == 0) return error.FileBusy;
6661 try parking_sleep.windowsRetrySleep((@as(u32, 1) << attempt) >> 1);
6662 attempt += 1;
6663 syscall = try .start();
6664 continue;
6665 },
6666 .OBJECT_NAME_INVALID => return syscall.fail(error.BadPathName),
6667 .OBJECT_NAME_NOT_FOUND => return syscall.fail(error.FileNotFound),
6668 .OBJECT_PATH_NOT_FOUND => return syscall.fail(error.FileNotFound),
6669 .BAD_NETWORK_PATH => return syscall.fail(error.NetworkNotFound), // \\server was not found
6670 .BAD_NETWORK_NAME => return syscall.fail(error.NetworkNotFound), // \\server was found but \\server\share wasn't
6671 .NO_MEDIA_IN_DEVICE => return syscall.fail(error.FileNotFound),
6672 .ACCESS_DENIED => return syscall.fail(error.AccessDenied),
6673 .PIPE_BUSY => return syscall.fail(error.AccessDenied),
6674 .PIPE_NOT_AVAILABLE => return syscall.fail(error.FileNotFound),
6675 .USER_MAPPED_FILE => return syscall.fail(error.AccessDenied),
6676 .VIRUS_INFECTED, .VIRUS_DELETED => return syscall.fail(error.AntivirusInterference),
6677 .INVALID_PARAMETER => |status| return syscall.ntstatusBug(status),
6678 .OBJECT_PATH_SYNTAX_BAD => |status| return syscall.ntstatusBug(status),
6679 .INVALID_HANDLE => |status| return syscall.ntstatusBug(status),
6680 else => |status| return syscall.unexpectedNtstatus(status),
6600 };6681 };
6682 defer windows.CloseHandle(result_handle);
6683
6684 var reparse_buf: [windows.MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 align(@alignOf(windows.REPARSE_DATA_BUFFER)) = undefined;
66016685
6686 syscall = try .start();
6687 while (true) switch (windows.ntdll.NtFsControlFile(
6688 result_handle,
6689 null, // event
6690 null, // APC routine
6691 null, // APC context
6692 &io_status_block,
6693 .GET_REPARSE_POINT,
6694 null, // input buffer
6695 0, // input buffer length
6696 &reparse_buf,
6697 reparse_buf.len,
6698 )) {
6699 .SUCCESS => {
6700 syscall.finish();
6701 break;
6702 },
6703 .CANCELLED => {
6704 try syscall.checkCancel();
6705 continue;
6706 },
6707 .NOT_A_REPARSE_POINT => return syscall.fail(error.NotLink),
6708 else => |status| return syscall.unexpectedNtstatus(status),
6709 };
6710
6711 const reparse_struct: *const windows.REPARSE_DATA_BUFFER = @ptrCast(@alignCast(&reparse_buf));
6712 const IoReparseTagInt = @typeInfo(windows.IO_REPARSE_TAG).@"struct".backing_integer.?;
6713 const result_w = switch (@as(IoReparseTagInt, @bitCast(reparse_struct.ReparseTag))) {
6714 @as(IoReparseTagInt, @bitCast(windows.IO_REPARSE_TAG.SYMLINK)) => r: {
6715 const buf: *const windows.SYMBOLIC_LINK_REPARSE_BUFFER = @ptrCast(@alignCast(&reparse_struct.DataBuffer[0]));
6716 const offset = buf.SubstituteNameOffset >> 1;
6717 const len = buf.SubstituteNameLength >> 1;
6718 const path_buf = @as([*]const u16, &buf.PathBuffer);
6719 const is_relative = buf.Flags & windows.SYMLINK_FLAG_RELATIVE != 0;
6720 break :r try parseReadLinkPath(path_buf[offset..][0..len], is_relative, &sub_path_w_buf.data);
6721 },
6722 @as(IoReparseTagInt, @bitCast(windows.IO_REPARSE_TAG.MOUNT_POINT)) => r: {
6723 const buf: *const windows.MOUNT_POINT_REPARSE_BUFFER = @ptrCast(@alignCast(&reparse_struct.DataBuffer[0]));
6724 const offset = buf.SubstituteNameOffset >> 1;
6725 const len = buf.SubstituteNameLength >> 1;
6726 const path_buf = @as([*]const u16, &buf.PathBuffer);
6727 break :r try parseReadLinkPath(path_buf[offset..][0..len], false, &sub_path_w_buf.data);
6728 },
6729 else => return error.UnsupportedReparsePointType,
6730 };
6602 const len = std.unicode.calcWtf8Len(result_w);6731 const len = std.unicode.calcWtf8Len(result_w);
6603 if (len > buffer.len) return error.NameTooLong;6732 if (len > buffer.len) return error.NameTooLong;
66046733
6605 return std.unicode.wtf16LeToWtf8(buffer, result_w);6734 return std.unicode.wtf16LeToWtf8(buffer, result_w);
6606}6735}
66076736
6608fn dirReadLinkWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLinkError!usize {6737fn parseReadLinkPath(path: []const u16, is_relative: bool, out_buffer: []u16) error{NameTooLong}![]u16 {
6609 if (builtin.link_libc) return dirReadLinkPosix(userdata, dir, sub_path, buffer);6738 path: {
6739 if (is_relative) break :path;
6740 return windows.ntToWin32Namespace(path, out_buffer) catch |err| switch (err) {
6741 error.NameTooLong => |e| return e,
6742 error.NotNtPath => break :path,
6743 };
6744 }
6745 if (out_buffer.len < path.len) return error.NameTooLong;
6746 const dest = out_buffer[0..path.len];
6747 @memcpy(dest, path);
6748 return dest;
6749}
66106750
6611 const t: *Threaded = @ptrCast(@alignCast(userdata));6751fn dirReadLinkWasi(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLinkError!usize {
6612 _ = t;6752 if (builtin.link_libc) return dirReadLinkPosix(dir, sub_path, buffer);
66136753
6614 var n: usize = undefined;6754 var n: usize = undefined;
6615 const syscall: Syscall = try .start();6755 const syscall: Syscall = try .start();
...@@ -6644,10 +6784,7 @@ fn dirReadLinkWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buffer...@@ -6644,10 +6784,7 @@ fn dirReadLinkWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buffer
6644 }6784 }
6645}6785}
66466786
6647fn dirReadLinkPosix(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLinkError!usize {6787fn dirReadLinkPosix(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLinkError!usize {
6648 const t: *Threaded = @ptrCast(@alignCast(userdata));
6649 _ = t;
6650
6651 var sub_path_buffer: [posix.PATH_MAX]u8 = undefined;6788 var sub_path_buffer: [posix.PATH_MAX]u8 = undefined;
6652 const sub_path_posix = try pathToPosix(sub_path, &sub_path_buffer);6789 const sub_path_posix = try pathToPosix(sub_path, &sub_path_buffer);
66536790
...@@ -8709,45 +8846,41 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) process.Execut...@@ -8709,45 +8846,41 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) process.Execut
8709 const symlink_path = std.mem.sliceTo(&symlink_path_buf, 0);8846 const symlink_path = std.mem.sliceTo(&symlink_path_buf, 0);
8710 return Io.Dir.realPathFileAbsolute(ioBasic(t), symlink_path, out_buffer) catch |err| switch (err) {8847 return Io.Dir.realPathFileAbsolute(ioBasic(t), symlink_path, out_buffer) catch |err| switch (err) {
8711 error.NetworkNotFound => unreachable, // Windows-only8848 error.NetworkNotFound => unreachable, // Windows-only
8849 error.FileBusy => unreachable, // Windows-only
8712 else => |e| return e,8850 else => |e| return e,
8713 };8851 };
8714 },8852 },
8715 .linux, .serenity => return Io.Dir.readLinkAbsolute(ioBasic(t), "/proc/self/exe", out_buffer) catch |err| switch (err) {8853 .linux, .serenity => return Io.Dir.readLinkAbsolute(ioBasic(t), "/proc/self/exe", out_buffer) catch |err| switch (err) {
8716 error.UnsupportedReparsePointType => unreachable, // Windows-only8854 error.UnsupportedReparsePointType => unreachable, // Windows-only
8717 error.NetworkNotFound => unreachable, // Windows-only8855 error.NetworkNotFound => unreachable, // Windows-only
8856 error.FileBusy => unreachable, // Windows-only
8718 else => |e| return e,8857 else => |e| return e,
8719 },8858 },
8720 .illumos => return Io.Dir.readLinkAbsolute(ioBasic(t), "/proc/self/path/a.out", out_buffer) catch |err| switch (err) {8859 .illumos => return Io.Dir.readLinkAbsolute(ioBasic(t), "/proc/self/path/a.out", out_buffer) catch |err| switch (err) {
8721 error.UnsupportedReparsePointType => unreachable, // Windows-only8860 error.UnsupportedReparsePointType => unreachable, // Windows-only
8722 error.NetworkNotFound => unreachable, // Windows-only8861 error.NetworkNotFound => unreachable, // Windows-only
8862 error.FileBusy => unreachable, // Windows-only
8723 else => |e| return e,8863 else => |e| return e,
8724 },8864 },
8725 .freebsd, .dragonfly => {8865 .freebsd, .dragonfly => {
8726 var mib: [4]c_int = .{ posix.CTL.KERN, posix.KERN.PROC, posix.KERN.PROC_PATHNAME, -1 };8866 var mib: [4]c_int = .{ posix.CTL.KERN, posix.KERN.PROC, posix.KERN.PROC_PATHNAME, -1 };
8727 var out_len: usize = out_buffer.len;8867 var out_len: usize = out_buffer.len;
8728 const syscall: Syscall = try .start();8868 const syscall: Syscall = try .start();
8729 while (true) {8869 while (true) switch (posix.errno(posix.system.sysctl(&mib, mib.len, out_buffer.ptr, &out_len, null, 0))) {
8730 switch (posix.errno(posix.system.sysctl(&mib, mib.len, out_buffer.ptr, &out_len, null, 0))) {8870 .SUCCESS => {
8731 .SUCCESS => {8871 syscall.finish();
8732 syscall.finish();8872 return out_len - 1; // discard terminating NUL
8733 return out_len - 1; // discard terminating NUL8873 },
8734 },8874 .INTR => {
8735 .INTR => {8875 try syscall.checkCancel();
8736 try syscall.checkCancel();8876 continue;
8737 continue;8877 },
8738 },8878 .PERM => return syscall.fail(error.PermissionDenied),
8739 else => |e| {8879 .NOMEM => return syscall.fail(error.SystemResources),
8740 syscall.finish();8880 .FAULT => |err| return syscall.errnoBug(err),
8741 switch (e) {8881 .NOENT => |err| return syscall.errnoBug(err),
8742 .FAULT => |err| return errnoBug(err),8882 else => |err| return syscall.unexpectedErrno(err),
8743 .PERM => return error.PermissionDenied,8883 };
8744 .NOMEM => return error.SystemResources,
8745 .NOENT => |err| return errnoBug(err),
8746 else => |err| return posix.unexpectedErrno(err),
8747 }
8748 },
8749 }
8750 }
8751 },8884 },
8752 .netbsd => {8885 .netbsd => {
8753 var mib = [4]c_int{ posix.CTL.KERN, posix.KERN.PROC_ARGS, -1, posix.KERN.PROC_PATHNAME };8886 var mib = [4]c_int{ posix.CTL.KERN, posix.KERN.PROC_ARGS, -1, posix.KERN.PROC_PATHNAME };
...@@ -8763,16 +8896,11 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) process.Execut...@@ -8763,16 +8896,11 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) process.Execut
8763 try syscall.checkCancel();8896 try syscall.checkCancel();
8764 continue;8897 continue;
8765 },8898 },
8766 else => |e| {8899 .PERM => return syscall.fail(error.PermissionDenied),
8767 syscall.finish();8900 .NOMEM => return syscall.fail(error.SystemResources),
8768 switch (e) {8901 .FAULT => |err| return syscall.errnoBug(err),
8769 .FAULT => |err| return errnoBug(err),8902 .NOENT => |err| return syscall.errnoBug(err),
8770 .PERM => return error.PermissionDenied,8903 else => |err| return syscall.unexpectedErrno(err),
8771 .NOMEM => return error.SystemResources,
8772 .NOENT => |err| return errnoBug(err),
8773 else => |err| return posix.unexpectedErrno(err),
8774 }
8775 },
8776 }8904 }
8777 }8905 }
8778 },8906 },
lib/std/debug/SelfInfo/Windows.zig-1
...@@ -335,7 +335,6 @@ const Module = struct {...@@ -335,7 +335,6 @@ const Module = struct {
335 error.NoSpaceLeft,335 error.NoSpaceLeft,
336 error.DeviceBusy,336 error.DeviceBusy,
337 error.NoDevice,337 error.NoDevice,
338 error.SharingViolation,
339 error.PathAlreadyExists,338 error.PathAlreadyExists,
340 error.PipeBusy,339 error.PipeBusy,
341 error.NetworkNotFound,340 error.NetworkNotFound,
lib/std/os/windows.zig+10-211
...@@ -1135,19 +1135,7 @@ pub const CTL_CODE = packed struct(ULONG) {...@@ -1135,19 +1135,7 @@ pub const CTL_CODE = packed struct(ULONG) {
11351135
1136 _,1136 _,
1137 };1137 };
1138};
1139
1140pub const IOCTL = struct {
1141 pub const KSEC = struct {
1142 pub const GEN_RANDOM: CTL_CODE = .{ .DeviceType = .KSEC, .Function = 2, .Method = .BUFFERED, .Access = .ANY };
1143 };
1144 pub const MOUNTMGR = struct {
1145 pub const QUERY_POINTS: CTL_CODE = .{ .DeviceType = .MOUNTMGRCONTROLTYPE, .Function = 2, .Method = .BUFFERED, .Access = .ANY };
1146 pub const QUERY_DOS_VOLUME_PATH: CTL_CODE = .{ .DeviceType = .MOUNTMGRCONTROLTYPE, .Function = 12, .Method = .BUFFERED, .Access = .ANY };
1147 };
1148};
11491138
1150pub const FSCTL = struct {
1151 pub const SET_REPARSE_POINT: CTL_CODE = .{ .DeviceType = .FILE_SYSTEM, .Function = 41, .Method = .BUFFERED, .Access = .SPECIAL };1139 pub const SET_REPARSE_POINT: CTL_CODE = .{ .DeviceType = .FILE_SYSTEM, .Function = 41, .Method = .BUFFERED, .Access = .SPECIAL };
1152 pub const GET_REPARSE_POINT: CTL_CODE = .{ .DeviceType = .FILE_SYSTEM, .Function = 42, .Method = .BUFFERED, .Access = .ANY };1140 pub const GET_REPARSE_POINT: CTL_CODE = .{ .DeviceType = .FILE_SYSTEM, .Function = 42, .Method = .BUFFERED, .Access = .ANY };
11531141
...@@ -1177,6 +1165,16 @@ pub const FSCTL = struct {...@@ -1177,6 +1165,16 @@ pub const FSCTL = struct {
1177 };1165 };
1178};1166};
11791167
1168pub const IOCTL = struct {
1169 pub const KSEC = struct {
1170 pub const GEN_RANDOM: CTL_CODE = .{ .DeviceType = .KSEC, .Function = 2, .Method = .BUFFERED, .Access = .ANY };
1171 };
1172 pub const MOUNTMGR = struct {
1173 pub const QUERY_POINTS: CTL_CODE = .{ .DeviceType = .MOUNTMGRCONTROLTYPE, .Function = 2, .Method = .BUFFERED, .Access = .ANY };
1174 pub const QUERY_DOS_VOLUME_PATH: CTL_CODE = .{ .DeviceType = .MOUNTMGRCONTROLTYPE, .Function = 12, .Method = .BUFFERED, .Access = .ANY };
1175 };
1176};
1177
1180pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: ULONG = 16 * 1024;1178pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: ULONG = 16 * 1024;
11811179
1182pub const IO_REPARSE_TAG = packed struct(ULONG) {1180pub const IO_REPARSE_TAG = packed struct(ULONG) {
...@@ -2908,205 +2906,6 @@ pub fn GetCurrentDirectory(buffer: []u8) GetCurrentDirectoryError![]u8 {...@@ -2908,205 +2906,6 @@ pub fn GetCurrentDirectory(buffer: []u8) GetCurrentDirectoryError![]u8 {
2908 return buffer[0..end_index];2906 return buffer[0..end_index];
2909}2907}
29102908
2911pub const CreateSymbolicLinkError = error{
2912 AccessDenied,
2913 PathAlreadyExists,
2914 FileNotFound,
2915 NameTooLong,
2916 NoDevice,
2917 NetworkNotFound,
2918 BadPathName,
2919 Unexpected,
2920};
2921
2922/// Needs either:
2923/// - `SeCreateSymbolicLinkPrivilege` privilege
2924/// or
2925/// - Developer mode on Windows 10
2926/// otherwise fails with `error.AccessDenied`. In which case `sym_link_path` may still
2927/// be created on the file system but will lack reparse processing data applied to it.
2928pub fn CreateSymbolicLink(
2929 dir: ?HANDLE,
2930 sym_link_path: []const u16,
2931 target_path: [:0]const u16,
2932 is_directory: bool,
2933) CreateSymbolicLinkError!void {
2934 const SYMLINK_DATA = extern struct {
2935 ReparseTag: IO_REPARSE_TAG,
2936 ReparseDataLength: USHORT,
2937 Reserved: USHORT,
2938 SubstituteNameOffset: USHORT,
2939 SubstituteNameLength: USHORT,
2940 PrintNameOffset: USHORT,
2941 PrintNameLength: USHORT,
2942 Flags: ULONG,
2943 };
2944
2945 const symlink_handle = OpenFile(sym_link_path, .{
2946 .access_mask = .{
2947 .STANDARD = .{ .SYNCHRONIZE = true },
2948 .GENERIC = .{ .WRITE = true, .READ = true },
2949 },
2950 .dir = dir,
2951 .creation = .CREATE,
2952 .filter = if (is_directory) .dir_only else .non_directory_only,
2953 }) catch |err| switch (err) {
2954 error.IsDir => return error.PathAlreadyExists,
2955 error.NotDir => return error.Unexpected,
2956 error.WouldBlock => return error.Unexpected,
2957 error.PipeBusy => return error.Unexpected,
2958 error.NoDevice => return error.Unexpected,
2959 error.AntivirusInterference => return error.Unexpected,
2960 else => |e| return e,
2961 };
2962 defer CloseHandle(symlink_handle);
2963
2964 // Relevant portions of the documentation:
2965 // > Relative links are specified using the following conventions:
2966 // > - Root relative—for example, "\Windows\System32" resolves to "current drive:\Windows\System32".
2967 // > - Current working directory–relative—for example, if the current working directory is
2968 // > C:\Windows\System32, "C:File.txt" resolves to "C:\Windows\System32\File.txt".
2969 // > Note: If you specify a current working directory–relative link, it is created as an absolute
2970 // > link, due to the way the current working directory is processed based on the user and the thread.
2971 // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
2972 var is_target_absolute = false;
2973 const final_target_path = target_path: {
2974 if (hasCommonNtPrefix(u16, target_path)) {
2975 // Already an NT path, no need to do anything to it
2976 break :target_path target_path;
2977 } else {
2978 switch (std.fs.path.getWin32PathType(u16, target_path)) {
2979 // Rooted paths need to avoid getting put through wToPrefixedFileW
2980 // (and they are treated as relative in this context)
2981 // Note: It seems that rooted paths in symbolic links are relative to
2982 // the drive that the symbolic exists on, not to the CWD's drive.
2983 // So, if the symlink is on C:\ and the CWD is on D:\,
2984 // it will still resolve the path relative to the root of
2985 // the C:\ drive.
2986 .rooted => break :target_path target_path,
2987 // Keep relative paths relative, but anything else needs to get NT-prefixed.
2988 else => if (!std.fs.path.isAbsoluteWindowsWtf16(target_path))
2989 break :target_path target_path,
2990 }
2991 }
2992 var prefixed_target_path = try wToPrefixedFileW(dir, target_path);
2993 // We do this after prefixing to ensure that drive-relative paths are treated as absolute
2994 is_target_absolute = std.fs.path.isAbsoluteWindowsWtf16(prefixed_target_path.span());
2995 break :target_path prefixed_target_path.span();
2996 };
2997
2998 // prepare reparse data buffer
2999 var buffer: [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 = undefined;
3000 const buf_len = @sizeOf(SYMLINK_DATA) + final_target_path.len * 4;
3001 const header_len = @sizeOf(ULONG) + @sizeOf(USHORT) * 2;
3002 const target_is_absolute = std.fs.path.isAbsoluteWindowsWtf16(final_target_path);
3003 const symlink_data: SYMLINK_DATA = .{
3004 .ReparseTag = .SYMLINK,
3005 .ReparseDataLength = @intCast(buf_len - header_len),
3006 .Reserved = 0,
3007 .SubstituteNameOffset = @intCast(final_target_path.len * 2),
3008 .SubstituteNameLength = @intCast(final_target_path.len * 2),
3009 .PrintNameOffset = 0,
3010 .PrintNameLength = @intCast(final_target_path.len * 2),
3011 .Flags = if (!target_is_absolute) SYMLINK_FLAG_RELATIVE else 0,
3012 };
3013
3014 @memcpy(buffer[0..@sizeOf(SYMLINK_DATA)], std.mem.asBytes(&symlink_data));
3015 @memcpy(buffer[@sizeOf(SYMLINK_DATA)..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path)));
3016 const paths_start = @sizeOf(SYMLINK_DATA) + final_target_path.len * 2;
3017 @memcpy(buffer[paths_start..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path)));
3018 const rc = DeviceIoControl(symlink_handle, FSCTL.SET_REPARSE_POINT, .{ .in = buffer[0..buf_len] });
3019 switch (rc) {
3020 .SUCCESS => {},
3021 .PRIVILEGE_NOT_HELD => return error.AccessDenied,
3022 .ACCESS_DENIED => return error.AccessDenied,
3023 .INVALID_DEVICE_REQUEST => return error.AccessDenied, // Not supported by the underlying filesystem
3024 else => return unexpectedStatus(rc),
3025 }
3026}
3027
3028pub const ReadLinkError = error{
3029 FileNotFound,
3030 NetworkNotFound,
3031 AccessDenied,
3032 Unexpected,
3033 NameTooLong,
3034 BadPathName,
3035 AntivirusInterference,
3036 UnsupportedReparsePointType,
3037 NotLink,
3038 OperationCanceled,
3039};
3040
3041/// `sub_path_w` will never be accessed after `out_buffer` has been written to, so it
3042/// is safe to reuse a single buffer for both.
3043pub fn ReadLink(dir: ?HANDLE, sub_path_w: []const u16, out_buffer: []u16) ReadLinkError![]u16 {
3044 const result_handle = OpenFile(sub_path_w, .{
3045 .access_mask = .{
3046 .SPECIFIC = .{ .FILE = .{
3047 .READ_ATTRIBUTES = true,
3048 } },
3049 .STANDARD = .{ .SYNCHRONIZE = true },
3050 },
3051 .dir = dir,
3052 .creation = .OPEN,
3053 .follow_symlinks = false,
3054 .filter = .any,
3055 }) catch |err| switch (err) {
3056 error.IsDir, error.NotDir => return error.Unexpected, // filter = .any
3057 error.PathAlreadyExists => return error.Unexpected, // FILE_OPEN
3058 error.WouldBlock => return error.Unexpected,
3059 error.NoDevice => return error.FileNotFound,
3060 error.PipeBusy => return error.AccessDenied,
3061 else => |e| return e,
3062 };
3063 defer CloseHandle(result_handle);
3064
3065 var reparse_buf: [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 align(@alignOf(REPARSE_DATA_BUFFER)) = undefined;
3066 const rc = DeviceIoControl(result_handle, FSCTL.GET_REPARSE_POINT, .{ .out = reparse_buf[0..] });
3067 switch (rc) {
3068 .SUCCESS => {},
3069 .CANCELLED => return error.OperationCanceled,
3070 .NOT_A_REPARSE_POINT => return error.NotLink,
3071 else => return unexpectedStatus(rc),
3072 }
3073
3074 const reparse_struct: *const REPARSE_DATA_BUFFER = @ptrCast(@alignCast(&reparse_buf[0]));
3075 const IoReparseTagInt = @typeInfo(IO_REPARSE_TAG).@"struct".backing_integer.?;
3076 switch (@as(IoReparseTagInt, @bitCast(reparse_struct.ReparseTag))) {
3077 @as(IoReparseTagInt, @bitCast(IO_REPARSE_TAG.SYMLINK)) => {
3078 const buf: *const SYMBOLIC_LINK_REPARSE_BUFFER = @ptrCast(@alignCast(&reparse_struct.DataBuffer[0]));
3079 const offset = buf.SubstituteNameOffset >> 1;
3080 const len = buf.SubstituteNameLength >> 1;
3081 const path_buf = @as([*]const u16, &buf.PathBuffer);
3082 const is_relative = buf.Flags & SYMLINK_FLAG_RELATIVE != 0;
3083 return parseReadLinkPath(path_buf[offset..][0..len], is_relative, out_buffer);
3084 },
3085 @as(IoReparseTagInt, @bitCast(IO_REPARSE_TAG.MOUNT_POINT)) => {
3086 const buf: *const MOUNT_POINT_REPARSE_BUFFER = @ptrCast(@alignCast(&reparse_struct.DataBuffer[0]));
3087 const offset = buf.SubstituteNameOffset >> 1;
3088 const len = buf.SubstituteNameLength >> 1;
3089 const path_buf = @as([*]const u16, &buf.PathBuffer);
3090 return parseReadLinkPath(path_buf[offset..][0..len], false, out_buffer);
3091 },
3092 else => return error.UnsupportedReparsePointType,
3093 }
3094}
3095
3096fn parseReadLinkPath(path: []const u16, is_relative: bool, out_buffer: []u16) error{NameTooLong}![]u16 {
3097 path: {
3098 if (is_relative) break :path;
3099 return ntToWin32Namespace(path, out_buffer) catch |err| switch (err) {
3100 error.NameTooLong => |e| return e,
3101 error.NotNtPath => break :path,
3102 };
3103 }
3104 if (out_buffer.len < path.len) return error.NameTooLong;
3105 const dest = out_buffer[0..path.len];
3106 @memcpy(dest, path);
3107 return dest;
3108}
3109
3110pub const DeleteFileError = error{2909pub const DeleteFileError = error{
3111 FileNotFound,2910 FileNotFound,
3112 AccessDenied,2911 AccessDenied,
lib/std/process.zig-1
...@@ -704,7 +704,6 @@ pub const ExecutablePathBaseError = error{...@@ -704,7 +704,6 @@ pub const ExecutablePathBaseError = error{
704 FileSystem,704 FileSystem,
705 BadPathName,705 BadPathName,
706 DeviceBusy,706 DeviceBusy,
707 SharingViolation,
708 PipeBusy,707 PipeBusy,
709 NotLink,708 NotLink,
710 PathAlreadyExists,709 PathAlreadyExists,
lib/std/zig/system.zig+1-2
...@@ -723,6 +723,7 @@ fn abiAndDynamicLinkerFromFile(...@@ -723,6 +723,7 @@ fn abiAndDynamicLinkerFromFile(
723 error.UnsupportedReparsePointType => unreachable, // Windows only723 error.UnsupportedReparsePointType => unreachable, // Windows only
724 error.NetworkNotFound => unreachable, // Windows only724 error.NetworkNotFound => unreachable, // Windows only
725 error.AntivirusInterference => unreachable, // Windows only725 error.AntivirusInterference => unreachable, // Windows only
726 error.FileBusy => unreachable, // Windows only
726727
727 error.AccessDenied,728 error.AccessDenied,
728 error.PermissionDenied,729 error.PermissionDenied,
...@@ -844,7 +845,6 @@ fn glibcVerFromRPath(io: Io, rpath: []const u8) !std.SemanticVersion {...@@ -844,7 +845,6 @@ fn glibcVerFromRPath(io: Io, rpath: []const u8) !std.SemanticVersion {
844 error.NameTooLong => return error.Unexpected,845 error.NameTooLong => return error.Unexpected,
845 error.BadPathName => return error.Unexpected,846 error.BadPathName => return error.Unexpected,
846 error.PipeBusy => return error.Unexpected, // Windows-only847 error.PipeBusy => return error.Unexpected, // Windows-only
847 error.SharingViolation => return error.Unexpected, // Windows-only
848 error.NetworkNotFound => return error.Unexpected, // Windows-only848 error.NetworkNotFound => return error.Unexpected, // Windows-only
849 error.AntivirusInterference => return error.Unexpected, // Windows-only849 error.AntivirusInterference => return error.Unexpected, // Windows-only
850 error.FileLocksUnsupported => return error.Unexpected, // No lock requested.850 error.FileLocksUnsupported => return error.Unexpected, // No lock requested.
...@@ -1052,7 +1052,6 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ...@@ -1052,7 +1052,6 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ
1052 error.NoSpaceLeft => return error.Unexpected,1052 error.NoSpaceLeft => return error.Unexpected,
1053 error.NameTooLong => return error.Unexpected,1053 error.NameTooLong => return error.Unexpected,
1054 error.PathAlreadyExists => return error.Unexpected,1054 error.PathAlreadyExists => return error.Unexpected,
1055 error.SharingViolation => return error.Unexpected,
1056 error.BadPathName => return error.Unexpected,1055 error.BadPathName => return error.Unexpected,
1057 error.PipeBusy => return error.Unexpected,1056 error.PipeBusy => return error.Unexpected,
1058 error.FileLocksUnsupported => return error.Unexpected,1057 error.FileLocksUnsupported => return error.Unexpected,