| ... | ... | @@ -898,7 +898,6 @@ pub fn SetFilePointerEx_CURRENT_get(handle: HANDLE) SetFilePointerError!u64 { |
| 898 | 898 | |
| 899 | 899 | pub const GetFinalPathNameByHandleError = error{ |
| 900 | 900 | FileNotFound, |
| 901 | | SystemResources, |
| 902 | 901 | NameTooLong, |
| 903 | 902 | Unexpected, |
| 904 | 903 | }; |
| ... | ... | @@ -963,9 +962,19 @@ pub fn GetFinalPathNameByHandle(hFile: HANDLE, out_buffer: []u16) GetFinalPathNa |
| 963 | 962 | break :blk @as([*]const u16, object_name.Name.Buffer)[0..object_name.Name.Length / 2]; |
| 964 | 963 | }; |
| 965 | 964 | |
| 966 | | // Since `NtQueryObject` returns a fully-qualified NT path, we need to translate |
| 967 | | // the result into a Win32/DOS path (e.g., \Device\HarddiskVolume4\foo would become |
| 968 | | // C:\foo). |
| 965 | // By now, we got a a fully-qualified NT path, which we need to translate |
| 966 | // into a Win32/DOS path, for instance: |
| 967 | // \Device\HarddiskVolume4\foo => C:\foo |
| 968 | // |
| 969 | // NOTE: |
| 970 | // I couldn't figure out a better way of doing this unfortunately... |
| 971 | // This snippet below is in part based around `QueryDosDeviceW` implementation |
| 972 | // found in Wine. The trick with `NtQueryDirectoryObject` for some reason |
| 973 | // only lists `\DosDevices\Global` as the only SymblinkObject available, which |
| 974 | // means it's not possible to query the kernel for all available DOS volume name |
| 975 | // symlinks. |
| 976 | // TODO investigate! |
| 977 | // Wine source: https://source.winehq.com/git/wine.git/blob/HEAD:/dlls/kernelbase/volume.c#l1009 |
| 969 | 978 | const dos_drive_letters = &[_]u16{ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; |
| 970 | 979 | var query_path = [_]u16{ '\\', 'D', 'o', 's', 'D', 'e', 'v', 'i', 'c', 'e', 's', '\\', 'C', ':' }; |
| 971 | 980 | for (dos_drive_letters) |drive_letter| { |
| ... | ... | @@ -1010,14 +1019,17 @@ pub fn GetFinalPathNameByHandle(hFile: HANDLE, out_buffer: []u16) GetFinalPathNa |
| 1010 | 1019 | const link_path = @as([*]const u16, link.Buffer)[0..link.Length / 2]; |
| 1011 | 1020 | const idx = std.mem.indexOf(u16, object_path, link_path) orelse continue; |
| 1012 | 1021 | |
| 1013 | | // TODO check the provided buffer is actually big enough. |
| 1022 | // TODO is this the most appropriate error here? |
| 1023 | if (out_buffer.len < drive.len + object_path.len) return error.NameTooLong; |
| 1024 | |
| 1014 | 1025 | std.mem.copy(u16, out_buffer[0..], drive[0..]); |
| 1015 | 1026 | std.mem.copy(u16, out_buffer[2..], object_path[link_path.len..]); |
| 1016 | 1027 | |
| 1017 | 1028 | return out_buffer[0..object_path.len - link_path.len + 2]; |
| 1018 | 1029 | } |
| 1019 | 1030 | |
| 1020 | | // If we're here, that means there was no match so error out! |
| 1031 | // If we're here, that means there was no match so we panic! |
| 1032 | // TODO should we actually panic here or return an error instead? |
| 1021 | 1033 | unreachable; |
| 1022 | 1034 | } |
| 1023 | 1035 | |