mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
fix: fallback in Windows casefold for MS-DOS devices (#3700)
This commit is contained in:
parent
9af792ef69
commit
e49cdfe220
2 changed files with 35 additions and 15 deletions
|
|
@ -180,17 +180,12 @@ 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, fs::File, os::windows::{ffi::OsStringExt, fs::OpenOptionsExt, io::AsRawHandle}};
|
use std::{ffi::OsString, fs::File, mem, os::windows::{ffi::{OsStrExt, OsStringExt}, fs::OpenOptionsExt, io::AsRawHandle}};
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
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, INVALID_HANDLE_VALUE}, Storage::FileSystem::{FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, FindClose, FindFirstFileW, GetFinalPathNameByHandleW, VOLUME_NAME_DOS, WIN32_FIND_DATAW}};
|
||||||
|
|
||||||
let file = std::fs::OpenOptions::new()
|
fn by_handle(file: &File, buf: &mut [u16]) -> io::Result<Either<PathBuf, u32>> {
|
||||||
.access_mode(0)
|
|
||||||
.custom_flags(FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)
|
|
||||||
.open(path)?;
|
|
||||||
|
|
||||||
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,
|
||||||
|
|
@ -211,11 +206,36 @@ fn final_path(path: &Path) -> io::Result<PathBuf> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
match inner(&file, &mut [0u16; 512])? {
|
fn by_find(path: &Path) -> io::Result<PathBuf> {
|
||||||
Either::Left(path) => Ok(path),
|
let Some(parent) = path.parent() else {
|
||||||
Either::Right(len) => inner(&file, &mut vec![0u16; len as usize])?
|
return Ok(path.to_path_buf());
|
||||||
.left()
|
};
|
||||||
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "path too long")),
|
|
||||||
|
let wide: Vec<u16> = path.as_os_str().encode_wide().chain([0]).collect();
|
||||||
|
let mut data = unsafe { mem::zeroed::<WIN32_FIND_DATAW>() };
|
||||||
|
match unsafe { FindFirstFileW(wide.as_ptr(), &mut data) } {
|
||||||
|
INVALID_HANDLE_VALUE => return Err(io::Error::last_os_error()),
|
||||||
|
handle => _ = unsafe { FindClose(handle) },
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = data.cFileName.split(|&c| c == 0).next().unwrap_or(&data.cFileName);
|
||||||
|
Ok(parent.join(OsString::from_wide(name)))
|
||||||
|
}
|
||||||
|
|
||||||
|
let file = std::fs::OpenOptions::new()
|
||||||
|
.access_mode(0)
|
||||||
|
.custom_flags(FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)
|
||||||
|
.open(path)?;
|
||||||
|
|
||||||
|
match by_handle(&file, &mut [0u16; 512]) {
|
||||||
|
Ok(Either::Left(path)) => Ok(path),
|
||||||
|
Ok(Either::Right(len)) => match by_handle(&file, &mut vec![0u16; len as usize])? {
|
||||||
|
Either::Left(path) => Ok(path),
|
||||||
|
Either::Right(_) => Err(io::Error::new(io::ErrorKind::InvalidData, "path too long")),
|
||||||
|
},
|
||||||
|
// Fallback for paths that GetFinalPathNameByHandleW cannot handle,
|
||||||
|
// such as those on DefineDosDeviceW-created devices (error 1005).
|
||||||
|
Err(_) => by_find(path),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ use std::{cell::Cell, fmt::{Debug, Display, Formatter}, ops::Deref};
|
||||||
|
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
/// [`SyncCell`], but [`Sync`].
|
/// [`Cell`], but [`Sync`].
|
||||||
///
|
///
|
||||||
/// This is just an `Cell`, except it implements `Sync`
|
/// This is just a `Cell`, except it implements `Sync`
|
||||||
/// if `T` implements `Sync`.
|
/// if `T` implements `Sync`.
|
||||||
pub struct SyncCell<T: ?Sized>(Cell<T>);
|
pub struct SyncCell<T: ?Sized>(Cell<T>);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue