authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2025-10-10 22:53:12-07:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2025-11-15 18:07:25-08:00
log06a7597ea8ac8d66f20f75580f8e0a6964e1861e
tree360e527c05902a0f8c5701b4ca9a042175b11ad9
parent813e8614bc2ecda414f308a1662be074e788e3f2

windows.ReadLink: Use OpenFile now that `.filter = .any` exists

The reasoning in the comment deleted by this commit no longer applies, since that same benefit can be obtained by using OpenFile with `.filter = .any`. Also removes a stray debug.print

3 files changed, 23 insertions(+), 52 deletions(-)

lib/std/os/windows.zig+16-52
......@@ -889,61 +889,26 @@ pub const ReadLinkError = error{
889889 AccessDenied,
890890 Unexpected,
891891 NameTooLong,
892 BadPathName,
893 AntivirusInterference,
892894 UnsupportedReparsePointType,
893895};
894896
895897pub fn ReadLink(dir: ?HANDLE, sub_path_w: []const u16, out_buffer: []u8) ReadLinkError![]u8 {
896 // Here, we use `NtCreateFile` to shave off one syscall if we were to use `OpenFile` wrapper.
897 // With the latter, we'd need to call `NtCreateFile` twice, once for file symlink, and if that
898 // failed, again for dir symlink. Omitting any mention of file/dir flags makes it possible
899 // to open the symlink there and then.
900 const path_len_bytes = math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;
901 var nt_name = UNICODE_STRING{
902 .Length = path_len_bytes,
903 .MaximumLength = path_len_bytes,
904 .Buffer = @constCast(sub_path_w.ptr),
905 };
906 var attr = OBJECT_ATTRIBUTES{
907 .Length = @sizeOf(OBJECT_ATTRIBUTES),
908 .RootDirectory = if (std.fs.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir,
909 .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
910 .ObjectName = &nt_name,
911 .SecurityDescriptor = null,
912 .SecurityQualityOfService = null,
898 const result_handle = OpenFile(sub_path_w, .{
899 .access_mask = FILE_READ_ATTRIBUTES | SYNCHRONIZE,
900 .dir = dir,
901 .creation = FILE_OPEN,
902 .follow_symlinks = false,
903 .filter = .any,
904 }) catch |err| switch (err) {
905 error.IsDir, error.NotDir => return error.Unexpected, // filter = .any
906 error.PathAlreadyExists => return error.Unexpected, // FILE_OPEN
907 error.WouldBlock => return error.Unexpected,
908 error.NoDevice => return error.FileNotFound,
909 error.PipeBusy => return error.AccessDenied,
910 else => |e| return e,
913911 };
914 var result_handle: HANDLE = undefined;
915 var io: IO_STATUS_BLOCK = undefined;
916
917 const rc = ntdll.NtCreateFile(
918 &result_handle,
919 FILE_READ_ATTRIBUTES | SYNCHRONIZE,
920 &attr,
921 &io,
922 null,
923 FILE_ATTRIBUTE_NORMAL,
924 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
925 FILE_OPEN,
926 FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT,
927 null,
928 0,
929 );
930 switch (rc) {
931 .SUCCESS => {},
932 .OBJECT_NAME_INVALID => unreachable,
933 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
934 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
935 .NO_MEDIA_IN_DEVICE => return error.FileNotFound,
936 .BAD_NETWORK_PATH => return error.NetworkNotFound, // \\server was not found
937 .BAD_NETWORK_NAME => return error.NetworkNotFound, // \\server was found but \\server\share wasn't
938 .INVALID_PARAMETER => unreachable,
939 .SHARING_VIOLATION => return error.AccessDenied,
940 .ACCESS_DENIED => return error.AccessDenied,
941 .PIPE_BUSY => return error.AccessDenied,
942 .OBJECT_PATH_SYNTAX_BAD => unreachable,
943 .OBJECT_NAME_COLLISION => unreachable,
944 .FILE_IS_A_DIRECTORY => unreachable,
945 else => return unexpectedStatus(rc),
946 }
947912 defer CloseHandle(result_handle);
948913
949914 var reparse_buf: [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 align(@alignOf(REPARSE_DATA_BUFFER)) = undefined;
......@@ -970,8 +935,7 @@ pub fn ReadLink(dir: ?HANDLE, sub_path_w: []const u16, out_buffer: []u8) ReadLin
970935 const path_buf = @as([*]const u16, &buf.PathBuffer);
971936 return parseReadlinkPath(path_buf[offset..][0..len], false, out_buffer);
972937 },
973 else => |value| {
974 std.debug.print("unsupported symlink type: {}", .{value});
938 else => {
975939 return error.UnsupportedReparsePointType;
976940 },
977941 }
lib/std/posix.zig+6
......@@ -3001,6 +3001,12 @@ pub const ReadLinkError = error{
30013001 UnsupportedReparsePointType,
30023002 /// On Windows, `\\server` or `\\server\share` was not found.
30033003 NetworkNotFound,
3004 /// On Windows, antivirus software is enabled by default. It can be
3005 /// disabled, but Windows Update sometimes ignores the user's preference
3006 /// and re-enables it. When enabled, antivirus software on Windows
3007 /// intercepts file system operations and makes them significantly slower
3008 /// in addition to possibly failing with this error code.
3009 AntivirusInterference,
30043010} || UnexpectedError;
30053011
30063012/// Read value of a symbolic link.
lib/std/zig/system.zig+1
......@@ -705,6 +705,7 @@ fn abiAndDynamicLinkerFromFile(
705705 error.BadPathName => unreachable, // Windows only
706706 error.UnsupportedReparsePointType => unreachable, // Windows only
707707 error.NetworkNotFound => unreachable, // Windows only
708 error.AntivirusInterference => unreachable, // Windows only
708709
709710 error.AccessDenied,
710711 error.PermissionDenied,