This commit is contained in:
sxyazi 2023-09-18 08:35:34 +08:00
parent fa6e57d0ce
commit f294881de6
No known key found for this signature in database
4 changed files with 56 additions and 28 deletions

View file

@ -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" => {

View file

@ -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.

View file

@ -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()
});

View file

@ -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<Metadata>,
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,
}
}
}