mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
refactor: replace Metadata with Cha in the file scheduler to improve interoperability with yazi-fs (#1785)
This commit is contained in:
parent
3e8ac856cf
commit
097e5abb82
9 changed files with 129 additions and 116 deletions
|
|
@ -136,7 +136,7 @@ impl Watcher {
|
|||
};
|
||||
|
||||
let u = &file.url;
|
||||
let eq = (!file.is_link() && fs::canonicalize(u).await.is_ok_and(|p| p == ***u))
|
||||
let eq = (!file.is_linkable() && fs::canonicalize(u).await.is_ok_and(|p| p == ***u))
|
||||
|| realname_unchecked(u, &mut cached).await.is_ok_and(|s| urn.as_urn() == s);
|
||||
|
||||
if !eq {
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ impl Utils {
|
|||
area,
|
||||
inner,
|
||||
wrap: if PREVIEW.wrap == PreviewWrap::Yes { WRAP } else { WRAP_NO },
|
||||
..Default::default()
|
||||
})];
|
||||
|
||||
emit!(Call(Cmd::new("update_peeked").with_any("lock", lock), Layer::Manager));
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use std::{borrow::Cow, collections::VecDeque, fs::Metadata, path::{Path, PathBuf}};
|
||||
use std::{borrow::Cow, collections::VecDeque, path::{Path, PathBuf}};
|
||||
|
||||
use anyhow::{Result, anyhow};
|
||||
use tokio::{fs, io::{self, ErrorKind::{AlreadyExists, NotFound}}, sync::mpsc};
|
||||
use tokio::{fs::{self, DirEntry}, io::{self, ErrorKind::{AlreadyExists, NotFound}}, sync::mpsc};
|
||||
use tracing::warn;
|
||||
use yazi_config::TASKS;
|
||||
use yazi_shared::fs::{Url, calculate_size, copy_with_progress, maybe_exists, ok_or_not_found, path_relative_to};
|
||||
use yazi_shared::fs::{Cha, Url, calculate_size, copy_with_progress, maybe_exists, ok_or_not_found, path_relative_to};
|
||||
|
||||
use super::{FileOp, FileOpDelete, FileOpHardlink, FileOpLink, FileOpPaste, FileOpTrash};
|
||||
use crate::{LOW, NORMAL, TaskOp, TaskProg};
|
||||
|
|
@ -26,7 +26,7 @@ impl File {
|
|||
match op {
|
||||
FileOp::Paste(mut task) => {
|
||||
ok_or_not_found(fs::remove_file(&task.to).await)?;
|
||||
let mut it = copy_with_progress(&task.from, &task.to, task.meta.as_ref().unwrap());
|
||||
let mut it = copy_with_progress(&task.from, &task.to, task.cha.unwrap());
|
||||
|
||||
while let Some(res) = it.recv().await {
|
||||
match res {
|
||||
|
|
@ -58,14 +58,14 @@ impl File {
|
|||
self.prog.send(TaskProg::Adv(task.id, 1, 0))?;
|
||||
}
|
||||
FileOp::Link(task) => {
|
||||
let meta = task.meta.as_ref().unwrap();
|
||||
let cha = task.cha.unwrap();
|
||||
|
||||
let src = if task.resolve {
|
||||
match fs::read_link(&task.from).await {
|
||||
Ok(p) => Cow::Owned(p),
|
||||
Err(e) if e.kind() == NotFound => {
|
||||
warn!("Link task partially done: {task:?}");
|
||||
return Ok(self.prog.send(TaskProg::Adv(task.id, 1, meta.len()))?);
|
||||
return Ok(self.prog.send(TaskProg::Adv(task.id, 1, cha.len))?);
|
||||
}
|
||||
Err(e) => Err(e)?,
|
||||
}
|
||||
|
|
@ -86,7 +86,7 @@ impl File {
|
|||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
if meta.is_dir() {
|
||||
if cha.is_dir() {
|
||||
fs::symlink_dir(src, &task.to).await?;
|
||||
} else {
|
||||
fs::symlink_file(src, &task.to).await?;
|
||||
|
|
@ -96,10 +96,10 @@ impl File {
|
|||
if task.delete {
|
||||
fs::remove_file(&task.from).await.ok();
|
||||
}
|
||||
self.prog.send(TaskProg::Adv(task.id, 1, meta.len()))?;
|
||||
self.prog.send(TaskProg::Adv(task.id, 1, cha.len))?;
|
||||
}
|
||||
FileOp::Hardlink(task) => {
|
||||
let meta = task.meta.as_ref().unwrap();
|
||||
let cha = task.cha.unwrap();
|
||||
let src = if !task.follow {
|
||||
Cow::Borrowed(task.from.as_path())
|
||||
} else if let Ok(p) = fs::canonicalize(&task.from).await {
|
||||
|
|
@ -116,7 +116,7 @@ impl File {
|
|||
v => v?,
|
||||
}
|
||||
|
||||
self.prog.send(TaskProg::Adv(task.id, 1, meta.len()))?;
|
||||
self.prog.send(TaskProg::Adv(task.id, 1, cha.len))?;
|
||||
}
|
||||
FileOp::Delete(task) => {
|
||||
if let Err(e) = fs::remove_file(&task.target).await {
|
||||
|
|
@ -154,19 +154,19 @@ impl File {
|
|||
return self.succ(task.id);
|
||||
}
|
||||
|
||||
if task.meta.is_none() {
|
||||
task.meta = Some(Self::metadata(&task.from, task.follow).await?);
|
||||
if task.cha.is_none() {
|
||||
task.cha = Some(Self::cha(&task.from, task.follow).await?);
|
||||
}
|
||||
|
||||
let meta = task.meta.as_ref().unwrap();
|
||||
if !meta.is_dir() {
|
||||
let cha = task.cha.unwrap();
|
||||
if !cha.is_dir() {
|
||||
let id = task.id;
|
||||
self.prog.send(TaskProg::New(id, meta.len()))?;
|
||||
self.prog.send(TaskProg::New(id, cha.len))?;
|
||||
|
||||
if meta.is_file() {
|
||||
self.queue(FileOp::Paste(task), LOW).await?;
|
||||
} else if meta.is_symlink() {
|
||||
if cha.is_linkable() {
|
||||
self.queue(FileOp::Link(task.into()), NORMAL).await?;
|
||||
} else {
|
||||
self.queue(FileOp::Paste(task), LOW).await?;
|
||||
}
|
||||
return self.succ(id);
|
||||
}
|
||||
|
|
@ -198,20 +198,20 @@ impl File {
|
|||
let mut it = continue_unless_ok!(fs::read_dir(&src).await);
|
||||
while let Ok(Some(entry)) = it.next_entry().await {
|
||||
let from = Url::from(entry.path());
|
||||
let meta = continue_unless_ok!(Self::metadata(&from, task.follow).await);
|
||||
let cha = continue_unless_ok!(Self::cha_from(entry, &from, task.follow).await);
|
||||
|
||||
if meta.is_dir() {
|
||||
if cha.is_dir() {
|
||||
dirs.push_back(from);
|
||||
continue;
|
||||
}
|
||||
|
||||
let to = dest.join(from.file_name().unwrap());
|
||||
self.prog.send(TaskProg::New(task.id, meta.len()))?;
|
||||
self.prog.send(TaskProg::New(task.id, cha.len))?;
|
||||
|
||||
if meta.is_file() {
|
||||
self.queue(FileOp::Paste(task.spawn(from, to, meta)), LOW).await?;
|
||||
} else if meta.is_symlink() {
|
||||
self.queue(FileOp::Link(task.spawn(from, to, meta).into()), NORMAL).await?;
|
||||
if cha.is_linkable() {
|
||||
self.queue(FileOp::Link(task.spawn(from, to, cha).into()), NORMAL).await?;
|
||||
} else {
|
||||
self.queue(FileOp::Paste(task.spawn(from, to, cha)), LOW).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -220,24 +220,24 @@ impl File {
|
|||
|
||||
pub async fn link(&self, mut task: FileOpLink) -> Result<()> {
|
||||
let id = task.id;
|
||||
if task.meta.is_none() {
|
||||
task.meta = Some(fs::symlink_metadata(&task.from).await?);
|
||||
if task.cha.is_none() {
|
||||
task.cha = Some(Self::cha(&task.from, false).await?);
|
||||
}
|
||||
|
||||
self.prog.send(TaskProg::New(id, task.meta.as_ref().unwrap().len()))?;
|
||||
self.prog.send(TaskProg::New(id, task.cha.unwrap().len))?;
|
||||
self.queue(FileOp::Link(task), NORMAL).await?;
|
||||
self.succ(id)
|
||||
}
|
||||
|
||||
pub async fn hardlink(&self, mut task: FileOpHardlink) -> Result<()> {
|
||||
if task.meta.is_none() {
|
||||
task.meta = Some(Self::metadata(&task.from, task.follow).await?);
|
||||
if task.cha.is_none() {
|
||||
task.cha = Some(Self::cha(&task.from, task.follow).await?);
|
||||
}
|
||||
|
||||
let meta = task.meta.as_ref().unwrap();
|
||||
if !meta.is_dir() {
|
||||
let cha = task.cha.unwrap();
|
||||
if !cha.is_dir() {
|
||||
let id = task.id;
|
||||
self.prog.send(TaskProg::New(id, meta.len()))?;
|
||||
self.prog.send(TaskProg::New(id, cha.len))?;
|
||||
self.queue(FileOp::Hardlink(task), NORMAL).await?;
|
||||
return self.succ(id);
|
||||
}
|
||||
|
|
@ -269,16 +269,16 @@ impl File {
|
|||
let mut it = continue_unless_ok!(fs::read_dir(&src).await);
|
||||
while let Ok(Some(entry)) = it.next_entry().await {
|
||||
let from = Url::from(entry.path());
|
||||
let meta = continue_unless_ok!(Self::metadata(&from, task.follow).await);
|
||||
let cha = continue_unless_ok!(Self::cha_from(entry, &from, task.follow).await);
|
||||
|
||||
if meta.is_dir() {
|
||||
if cha.is_dir() {
|
||||
dirs.push_back(from);
|
||||
continue;
|
||||
}
|
||||
|
||||
let to = dest.join(from.file_name().unwrap());
|
||||
self.prog.send(TaskProg::New(task.id, meta.len()))?;
|
||||
self.queue(FileOp::Hardlink(task.spawn(from, to, meta)), NORMAL).await?;
|
||||
self.prog.send(TaskProg::New(task.id, cha.len))?;
|
||||
self.queue(FileOp::Hardlink(task.spawn(from, to, cha)), NORMAL).await?;
|
||||
}
|
||||
}
|
||||
self.succ(task.id)
|
||||
|
|
@ -325,13 +325,18 @@ impl File {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
async fn metadata(path: &Path, follow: bool) -> io::Result<Metadata> {
|
||||
if !follow {
|
||||
return fs::symlink_metadata(path).await;
|
||||
}
|
||||
async fn cha(path: &Path, follow: bool) -> io::Result<Cha> {
|
||||
let meta = fs::symlink_metadata(path).await?;
|
||||
Ok(if follow { Cha::new(path, meta).await } else { Cha::new_nofollow(path, meta) })
|
||||
}
|
||||
|
||||
let meta = fs::metadata(path).await;
|
||||
if meta.is_ok() { meta } else { fs::symlink_metadata(path).await }
|
||||
#[inline]
|
||||
async fn cha_from(entry: DirEntry, path: &Path, follow: bool) -> io::Result<Cha> {
|
||||
Ok(if follow {
|
||||
Cha::new(path, entry.metadata().await?).await
|
||||
} else {
|
||||
Cha::new_nofollow(path, entry.metadata().await?)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
use std::fs::Metadata;
|
||||
|
||||
use yazi_shared::fs::Url;
|
||||
use yazi_shared::fs::{Cha, Url};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FileOp {
|
||||
|
|
@ -29,19 +27,19 @@ pub struct FileOpPaste {
|
|||
pub id: usize,
|
||||
pub from: Url,
|
||||
pub to: Url,
|
||||
pub meta: Option<Metadata>,
|
||||
pub cha: Option<Cha>,
|
||||
pub cut: bool,
|
||||
pub follow: bool,
|
||||
pub retry: u8,
|
||||
}
|
||||
|
||||
impl FileOpPaste {
|
||||
pub(super) fn spawn(&self, from: Url, to: Url, meta: Metadata) -> Self {
|
||||
pub(super) fn spawn(&self, from: Url, to: Url, cha: Cha) -> Self {
|
||||
Self {
|
||||
id: self.id,
|
||||
from,
|
||||
to,
|
||||
meta: Some(meta),
|
||||
cha: Some(cha),
|
||||
cut: self.cut,
|
||||
follow: self.follow,
|
||||
retry: self.retry,
|
||||
|
|
@ -55,7 +53,7 @@ pub struct FileOpLink {
|
|||
pub id: usize,
|
||||
pub from: Url,
|
||||
pub to: Url,
|
||||
pub meta: Option<Metadata>,
|
||||
pub cha: Option<Cha>,
|
||||
pub resolve: bool,
|
||||
pub relative: bool,
|
||||
pub delete: bool,
|
||||
|
|
@ -67,7 +65,7 @@ impl From<FileOpPaste> for FileOpLink {
|
|||
id: value.id,
|
||||
from: value.from,
|
||||
to: value.to,
|
||||
meta: value.meta,
|
||||
cha: value.cha,
|
||||
resolve: true,
|
||||
relative: false,
|
||||
delete: value.cut,
|
||||
|
|
@ -81,13 +79,13 @@ pub struct FileOpHardlink {
|
|||
pub id: usize,
|
||||
pub from: Url,
|
||||
pub to: Url,
|
||||
pub meta: Option<Metadata>,
|
||||
pub cha: Option<Cha>,
|
||||
pub follow: bool,
|
||||
}
|
||||
|
||||
impl FileOpHardlink {
|
||||
pub(super) fn spawn(&self, from: Url, to: Url, meta: Metadata) -> Self {
|
||||
Self { id: self.id, from, to, meta: Some(meta), follow: self.follow }
|
||||
pub(super) fn spawn(&self, from: Url, to: Url, cha: Cha) -> Self {
|
||||
Self { id: self.id, from, to, cha: Some(cha), follow: self.follow }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ impl Scheduler {
|
|||
|
||||
pub fn file_cut(&self, from: Url, mut to: Url, force: bool) {
|
||||
let mut ongoing = self.ongoing.lock();
|
||||
let id = ongoing.add(TaskKind::User, format!("Cut {:?} to {:?}", from, to));
|
||||
let id = ongoing.add(TaskKind::User, format!("Cut {from} to {to}"));
|
||||
|
||||
if to.starts_with(&from) && to != from {
|
||||
self.new_and_fail(id, "Cannot cut directory into itself").ok();
|
||||
|
|
@ -99,7 +99,7 @@ impl Scheduler {
|
|||
if !force {
|
||||
to = unique_name(to).await?;
|
||||
}
|
||||
file.paste(FileOpPaste { id, from, to, meta: None, cut: true, follow: false, retry: 0 }).await
|
||||
file.paste(FileOpPaste { id, from, to, cha: None, cut: true, follow: false, retry: 0 }).await
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -116,7 +116,7 @@ impl Scheduler {
|
|||
if !force {
|
||||
to = unique_name(to).await?;
|
||||
}
|
||||
file.paste(FileOpPaste { id, from, to, meta: None, cut: false, follow, retry: 0 }).await
|
||||
file.paste(FileOpPaste { id, from, to, cha: None, cut: false, follow, retry: 0 }).await
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -129,7 +129,7 @@ impl Scheduler {
|
|||
to = unique_name(to).await?;
|
||||
}
|
||||
file
|
||||
.link(FileOpLink { id, from, to, meta: None, resolve: false, relative, delete: false })
|
||||
.link(FileOpLink { id, from, to, cha: None, resolve: false, relative, delete: false })
|
||||
.await
|
||||
});
|
||||
}
|
||||
|
|
@ -147,7 +147,7 @@ impl Scheduler {
|
|||
if !force {
|
||||
to = unique_name(to).await?;
|
||||
}
|
||||
file.hardlink(FileOpHardlink { id, from, to, meta: None, follow }).await
|
||||
file.hardlink(FileOpHardlink { id, from, to, cha: None, follow }).await
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
use std::{fs::{FileType, Metadata}, time::SystemTime};
|
||||
use std::{fs::{FileType, Metadata}, path::Path, time::SystemTime};
|
||||
|
||||
use bitflags::bitflags;
|
||||
use yazi_macro::unix_either;
|
||||
|
||||
use super::Urn;
|
||||
|
||||
bitflags! {
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub struct ChaKind: u8 {
|
||||
|
|
@ -37,40 +39,40 @@ pub struct Cha {
|
|||
|
||||
impl From<Metadata> for Cha {
|
||||
fn from(m: Metadata) -> Self {
|
||||
let mut ck = ChaKind::empty();
|
||||
let mut kind = ChaKind::empty();
|
||||
if m.is_dir() {
|
||||
ck |= ChaKind::DIR;
|
||||
kind |= ChaKind::DIR;
|
||||
}
|
||||
|
||||
Self {
|
||||
kind: ck,
|
||||
len: m.len(),
|
||||
atime: m.accessed().ok(),
|
||||
btime: m.created().ok(),
|
||||
kind,
|
||||
len: m.len(),
|
||||
atime: m.accessed().ok(),
|
||||
btime: m.created().ok(),
|
||||
#[cfg(unix)]
|
||||
ctime: {
|
||||
ctime: {
|
||||
use std::{os::unix::fs::MetadataExt, time::{Duration, UNIX_EPOCH}};
|
||||
UNIX_EPOCH.checked_add(Duration::new(m.ctime() as u64, m.ctime_nsec() as u32))
|
||||
},
|
||||
mtime: m.modified().ok(),
|
||||
mtime: m.modified().ok(),
|
||||
|
||||
#[cfg(unix)]
|
||||
perm: {
|
||||
perm: {
|
||||
use std::os::unix::prelude::PermissionsExt;
|
||||
m.permissions().mode() as _
|
||||
},
|
||||
#[cfg(unix)]
|
||||
uid: {
|
||||
uid: {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
m.uid() as _
|
||||
},
|
||||
#[cfg(unix)]
|
||||
gid: {
|
||||
gid: {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
m.gid() as _
|
||||
},
|
||||
#[cfg(unix)]
|
||||
nlink: {
|
||||
nlink: {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
m.nlink() as _
|
||||
},
|
||||
|
|
@ -89,7 +91,7 @@ impl From<FileType> for Cha {
|
|||
kind |= ChaKind::DIR;
|
||||
libc::S_IFDIR
|
||||
} else if t.is_symlink() {
|
||||
kind |= ChaKind::LINK;
|
||||
kind |= ChaKind::ORPHAN;
|
||||
libc::S_IFLNK
|
||||
} else if t.is_block_device() {
|
||||
libc::S_IFBLK
|
||||
|
|
@ -124,14 +126,43 @@ impl From<FileType> for Cha {
|
|||
|
||||
impl Cha {
|
||||
#[inline]
|
||||
pub fn dummy() -> Self { Self { kind: ChaKind::DUMMY, ..Default::default() } }
|
||||
pub async fn new(path: &Path, mut meta: Metadata) -> Self {
|
||||
let mut attached = ChaKind::empty();
|
||||
|
||||
if meta.is_symlink() {
|
||||
meta = tokio::fs::metadata(path).await.unwrap_or(meta);
|
||||
attached |= if meta.is_symlink() { ChaKind::ORPHAN } else { ChaKind::LINK };
|
||||
}
|
||||
|
||||
let mut cha = Self::new_nofollow(path, meta);
|
||||
cha.kind |= attached;
|
||||
cha
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_kind(mut self, kind: ChaKind) -> Self {
|
||||
self.kind |= kind;
|
||||
self
|
||||
pub fn new_nofollow(path: &Path, meta: Metadata) -> Self {
|
||||
let mut attached = ChaKind::empty();
|
||||
|
||||
#[cfg(unix)]
|
||||
if Urn::new(path).is_hidden() {
|
||||
attached |= ChaKind::HIDDEN;
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::os::windows::fs::MetadataExt;
|
||||
if meta.file_attributes() & 2 != 0 {
|
||||
attached |= ChaKind::HIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
let mut cha = Self::from(meta);
|
||||
cha.kind |= attached;
|
||||
cha
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn dummy() -> Self { Self { kind: ChaKind::DUMMY, ..Default::default() } }
|
||||
|
||||
#[inline]
|
||||
pub fn hits(self, c: Self) -> bool {
|
||||
self.len == c.len
|
||||
|
|
@ -156,6 +187,9 @@ impl Cha {
|
|||
#[inline]
|
||||
pub const fn is_orphan(&self) -> bool { self.kind.contains(ChaKind::ORPHAN) }
|
||||
|
||||
#[inline]
|
||||
pub const fn is_linkable(&self) -> bool { self.is_link() || self.is_orphan() }
|
||||
|
||||
#[inline]
|
||||
pub const fn is_dummy(&self) -> bool { self.kind.contains(ChaKind::DUMMY) }
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use anyhow::Result;
|
|||
use tokio::fs;
|
||||
|
||||
use super::{Urn, UrnBuf};
|
||||
use crate::{fs::{Cha, ChaKind, Url}, theme::IconCache};
|
||||
use crate::{fs::{Cha, Url}, theme::IconCache};
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct File {
|
||||
|
|
@ -34,34 +34,13 @@ impl File {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn from_meta(url: Url, mut meta: Metadata) -> Self {
|
||||
let mut ck = ChaKind::empty();
|
||||
let (is_link, mut link_to) = (meta.is_symlink(), None);
|
||||
pub async fn from_meta(url: Url, meta: Metadata) -> Self {
|
||||
let link_to =
|
||||
if meta.is_symlink() { fs::read_link(&url).await.map(Url::from).ok() } else { None };
|
||||
|
||||
if is_link {
|
||||
meta = fs::metadata(&url).await.unwrap_or(meta);
|
||||
link_to = fs::read_link(&url).await.map(Url::from).ok();
|
||||
}
|
||||
let cha = Cha::new(&url, meta).await;
|
||||
|
||||
if is_link && meta.is_symlink() {
|
||||
ck |= ChaKind::ORPHAN;
|
||||
} else if is_link {
|
||||
ck |= ChaKind::LINK;
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
if url.is_hidden() {
|
||||
ck |= ChaKind::HIDDEN;
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::os::windows::fs::MetadataExt;
|
||||
if meta.file_attributes() & 2 != 0 {
|
||||
ck |= ChaKind::HIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
Self { url, cha: Cha::from(meta).with_kind(ck), link_to, icon: Default::default() }
|
||||
Self { url, cha, link_to, icon: Default::default() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
use std::{borrow::Cow, collections::{HashMap, HashSet, VecDeque}, ffi::{OsStr, OsString}, fs::Metadata, path::{Path, PathBuf}};
|
||||
use std::{borrow::Cow, collections::{HashMap, HashSet, VecDeque}, ffi::{OsStr, OsString}, path::{Path, PathBuf}};
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use tokio::{fs, io, select, sync::{mpsc, oneshot}, time};
|
||||
|
||||
use super::Cha;
|
||||
|
||||
#[inline]
|
||||
pub async fn must_exists(p: impl AsRef<Path>) -> bool { fs::symlink_metadata(p).await.is_ok() }
|
||||
|
||||
|
|
@ -175,7 +177,7 @@ pub async fn calculate_size(path: &Path) -> u64 {
|
|||
pub fn copy_with_progress(
|
||||
from: &Path,
|
||||
to: &Path,
|
||||
meta: &Metadata,
|
||||
cha: Cha,
|
||||
) -> mpsc::Receiver<Result<u64, io::Error>> {
|
||||
let (tx, rx) = mpsc::channel(1);
|
||||
let (tick_tx, mut tick_rx) = oneshot::channel();
|
||||
|
|
@ -184,17 +186,17 @@ pub fn copy_with_progress(
|
|||
let (from, to) = (from.to_owned(), to.to_owned());
|
||||
|
||||
let mut ft = std::fs::FileTimes::new();
|
||||
meta.accessed().map(|t| ft = ft.set_accessed(t)).ok();
|
||||
meta.modified().map(|t| ft = ft.set_modified(t)).ok();
|
||||
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;
|
||||
meta.created().map(|t| ft = ft.set_created(t)).ok();
|
||||
cha.btime.map(|t| ft = ft.set_created(t));
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::os::windows::fs::FileTimesExt;
|
||||
meta.created().map(|t| ft = ft.set_created(t)).ok();
|
||||
cha.btime.map(|t| ft = ft.set_created(t));
|
||||
}
|
||||
|
||||
async move {
|
||||
|
|
|
|||
|
|
@ -170,10 +170,6 @@ impl Url {
|
|||
#[inline]
|
||||
pub fn pair(&self) -> Option<(Self, UrnBuf)> { Some((self.parent_url()?, self.loc.urn_owned())) }
|
||||
|
||||
#[cfg(unix)]
|
||||
#[inline]
|
||||
pub fn is_hidden(&self) -> bool { self.loc.urn().is_hidden() }
|
||||
|
||||
#[inline]
|
||||
pub fn rebase(&self, parent: &Path) -> Self {
|
||||
debug_assert!(self.is_regular());
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue