From f294881de68a2f1df1e3764adf3725f028d10932 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Mon, 18 Sep 2023 08:35:34 +0800 Subject: [PATCH] .. --- app/src/executor.rs | 2 +- config/docs/keymap.md | 1 - core/src/tasks/scheduler.rs | 11 ++++-- core/src/tasks/workers/file.rs | 70 +++++++++++++++++++++++----------- 4 files changed, 56 insertions(+), 28 deletions(-) diff --git a/app/src/executor.rs b/app/src/executor.rs index e0229e2a..bb4d4587 100644 --- a/app/src/executor.rs +++ b/app/src/executor.rs @@ -105,7 +105,7 @@ impl Executor { if *cut { cx.tasks.file_cut(src, dest, force) } else { - cx.tasks.file_copy(src, dest, force, exec.named.contains_key("follow")) + cx.tasks.file_copy(src, dest, force) } } "link" => { diff --git a/config/docs/keymap.md b/config/docs/keymap.md index c6ebb0f7..81e7025f 100644 --- a/config/docs/keymap.md +++ b/config/docs/keymap.md @@ -56,7 +56,6 @@ - paste: Paste the files. - `--force`: Overwrite the destination file if it exists. - - `--follow`: Copy the file pointed to by a symbolic link, rather than the link itself. Only valid during copying. - remove: Move the files to the trash/recycle bin. diff --git a/core/src/tasks/scheduler.rs b/core/src/tasks/scheduler.rs index 5a9484c3..bb600908 100644 --- a/core/src/tasks/scheduler.rs +++ b/core/src/tasks/scheduler.rs @@ -218,7 +218,7 @@ impl Scheduler { }); } - pub(super) fn file_copy(&self, from: Url, mut to: Url, force: bool, follow: bool) { + pub(super) fn file_copy(&self, from: Url, mut to: Url, force: bool) { let name = format!("Copy {:?} to {:?}", from, to); let id = self.running.write().add(name); @@ -228,13 +228,13 @@ impl Scheduler { if !force { to = unique_path(to).await; } - file.paste(FileOpPaste { id, from, to, cut: false, follow, retry: 0 }).await.ok(); + file.paste(FileOpPaste { id, from, to, cut: false, follow: true, retry: 0 }).await.ok(); } .boxed() }); } - pub(super) fn file_link(&self, from: Url, mut to: Url, force: bool) { + pub(super) fn file_link(&self, from: Url, mut to: Url, force: bool, relative: bool) { let name = format!("Link {from:?} to {to:?}"); let id = self.running.write().add(name); @@ -244,7 +244,10 @@ impl Scheduler { if !force { to = unique_path(to).await; } - file.link(FileOpLink { id, from, to }).await.ok(); + file + .link(FileOpLink { id, from, to, meta: None, resolve: false, relative, delete: false }) + .await + .ok(); } .boxed() }); diff --git a/core/src/tasks/workers/file.rs b/core/src/tasks/workers/file.rs index 37585e2e..cde14129 100644 --- a/core/src/tasks/workers/file.rs +++ b/core/src/tasks/workers/file.rs @@ -1,9 +1,9 @@ -use std::{collections::VecDeque, fs::Metadata, path::{Path, PathBuf}}; +use std::{borrow::Cow, collections::VecDeque, fs::Metadata, path::{Path, PathBuf}}; use anyhow::Result; use config::TASKS; use futures::{future::BoxFuture, FutureExt}; -use shared::{calculate_size, copy_with_progress, Url}; +use shared::{calculate_size, copy_with_progress, path_relative_to, Url}; use tokio::{fs, io::{self, ErrorKind::{AlreadyExists, NotFound}}, sync::mpsc}; use tracing::trace; @@ -36,11 +36,13 @@ pub(crate) struct FileOpPaste { #[derive(Clone, Debug)] pub(crate) struct FileOpLink { - pub id: usize, - pub from: Url, - pub to: Url, - pub cut: bool, - pub length: u64, + pub id: usize, + pub from: Url, + pub to: Url, + pub meta: Option, + pub resolve: bool, + pub relative: bool, + pub delete: bool, } #[derive(Clone, Debug)] @@ -114,15 +116,23 @@ impl File { self.sch.send(TaskOp::Adv(task.id, 1, 0))?; } FileOp::Link(task) => { - let src = match fs::read_link(&task.from).await { - Ok(src) => src, - Err(e) if e.kind() == NotFound => { - self.log(task.id, format!("Link task partially done: {:?}", task))?; - return Ok(self.sch.send(TaskOp::Adv(task.id, 1, task.length))?); + let meta = task.meta.as_ref().unwrap(); + + let src = if task.resolve { + match fs::read_link(&task.from).await { + Ok(p) => Cow::Owned(p), + Err(e) if e.kind() == NotFound => { + self.log(task.id, format!("Link task partially done: {:?}", task))?; + return Ok(self.sch.send(TaskOp::Adv(task.id, 1, meta.len()))?); + } + Err(e) => Err(e)?, } - Err(e) => Err(e)?, + } else { + Cow::Borrowed(task.from.as_path()) }; + let src = if task.relative { path_relative_to(&src, &task.to) } else { src }; + match fs::remove_file(&task.to).await { Err(e) if e.kind() != NotFound => Err(e)?, _ => { @@ -132,15 +142,19 @@ impl File { } #[cfg(target_os = "windows")] { - fs::symlink_file(src, &task.to).await? + if meta.is_dir() { + fs::symlink_dir(src, &task.to).await? + } else { + fs::symlink_file(src, &task.to).await? + } } } } - if task.cut { + if task.delete { fs::remove_file(&task.from).await.ok(); } - self.sch.send(TaskOp::Adv(task.id, 1, task.length))?; + self.sch.send(TaskOp::Adv(task.id, 1, meta.len()))?; } FileOp::Delete(task) => { if let Err(e) = fs::remove_file(&task.target).await { @@ -192,7 +206,7 @@ impl File { if meta.is_file() { self.tx.send(FileOp::Paste(task)).await?; } else if meta.is_symlink() { - self.tx.send(FileOp::Link(task.to_link(meta.len()))).await?; + self.tx.send(FileOp::Link(task.to_link(meta))).await?; } return self.done(id); } @@ -237,16 +251,20 @@ impl File { if meta.is_file() { self.tx.send(FileOp::Paste(task.clone())).await?; } else if meta.is_symlink() { - self.tx.send(FileOp::Link(task.to_link(meta.len()))).await?; + self.tx.send(FileOp::Link(task.to_link(meta))).await?; } } } self.done(task.id) } - pub(crate) async fn link(&self, task: FileOpLink) -> Result<()> { + pub(crate) async fn link(&self, mut task: FileOpLink) -> Result<()> { let id = task.id; - self.sch.send(TaskOp::New(id, 0))?; + if task.meta.is_none() { + task.meta = Some(fs::symlink_metadata(&task.from).await?); + } + + self.sch.send(TaskOp::New(id, task.meta.as_ref().unwrap().len()))?; self.tx.send(FileOp::Link(task)).await?; self.done(id) } @@ -328,7 +346,15 @@ impl File { } impl FileOpPaste { - fn to_link(&self, length: u64) -> FileOpLink { - FileOpLink { id: self.id, from: self.from.clone(), to: self.to.clone(), cut: self.cut, length } + fn to_link(&self, meta: Metadata) -> FileOpLink { + FileOpLink { + id: self.id, + from: self.from.clone(), + to: self.to.clone(), + meta: Some(meta), + resolve: true, + relative: false, + delete: self.cut, + } } }