diff options
| author | David Lönnhager <david.l@mullvad.net> | 2021-07-01 14:58:37 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2021-08-26 13:46:33 +0200 |
| commit | 5fef2f51685183c87b796c60896151586fbeec23 (patch) | |
| tree | 83386f658c87621f84d4a326478c9ab0ed1cd7f1 | |
| parent | d6f2ebac9a67df07bd596ffc8e0a10b368192c04 (diff) | |
| download | mullvadvpn-5fef2f51685183c87b796c60896151586fbeec23.tar.xz mullvadvpn-5fef2f51685183c87b796c60896151586fbeec23.zip | |
Resolve entire path before sending it to the driver
| -rw-r--r-- | talpid-core/src/split_tunnel/windows/windows.rs | 39 |
1 files changed, 36 insertions, 3 deletions
diff --git a/talpid-core/src/split_tunnel/windows/windows.rs b/talpid-core/src/split_tunnel/windows/windows.rs index 3163244c5f..6ae2ce7c98 100644 --- a/talpid-core/src/split_tunnel/windows/windows.rs +++ b/talpid-core/src/split_tunnel/windows/windows.rs @@ -3,10 +3,10 @@ use std::{ ffi::{OsStr, OsString}, - io, iter, mem, + fs, io, iter, mem, os::windows::{ ffi::{OsStrExt, OsStringExt}, - io::RawHandle, + io::{AsRawHandle, RawHandle}, }, path::Path, ptr, @@ -18,7 +18,7 @@ use winapi::{ winerror::{ERROR_INSUFFICIENT_BUFFER, ERROR_NO_MORE_FILES}, }, um::{ - fileapi::QueryDosDeviceW, + fileapi::{GetFinalPathNameByHandleW, QueryDosDeviceW}, handleapi::{CloseHandle, INVALID_HANDLE_VALUE}, processthreadsapi::{GetProcessTimes, OpenProcess}, psapi::K32GetProcessImageFileNameW, @@ -27,6 +27,9 @@ use winapi::{ }, }; +/// Return path with the volume device path. +const VOLUME_NAME_NT: u32 = 0x02; + pub struct ProcessSnapshot { handle: HANDLE, } @@ -107,6 +110,12 @@ impl Iterator for ProcessSnapshotEntries<'_> { /// Obtains a device path without resolving links or mount points. pub fn get_device_path<T: AsRef<Path>>(path: T) -> Result<OsString, io::Error> { + // Preferentially, use GetFinalPathNameByHandleW. If the file does not exist + // or cannot be opened, infer the path from the label only. + if let Ok(file) = fs::OpenOptions::new().read(true).open(path.as_ref()) { + return get_final_path_name_by_handle(file.as_raw_handle()); + } + let drive_comp = path.as_ref().components().next(); let drive = match drive_comp { Some(std::path::Component::Prefix(prefix)) => prefix.as_os_str(), @@ -128,6 +137,30 @@ pub fn get_device_path<T: AsRef<Path>>(path: T) -> Result<OsString, io::Error> { Ok(new_path) } +pub fn get_final_path_name_by_handle(raw_handle: RawHandle) -> Result<OsString, io::Error> { + let buffer_size = unsafe { + GetFinalPathNameByHandleW(raw_handle as *mut _, ptr::null_mut(), 0u32, VOLUME_NAME_NT) + } as usize; + let mut buffer = Vec::new(); + buffer.resize(buffer_size, 0); + + let status = unsafe { + GetFinalPathNameByHandleW( + raw_handle as *mut _, + buffer.as_mut_ptr(), + buffer_size as u32, + VOLUME_NAME_NT, + ) + } as usize; + + if status == 0 { + return Err(io::Error::last_os_error()); + } + + buffer.resize(buffer_size - 1, 0); + Ok(OsStringExt::from_wide(&buffer)) +} + /// Obtains the real device path for a label (such as C:). /// The underlying function may return multiple paths, but only the first is returned. fn query_dos_device<T: AsRef<OsStr>>(device_name: T) -> io::Result<OsString> { |
