| ... | @@ -889,61 +889,26 @@ pub const ReadLinkError = error{ | ... | @@ -889,61 +889,26 @@ pub const ReadLinkError = error{ |
| 889 | AccessDenied, | 889 | AccessDenied, |
| 890 | Unexpected, | 890 | Unexpected, |
| 891 | NameTooLong, | 891 | NameTooLong, |
| | 892 | BadPathName, |
| | 893 | AntivirusInterference, |
| 892 | UnsupportedReparsePointType, | 894 | UnsupportedReparsePointType, |
| 893 | }; | 895 | }; |
| 894 | | 896 | |
| 895 | pub fn ReadLink(dir: ?HANDLE, sub_path_w: []const u16, out_buffer: []u8) ReadLinkError![]u8 { | 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. | 898 | const result_handle = OpenFile(sub_path_w, .{ |
| 897 | // With the latter, we'd need to call `NtCreateFile` twice, once for file symlink, and if that | 899 | .access_mask = FILE_READ_ATTRIBUTES | SYNCHRONIZE, |
| 898 | // failed, again for dir symlink. Omitting any mention of file/dir flags makes it possible | 900 | .dir = dir, |
| 899 | // to open the symlink there and then. | 901 | .creation = FILE_OPEN, |
| 900 | const path_len_bytes = math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong; | 902 | .follow_symlinks = false, |
| 901 | var nt_name = UNICODE_STRING{ | 903 | .filter = .any, |
| 902 | .Length = path_len_bytes, | 904 | }) catch |err| switch (err) { |
| 903 | .MaximumLength = path_len_bytes, | 905 | error.IsDir, error.NotDir => return error.Unexpected, // filter = .any |
| 904 | .Buffer = @constCast(sub_path_w.ptr), | 906 | error.PathAlreadyExists => return error.Unexpected, // FILE_OPEN |
| 905 | }; | 907 | error.WouldBlock => return error.Unexpected, |
| 906 | var attr = OBJECT_ATTRIBUTES{ | 908 | error.NoDevice => return error.FileNotFound, |
| 907 | .Length = @sizeOf(OBJECT_ATTRIBUTES), | 909 | error.PipeBusy => return error.AccessDenied, |
| 908 | .RootDirectory = if (std.fs.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir, | 910 | else => |e| return e, |
| 909 | .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here. | | |
| 910 | .ObjectName = &nt_name, | | |
| 911 | .SecurityDescriptor = null, | | |
| 912 | .SecurityQualityOfService = null, | | |
| 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 | defer CloseHandle(result_handle); | 912 | defer CloseHandle(result_handle); |
| 948 | | 913 | |
| 949 | var reparse_buf: [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 align(@alignOf(REPARSE_DATA_BUFFER)) = undefined; | 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,8 +935,7 @@ pub fn ReadLink(dir: ?HANDLE, sub_path_w: []const u16, out_buffer: []u8) ReadLin |
| 970 | const path_buf = @as([*]const u16, &buf.PathBuffer); | 935 | const path_buf = @as([*]const u16, &buf.PathBuffer); |
| 971 | return parseReadlinkPath(path_buf[offset..][0..len], false, out_buffer); | 936 | return parseReadlinkPath(path_buf[offset..][0..len], false, out_buffer); |
| 972 | }, | 937 | }, |
| 973 | else => |value| { | 938 | else => { |
| 974 | std.debug.print("unsupported symlink type: {}", .{value}); | | |
| 975 | return error.UnsupportedReparsePointType; | 939 | return error.UnsupportedReparsePointType; |
| 976 | }, | 940 | }, |
| 977 | } | 941 | } |