Skip to content

Commit

Permalink
fix: suppress warnings for different name representations of the same…
Browse files Browse the repository at this point in the history
… file in the case-insensitive file system when renaming (#1185)

Co-authored-by: sxyazi <sxyazi@gmail.com>
  • Loading branch information
Xerxes-2 and sxyazi authored Jun 23, 2024
1 parent 696dcf2 commit f1cf136
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 142 deletions.
269 changes: 136 additions & 133 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion cspell.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":"0.2","flagWords":[],"words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","imagesize","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname"],"language":"en"}
{"language":"en","flagWords":[],"words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","imagesize","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE"],"version":"0.2"}
2 changes: 1 addition & 1 deletion yazi-boot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ serde = { version = "1.0.203", features = [ "derive" ] }

[build-dependencies]
clap = { version = "4.5.7", features = [ "derive" ] }
clap_complete = "4.5.5"
clap_complete = "4.5.6"
clap_complete_nushell = "4.5.2"
clap_complete_fig = "4.5.1"
vergen = { version = "8.3.1", features = [ "build", "git", "gitcl" ] }
2 changes: 1 addition & 1 deletion yazi-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ toml_edit = "0.22.14"
[build-dependencies]
anyhow = "1.0.86"
clap = { version = "4.5.7", features = [ "derive" ] }
clap_complete = "4.5.5"
clap_complete = "4.5.6"
clap_complete_fig = "4.5.1"
clap_complete_nushell = "4.5.2"
serde_json = "1.0.117"
Expand Down
4 changes: 2 additions & 2 deletions yazi-core/src/manager/commands/bulk_rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use tokio::{fs::{self, OpenOptions}, io::{stdin, AsyncReadExt, AsyncWriteExt}};
use yazi_config::{OPEN, PREVIEW};
use yazi_dds::Pubsub;
use yazi_proxy::{AppProxy, TasksProxy, HIDER, WATCHER};
use yazi_shared::{fs::{max_common_root, maybe_exists, File, FilesOp, Url}, terminal_clear};
use yazi_shared::{fs::{max_common_root, maybe_exists, paths_to_same_file, File, FilesOp, Url}, terminal_clear};

use crate::manager::Manager;

Expand Down Expand Up @@ -84,7 +84,7 @@ impl Manager {
for (o, n) in todo {
let (old, new) = (root.join(&o), root.join(&n));

if maybe_exists(&new).await {
if maybe_exists(&new).await && !paths_to_same_file(&old, &new).await {
failed.push((o, n, anyhow!("Destination already exists")));
} else if let Err(e) = fs::rename(&old, &new).await {
failed.push((o, n, e.into()));
Expand Down
4 changes: 2 additions & 2 deletions yazi-core/src/manager/commands/rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use tokio::fs;
use yazi_config::popup::InputCfg;
use yazi_dds::Pubsub;
use yazi_proxy::{InputProxy, TabProxy, WATCHER};
use yazi_shared::{event::Cmd, fs::{maybe_exists, ok_or_not_found, symlink_realpath, File, FilesOp, Url}};
use yazi_shared::{event::Cmd, fs::{maybe_exists, ok_or_not_found, paths_to_same_file, symlink_realpath, File, FilesOp, Url}};

use crate::manager::Manager;

Expand Down Expand Up @@ -62,7 +62,7 @@ impl Manager {
}

let new = hovered.parent().unwrap().join(name);
if opt.force || !maybe_exists(&new).await {
if opt.force || !maybe_exists(&new).await || paths_to_same_file(&hovered, &new).await {
Self::rename_do(tab, hovered, Url::from(new)).await.ok();
return;
}
Expand Down
4 changes: 2 additions & 2 deletions yazi-scheduler/src/process/shell.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{ffi::OsString, io::Error, process::Stdio};
use std::{ffi::OsString, process::Stdio};

use anyhow::Result;
use tokio::process::{Child, Command};
Expand Down Expand Up @@ -37,7 +37,7 @@ pub fn shell(opt: ShellOpt) -> Result<Child> {
.kill_on_drop(!opt.orphan)
.pre_exec(move || {
if opt.orphan && libc::setpgid(0, 0) < 0 {
return Err(Error::last_os_error());
return Err(std::io::Error::last_os_error());
}
Ok(())
})
Expand Down
3 changes: 3 additions & 0 deletions yazi-shared/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ tokio = { version = "1.38.0", features = [ "full" ] }

[target."cfg(unix)".dependencies]
libc = "0.2.155"

[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.52.0", features = [ "Win32_Storage_FileSystem" ] }
53 changes: 53 additions & 0 deletions yazi-shared/src/fs/fns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,59 @@ pub fn ok_or_not_found(result: io::Result<()>) -> io::Result<()> {
}
}

#[inline]
pub async fn paths_to_same_file(a: impl AsRef<Path>, b: impl AsRef<Path>) -> bool {
_paths_to_same_file(a.as_ref(), b.as_ref()).await.unwrap_or(false)
}

#[cfg(unix)]
async fn _paths_to_same_file(a: &Path, b: &Path) -> io::Result<bool> {
use std::os::unix::fs::MetadataExt;

let (a_, b_) = (fs::symlink_metadata(a).await?, fs::symlink_metadata(b).await?);
Ok(
a_.ino() == b_.ino()
&& a_.dev() == b_.dev()
&& fs::canonicalize(a).await? == fs::canonicalize(b).await?,
)
}

#[cfg(windows)]
async fn _paths_to_same_file(a: &Path, b: &Path) -> std::io::Result<bool> {
use std::os::windows::{ffi::OsStringExt, io::AsRawHandle};

use windows_sys::Win32::{Foundation::{HANDLE, MAX_PATH}, Storage::FileSystem::{GetFinalPathNameByHandleW, FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, VOLUME_NAME_DOS}};

async fn final_name(p: &Path) -> std::io::Result<PathBuf> {
let file = tokio::fs::OpenOptions::new()
.access_mode(0)
.custom_flags(FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)
.open(p)
.await?;

tokio::task::spawn_blocking(move || {
let mut buf = [0u16; MAX_PATH as usize];
let len = unsafe {
GetFinalPathNameByHandleW(
file.as_raw_handle() as HANDLE,
buf.as_mut_ptr(),
buf.len() as u32,
VOLUME_NAME_DOS,
)
};

if len == 0 {
Err(std::io::Error::last_os_error())
} else {
Ok(PathBuf::from(OsString::from_wide(&buf[0..len as usize])))
}
})
.await?
}

Ok(final_name(a).await? == final_name(b).await?)
}

pub async fn symlink_realpath(path: &Path) -> Result<PathBuf> {
let p = fs::canonicalize(path).await?;
if p == path {
Expand Down

0 comments on commit f1cf136

Please sign in to comment.