summaryrefslogtreecommitdiffstats
path: root/src/io
diff options
context:
space:
mode:
authorJeff Zhao <jeff.no.zhao@gmail.com>2022-09-03 12:45:51 -0400
committerJeff Zhao <jeff.no.zhao@gmail.com>2022-09-03 12:45:51 -0400
commite7755ad0be98540c777d86c67605386ff11522a3 (patch)
tree8b8c6c3b138fea8ded708f64e0a24073b0a1f7ce /src/io
parent596ced65ae6ae59f4e1ac2ed60246a4c5943a919 (diff)
add symlink relative
Diffstat (limited to 'src/io')
-rw-r--r--src/io/file_operation.rs23
-rw-r--r--src/io/io_observer.rs9
-rw-r--r--src/io/io_worker.rs51
3 files changed, 72 insertions, 11 deletions
diff --git a/src/io/file_operation.rs b/src/io/file_operation.rs
index 9d39716..43589aa 100644
--- a/src/io/file_operation.rs
+++ b/src/io/file_operation.rs
@@ -2,16 +2,35 @@
pub enum FileOperation {
Cut,
Copy,
- Symlink,
+ Symlink { relative: bool },
Delete,
}
+impl FileOperation {
+ pub fn actioning_str(&self) -> &'static str {
+ match *self {
+ Self::Cut => "Moving",
+ Self::Copy => "Copying",
+ Self::Symlink { .. } => "Symlinking",
+ Self::Delete => "Deleting",
+ }
+ }
+ pub fn actioned_str(&self) -> &'static str {
+ match *self {
+ Self::Cut => "moved",
+ Self::Copy => "copied",
+ Self::Symlink { .. } => "symlinked",
+ Self::Delete => "deleted",
+ }
+ }
+}
+
impl std::fmt::Display for FileOperation {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::Cut => write!(f, "Cut"),
Self::Copy => write!(f, "Copy"),
- Self::Symlink => write!(f, "Symlink"),
+ Self::Symlink { relative } => write!(f, "Symlink --relative={}", relative),
Self::Delete => write!(f, "Delete"),
}
}
diff --git a/src/io/io_observer.rs b/src/io/io_observer.rs
index 44d4248..93a1b15 100644
--- a/src/io/io_observer.rs
+++ b/src/io/io_observer.rs
@@ -1,7 +1,7 @@
use std::path;
use std::thread;
-use crate::io::{FileOperation, FileOperationProgress};
+use crate::io::FileOperationProgress;
use crate::util::format;
#[derive(Debug)]
@@ -34,12 +34,7 @@ impl IoWorkerObserver {
match self.progress.as_ref() {
None => {}
Some(progress) => {
- let op_str = match progress.kind() {
- FileOperation::Cut => "Moving",
- FileOperation::Copy => "Copying",
- FileOperation::Symlink => "Symlinking",
- FileOperation::Delete => "Deleting",
- };
+ let op_str = progress.kind().actioning_str();
let processed_size = format::file_size_to_string(progress.bytes_processed());
let total_size = format::file_size_to_string(progress.total_bytes());
diff --git a/src/io/io_worker.rs b/src/io/io_worker.rs
index f9d86d9..54385ec 100644
--- a/src/io/io_worker.rs
+++ b/src/io/io_worker.rs
@@ -44,7 +44,8 @@ impl IoWorkerThread {
match self.kind() {
FileOperation::Cut => self.paste_cut(tx),
FileOperation::Copy => self.paste_copy(tx),
- FileOperation::Symlink => self.paste_link(tx),
+ FileOperation::Symlink { relative: false } => self.paste_link_absolute(tx),
+ FileOperation::Symlink { relative: true } => self.paste_link_relative(tx),
FileOperation::Delete => self.delete(tx),
}
}
@@ -87,7 +88,7 @@ impl IoWorkerThread {
Ok(progress)
}
- fn paste_link(
+ fn paste_link_absolute(
&self,
tx: mpsc::Sender<FileOperationProgress>,
) -> io::Result<FileOperationProgress> {
@@ -112,6 +113,52 @@ impl IoWorkerThread {
Ok(progress)
}
+ fn paste_link_relative(
+ &self,
+ tx: mpsc::Sender<FileOperationProgress>,
+ ) -> io::Result<FileOperationProgress> {
+ let total_files = self.paths.len();
+ let total_bytes = total_files as u64;
+ let mut progress = FileOperationProgress::new(self.kind(), 0, total_files, 0, total_bytes);
+
+ #[cfg(unix)]
+ for src in self.paths.iter() {
+ let _ = tx.send(progress.clone());
+ let mut dest_buf = self.dest.to_path_buf();
+ if let Some(s) = src.file_name() {
+ dest_buf.push(s);
+ }
+ if !self.options.overwrite {
+ rename_filename_conflict(&mut dest_buf);
+ }
+ let mut src_components = src.components();
+ let mut dest_components = dest_buf.components();
+
+ // skip to where the two paths diverge
+ let mut non_relative_path = path::PathBuf::new();
+ for (s, d) in src_components.by_ref().zip(dest_components.by_ref()) {
+ if s != d {
+ non_relative_path.push(s);
+ break;
+ }
+ }
+
+ let mut relative_path = path::PathBuf::new();
+ for _ in dest_components {
+ relative_path.push("..");
+ }
+ relative_path.push(non_relative_path);
+ for s in src_components {
+ relative_path.push(s);
+ }
+ unix::fs::symlink(relative_path, &dest_buf)?;
+
+ progress.set_files_processed(progress.files_processed() + 1);
+ progress.set_bytes_processed(progress.bytes_processed() + 1);
+ }
+ Ok(progress)
+ }
+
fn delete(
&self,
_tx: mpsc::Sender<FileOperationProgress>,