mitosis/clone_backend/
copy.rs1use super::{
5 apparent_size, clone_tree, create_dst, fs_create_dir, fs_remove_dir, fs_rename_dir, io_error,
6 CloneBackend,
7};
8use crate::error::Result;
9use std::fs::{File, Metadata};
10use std::path::Path;
11
12pub const SLOW_WARNING: &str =
14 "backend \"copy\" makes full copies; clones are slow and use full disk space";
15
16pub struct CopyBackend;
17
18impl CloneBackend for CopyBackend {
19 fn name(&self) -> &'static str {
20 "copy"
21 }
22
23 fn check_supported(&self, _path: &Path) -> Result<()> {
24 Ok(())
25 }
26
27 fn clone_dir(&self, src: &Path, dst: &Path) -> Result<()> {
28 clone_tree(src, dst, ©_file)
29 }
30
31 fn create_dir(&self, path: &Path) -> Result<()> {
32 fs_create_dir(path)
33 }
34
35 fn remove_dir(&self, path: &Path) -> Result<()> {
36 fs_remove_dir(path)
37 }
38
39 fn rename_dir(&self, from: &Path, to: &Path) -> Result<()> {
40 fs_rename_dir(from, to)
41 }
42
43 fn private_size(&self, path: &Path) -> Option<u64> {
45 apparent_size(path).ok()
46 }
47}
48
49pub(super) fn copy_file(src: &Path, dst: &Path, md: &Metadata) -> Result<()> {
51 let mut s = File::open(src).map_err(|e| io_error("open", src, e))?;
52 let mut d = create_dst(dst, md)?;
53 std::io::copy(&mut s, &mut d).map_err(|e| io_error("copy", src, e))?;
54 Ok(())
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60 use std::fs::{create_dir, read_link, read_to_string, symlink_metadata, write};
61
62 #[test]
63 fn copy_backend_clone_is_isolated() {
64 let tmp = tempfile::tempdir().unwrap();
65 let (src, dst) = (tmp.path().join("src"), tmp.path().join("dst"));
66 create_dir(&src).unwrap();
67 write(src.join("a.txt"), "hello").unwrap();
68 create_dir(src.join("sub")).unwrap();
69 write(src.join("sub/b.txt"), "x".repeat(1_000_000)).unwrap();
70 std::os::unix::fs::symlink("/elsewhere", src.join("link")).unwrap();
71
72 CopyBackend.check_supported(tmp.path()).unwrap();
73 CopyBackend.clone_dir(&src, &dst).unwrap();
74 write(dst.join("a.txt"), "changed").unwrap();
75 assert_eq!(read_to_string(src.join("a.txt")).unwrap(), "hello");
76 assert!(symlink_metadata(dst.join("link"))
77 .unwrap()
78 .file_type()
79 .is_symlink());
80 assert_eq!(
81 read_link(dst.join("link")).unwrap(),
82 Path::new("/elsewhere")
83 );
84 assert_eq!(CopyBackend.private_size(&dst), Some(1_000_005 + 2));
85 assert!(CopyBackend.clone_dir(&src, &dst).is_err());
86 }
87}