This commit is contained in:
sxyazi 2025-09-04 16:48:07 +08:00
parent a1e4f7781c
commit 5efde5366a
No known key found for this signature in database
2 changed files with 44 additions and 18 deletions

View file

@ -127,32 +127,44 @@ fn final_path(path: &Path) -> io::Result<PathBuf> {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
fn final_path(path: &Path) -> io::Result<PathBuf> { fn final_path(path: &Path) -> io::Result<PathBuf> {
use std::{ffi::OsString, os::windows::{ffi::OsStringExt, fs::OpenOptionsExt, io::AsRawHandle}}; use std::{ffi::OsString, fs::File, os::windows::{ffi::OsStringExt, fs::OpenOptionsExt, io::AsRawHandle}};
use windows_sys::Win32::{Foundation::HANDLE, Storage::FileSystem::{FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, GetFinalPathNameByHandleW, VOLUME_NAME_DOS}}; use windows_sys::Win32::{Foundation::HANDLE, Storage::FileSystem::{FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, GetFinalPathNameByHandleW, VOLUME_NAME_DOS}};
use yazi_shared::Either;
let file = std::fs::OpenOptions::new() let file = std::fs::OpenOptions::new()
.access_mode(0) .access_mode(0)
.custom_flags(FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT) .custom_flags(FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)
.open(path)?; .open(path)?;
let mut buf = [0u16; 512]; fn inner(file: &File, buf: &mut [u16]) -> io::Result<Either<PathBuf, u32>> {
let len = unsafe { let len = unsafe {
GetFinalPathNameByHandleW( GetFinalPathNameByHandleW(
file.as_raw_handle() as HANDLE, file.as_raw_handle() as HANDLE,
buf.as_mut_ptr(), buf.as_mut_ptr(),
buf.len() as u32, buf.len() as u32,
VOLUME_NAME_DOS, VOLUME_NAME_DOS,
) )
}; };
if len == 0 { Ok(if len == 0 {
Err(io::Error::last_os_error()) Err(io::Error::last_os_error())?
} else if len as usize > buf.len() { } else if len as usize > buf.len() {
Err(io::Error::new(io::ErrorKind::Other, "Path too long")) Either::Right(len)
} else if buf.starts_with(&[92, 92, 63, 92]) { } else if buf.starts_with(&[92, 92, 63, 92]) {
Ok(PathBuf::from(OsString::from_wide(&buf[4..len as usize]))) Either::Left(PathBuf::from(OsString::from_wide(&buf[4..len as usize])))
} else { } else {
Ok(PathBuf::from(OsString::from_wide(&buf[0..len as usize]))) Either::Left(PathBuf::from(OsString::from_wide(&buf[0..len as usize])))
})
}
let mut buf = [0u16; 512];
match inner(&file, &mut buf)? {
Either::Left(path) => Ok(path),
Either::Right(len) => {
let mut buf = vec![0u16; len as usize];
inner(&file, &mut buf)?
.left_or_err(|| io::Error::new(io::ErrorKind::InvalidData, "path too long"))
}
} }
} }

View file

@ -54,4 +54,18 @@ impl<L, R> Either<L, R> {
_ => None, _ => None,
} }
} }
pub fn left_or_err<E, F: FnOnce() -> E>(self, f: F) -> Result<L, E> {
match self {
Either::Left(l) => Ok(l),
_ => Err(f()),
}
}
pub fn right_or_err<E, F: FnOnce() -> E>(self, f: F) -> Result<R, E> {
match self {
Either::Right(r) => Ok(r),
_ => Err(f()),
}
}
} }