From 8f410d1ead74b979481f1488a4dcddd33ea829c7 Mon Sep 17 00:00:00 2001
From: Ben Bridle <bridle.benjamin@gmail.com>
Date: Thu, 25 Aug 2022 21:27:39 +1200
Subject: Initial commit

---
 src/operations/cp.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)
 create mode 100644 src/operations/cp.rs

(limited to 'src/operations/cp.rs')

diff --git a/src/operations/cp.rs b/src/operations/cp.rs
new file mode 100644
index 0000000..be43826
--- /dev/null
+++ b/src/operations/cp.rs
@@ -0,0 +1,62 @@
+use crate::make_parent_directory;
+use crate::{get_entry, get_optional_entry, list_directory};
+use crate::{EntryType, EntryWriteError};
+use std::path::Path;
+
+pub fn copy<P, Q>(source_path: P, target_path: Q) -> Result<(), EntryWriteError>
+where
+    P: AsRef<Path>,
+    Q: AsRef<Path>,
+{
+    let source = get_entry(&source_path)?;
+    let target = get_optional_entry(&target_path)?;
+    let target_type = target.and_then(|e| Some(e.entry_type));
+
+    match (source.entry_type, target_type) {
+        (EntryType::File, Some(EntryType::File)) => {
+            copy_file(source_path, target_path)?;
+        }
+        (EntryType::File, Some(EntryType::Directory)) => {
+            let target_path = target_path.as_ref().join(source.name);
+            copy_file(source_path, target_path)?;
+        }
+        (EntryType::File, None) => {
+            make_parent_directory(&target_path)?;
+            copy_file(source_path, target_path)?;
+        }
+        (EntryType::Directory, Some(EntryType::File)) => {
+            std::fs::remove_file(&target_path)?;
+            copy_directory(&source_path, &target_path)?;
+        }
+        (EntryType::Directory, Some(EntryType::Directory)) => {
+            let target_path = target_path.as_ref().join(source.name);
+            copy_directory(source_path, target_path)?;
+        }
+        (EntryType::Directory, None) => {
+            make_parent_directory(&target_path)?;
+            copy_directory(source_path, target_path)?;
+        }
+    }
+    Ok(())
+}
+
+fn copy_file<P, Q>(source_path: P, target_path: Q) -> Result<(), EntryWriteError>
+where
+    P: AsRef<Path>,
+    Q: AsRef<Path>,
+{
+    std::fs::copy(source_path, target_path)?;
+    Ok(())
+}
+
+fn copy_directory<P, Q>(source_path: P, target_path: Q) -> Result<(), EntryWriteError>
+where
+    P: AsRef<Path>,
+    Q: AsRef<Path>,
+{
+    for entry in list_directory(&source_path)? {
+        let target_path = target_path.as_ref().join(entry.name);
+        copy(entry.path, &target_path)?;
+    }
+    Ok(())
+}
-- 
cgit v1.2.3-70-g09d2