Skip to main content

git_sprout/clone/
mod.rs

1// ABOUTME: The block-cloning layer: one trait, one implementation per platform primitive.
2// ABOUTME: Support is found by attempting a clone and reading the error, never by sniffing.
3
4use std::io;
5use std::path::Path;
6
7use crate::stats::CloneBackend;
8
9#[cfg(target_os = "macos")]
10mod apfs;
11#[cfg(any(target_os = "linux", target_os = "android", windows))]
12mod reflink;
13#[cfg(not(any(
14    target_os = "macos",
15    target_os = "linux",
16    target_os = "android",
17    windows
18)))]
19mod unsupported;
20
21/// Materialises a path by sharing the source's disk blocks rather than copying them.
22pub trait BlockCloner {
23    /// Which primitive this implementation calls.
24    fn backend(&self) -> CloneBackend;
25
26    /// Clones one regular file. `destination` must not exist.
27    fn clone_file(&self, source: &Path, destination: &Path) -> io::Result<()>;
28
29    /// Clones a whole directory hierarchy in one call. `destination` must not exist.
30    fn clone_directory(&self, source: &Path, destination: &Path) -> io::Result<()>;
31
32    /// Whether `clone_directory` is cheaper than descending file by file.
33    fn clones_directories(&self) -> bool;
34}
35
36/// The cloner for the platform this binary was built for.
37pub fn for_this_platform() -> Box<dyn BlockCloner> {
38    #[cfg(target_os = "macos")]
39    {
40        Box::new(apfs::Clonefile)
41    }
42    #[cfg(any(target_os = "linux", target_os = "android"))]
43    {
44        Box::new(reflink::Reflink::new(CloneBackend::Ficlone))
45    }
46    #[cfg(windows)]
47    {
48        Box::new(reflink::Reflink::new(CloneBackend::Refs))
49    }
50    #[cfg(not(any(
51        target_os = "macos",
52        target_os = "linux",
53        target_os = "android",
54        windows
55    )))]
56    {
57        Box::new(unsupported::Unsupported)
58    }
59}