| ... | ... | @@ -889,61 +889,26 @@ pub const ReadLinkError = error{ |
| 889 | 889 | AccessDenied, |
| 890 | 890 | Unexpected, |
| 891 | 891 | NameTooLong, |
| 892 | BadPathName, |
| 893 | AntivirusInterference, |
| 892 | 894 | UnsupportedReparsePointType, |
| 893 | 895 | }; |
| 894 | 896 | |
| 895 | 897 | pub 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, |
| 913 | 911 | }; |
| 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 | | } |
| 947 | 912 | defer CloseHandle(result_handle); |
| 948 | 913 | |
| 949 | 914 | 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 |
| 970 | 935 | const path_buf = @as([*]const u16, &buf.PathBuffer); |
| 971 | 936 | return parseReadlinkPath(path_buf[offset..][0..len], false, out_buffer); |
| 972 | 937 | }, |
| 973 | | else => |value| { |
| 974 | | std.debug.print("unsupported symlink type: {}", .{value}); |
| 938 | else => { |
| 975 | 939 | return error.UnsupportedReparsePointType; |
| 976 | 940 | }, |
| 977 | 941 | } |