ctree

Crates.ioctree
lib.rsctree
version0.0.2
created_at2025-06-09 03:04:50.956845+00
updated_at2025-12-06 09:31:12.303391+00
descriptionA copy-on-write directory library for Rust with fast reflink cloning
homepage
repositoryhttps://github.com/cortesi/clonetree
max_upload_size
id1705459
size24,229
Aldo Cortesi (cortesi)

documentation

README

Discord Crates.io docs.rs

clonetree

A copy‑on‑write directory library for Rust

clonetree is a Rust crate for fast directory duplication. It uses filesystem‑level reflinks so large trees are cloned quickly and consume no extra space until files diverge.


Community

Want to contribute? Have ideas or feature requests? Come tell us about it on Discord.


Highlights

  • Fast copy‑on‑write clone on APFS, Btrfs, XFS, bcachefs, overlayfs, ReFS…

  • Powered by reflink-copy for portable block‑cloning.

  • Flexible glob patterns to include/exclude files (uses ! prefix for exclusions).

  • Graceful fallback to std::fs::copy when reflinks are unsupported.

  • Symlink preservation — symbolic links are recreated with their original targets.

  • Empty directory preservation — empty directories are included in the clone.

  • Pure Rust, no unsafe code, minimal deps.


Library quick start

Clone only Rust source files under src/ into ./sandbox, while excluding unit tests. This demonstrates the precedence rules from the ignore crate: later patterns override earlier ones.

use clonetree::{clone_tree, Options};

fn main() -> anyhow::Result<()> {
    // Include all source files but drop tests
    let opts = Options::new()
        .glob("src/**")         // positive include
        .glob("!src/tests/**"); // negative exclude; overrides the line above

    clone_tree("./", "./sandbox", &opts)?;
    Ok(())
}

Glob syntax

clonetree accepts the same glob rules as a single line in a .gitignore file. Prefix a pattern with ! to exclude matching paths instead of including them.

Pattern Description
*.rs All Rust source files in the current directory
**/*.toml Any .toml file at any depth
!target/** Exclude Cargo build artefacts
images/**/thumb_* Every thumb_* file under images/ recursively

Rules:

  • * matches any sequence of characters except path separators.
  • ** matches across directory boundaries.
  • ? matches exactly one character.
  • A trailing / restricts the pattern to directories only.
  • Patterns are evaluated in the order they are given; later patterns can override earlier ones (precedence follows the ignore crate).

ctree ‑ command‑line tool

The crate ships with a convenience binary so users can benefit without writing code.

Install

cargo install ctree

Semantics

ctree copies a directory to a specified destination. The source must be a directory, and the destination must not exist.

Basic usage

ctree <SRC> <DEST> [OPTIONS]

OPTIONS:
  -g, --glob <GLOB>      Match or exclude glob (repeatable)
      --strategy <auto|single-call|full-traversal>
                         Cloning strategy (defaults to auto)
  -q, --quiet            Suppress progress output
  -h, --help             Show this help

Example: snapshot a repo while excluding Git metadata and build output:

ctree . ./sandbox \
  --glob '!target/**' \
  --glob '!.git/**'

Strategies

clonetree offers three strategies:

  • auto (default): on macOS/APFS it issues a single clonefile call on the root directory (fastest, atomic, COW). Else it falls back to traversal.
  • single-call: force the one-shot clone (macOS only; destination must not exist; incompatible with glob filters).
  • full-traversal: user-space walk that reflinks each file individually (works everywhere and honors glob filters).

Symlink handling

Symbolic links are preserved as symbolic links — they are not followed or dereferenced. The link target is copied verbatim, so relative symlinks maintain their relative paths in the cloned tree.

Strategy Symlink behaviour
single-call Preserved by the kernel's clonefile(2) (macOS only)
full-traversal Recreated via symlink(2) (Unix) or CreateSymbolicLink (Windows)

Filesystem support matrix

Via reflink-copy

OS / FS Reflink supported API used Behaviour
macOS 10.13+ / APFS clonefile(2) COW clone
iOS / APFS clonefile(2) COW clone
Linux 6.7+ / Btrfs FICLONE ioctl COW clone
Linux 5.4+ / XFS (reflink=1) FICLONE ioctl COW clone
Linux 6.1+ / bcachefs remap_file_range COW clone
Linux 5.13+ / overlayfs remap_file_range COW clone
Windows Server 2016+ / ReFS FSCTL_DUPLICATE_EXTENTS_TO_FILE COW clone
ext4 (Ubuntu/Fedora default) Byte‑for‑byte copy
Commit count: 17

cargo fmt