diff --git a/cspell.json b/cspell.json index 8863c4db..c9ca6db9 100644 --- a/cspell.json +++ b/cspell.json @@ -1 +1 @@ -{"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","hardlink","hardlinking","nlink","nlink","linemodes","SIGSTOP","sevenzip","rsplitn","replacen","DECSET","DECRQM","repeek","cwds","tcsi","Hyprland","Wayfire","SWAYSOCK","btime","nsec","codegen","gethostname"],"flagWords":[],"version":"0.2","language":"en"} \ No newline at end of file +{"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","hardlink","hardlinking","nlink","nlink","linemodes","SIGSTOP","sevenzip","rsplitn","replacen","DECSET","DECRQM","repeek","cwds","tcsi","Hyprland","Wayfire","SWAYSOCK","btime","nsec","codegen","gethostname","fchmod"],"version":"0.2","language":"en"} \ No newline at end of file diff --git a/yazi-shared/src/fs/fns.rs b/yazi-shared/src/fs/fns.rs index d0e3286a..b07f7231 100644 --- a/yazi-shared/src/fs/fns.rs +++ b/yazi-shared/src/fs/fns.rs @@ -54,7 +54,7 @@ async fn _paths_to_same_file(a: &Path, b: &Path) -> std::io::Result { use windows_sys::Win32::{Foundation::{HANDLE, MAX_PATH}, Storage::FileSystem::{FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, GetFinalPathNameByHandleW, VOLUME_NAME_DOS}}; async fn final_name(p: &Path) -> std::io::Result { - let file = tokio::fs::OpenOptions::new() + let file = fs::OpenOptions::new() .access_mode(0) .custom_flags(FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT) .open(p) @@ -190,31 +190,8 @@ pub fn copy_with_progress( tokio::spawn({ let (from, to) = (from.to_owned(), to.to_owned()); - let mut ft = std::fs::FileTimes::new(); - cha.atime.map(|t| ft = ft.set_accessed(t)); - cha.mtime.map(|t| ft = ft.set_modified(t)); - #[cfg(target_os = "macos")] - { - use std::os::macos::fs::FileTimesExt; - cha.btime.map(|t| ft = ft.set_created(t)); - } - #[cfg(windows)] - { - use std::os::windows::fs::FileTimesExt; - cha.btime.map(|t| ft = ft.set_created(t)); - } - async move { - _ = match fs::copy(&from, &to).await { - Ok(len) => { - _ = tokio::task::spawn_blocking(move || { - std::fs::File::options().write(true).open(to).and_then(|f| f.set_times(ft)).ok(); - }) - .await; - tick_tx.send(Ok(len)) - } - Err(e) => tick_tx.send(Err(e)), - }; + tick_tx.send(_copy_with_progress(from, to, cha).await).ok(); } }); @@ -259,6 +236,57 @@ pub fn copy_with_progress( rx } +async fn _copy_with_progress(from: PathBuf, to: PathBuf, cha: Cha) -> io::Result { + let mut ft = std::fs::FileTimes::new(); + cha.atime.map(|t| ft = ft.set_accessed(t)); + cha.mtime.map(|t| ft = ft.set_modified(t)); + #[cfg(target_os = "macos")] + { + use std::os::macos::fs::FileTimesExt; + cha.btime.map(|t| ft = ft.set_created(t)); + } + #[cfg(windows)] + { + use std::os::windows::fs::FileTimesExt; + cha.btime.map(|t| ft = ft.set_created(t)); + } + + let written; + #[cfg(any(target_os = "linux", target_os = "android"))] + { + use std::os::fd::AsRawFd; + + let mut reader = fs::File::open(from).await?; + let mut writer = fs::OpenOptions::new() + .mode(cha.perm as u32) + .write(true) + .create(true) + .truncate(true) + .open(to) + .await?; + + written = io::copy(&mut reader, &mut writer).await?; + let writer = writer.into_std().await; + + _ = tokio::task::spawn_blocking(move || { + unsafe { libc::fchmod(writer.as_raw_fd(), cha.perm) }; + writer.set_times(ft).ok(); + }) + .await; + } + + #[cfg(not(any(target_os = "linux", target_os = "android")))] + { + written = fs::copy(from, &to).await?; + _ = tokio::task::spawn_blocking(move || { + std::fs::File::options().write(true).open(to).and_then(|f| f.set_times(ft)).ok(); + }) + .await; + } + + Ok(written) +} + pub async fn remove_dir_clean(dir: &Path) { let Ok(mut it) = fs::read_dir(dir).await else { return };