Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation


Rust Lines Tests Benchmarks License



$ cp

A modern, GNU-compatible file copy utility rewritten in Rust.

Zero-copy kernel I/O • Parallel directory traversal • Sparse file detection • Reflink support


cargo build --release



Highlights

  Zero-Copy Kernel I/O

Uses copy_file_range, sendfile, and FICLONE (reflink) syscalls to avoid unnecessary user-space memory copies. Automatic cascading fallback.

  Parallel Directory Copy

Raw openat / mkdirat / readdir syscalls with Rayon-powered parallelism. Auto-switches at 64 entries.

  Sparse File Detection

SEEK_HOLE / SEEK_DATA to preserve file holes. Supports --sparse=auto|always|never.

  Reflink / CoW

Instant copy-on-write cloning on Btrfs, XFS via FICLONE ioctl. Transparent fallback when unsupported.

  Full Metadata Preservation

Mode, ownership, timestamps (nanosecond), xattr, ACL, and hard links with correct ordering to prevent permission races.

  Security-Hardened

Same-file detection via inode, symlink loop protection, TOCTOU-safe operations, setuid handling, path traversal prevention.




Benchmarks vs GNU cp

Averaged over 3 runs × 5 iterations — Linux 6.18 — release profile (opt-level=3, LTO)


  Benchmark GNU cp Ours Speedup
  Many small files   1000 × 1 KB 20.0 ms 12.9 ms 1.6x
  Recursive archive   500 × 4 KB, -a 12.9 ms 8.1 ms 1.6x
  Mixed sizes   50×1K + 30×100K + 15×1M + 5×10M 53.3 ms 48.7 ms 1.1x
  Large file   100 MB single file 79.2 ms 77.1 ms 1.0x
  Deep tree   5 lvl × 4 dirs × 10 files 213 ms 204 ms 1.0x
  Hardlink-heavy   50 files × 20 links 10.5 ms 10.8 ms 1.0x
  Symlink-heavy   100 files + 400 symlinks 7.6 ms 7.8 ms 1.0x
  Sparse file   100 MB, 50 MB hole 1.4 ms 2.2 ms 0.7x*

* Sparse scan overhead from SEEK_HOLE / SEEK_DATA probing on small files.


Parallel threshold sweep
Files in directory Time
32 2.8 ms
64 3.3 ms
128 3.4 ms
256 5.5 ms

Parallel I/O kicks in at 64 entries (PARALLEL_THRESHOLD in src/dir.rs).

Startup overhead

~1.8 ms for a 1-byte file copy (50 runs average).




Architecture

                        ┌─────────────────────────────────────────────────────────┐
                        │                     Copy Pipeline                       │
                        ├───────────┬──────────────┬──────────────┬──────────────┤
                        │           │              │              │              │
                        │  CLI      │   Target     │  Directory   │   Metadata   │
                        │  Parse    │  Resolution  │    Walk      │    Sync      │
                        │           │              │              │              │
                        │  Clap     │  same-file   │  fast path:  │  xattr       │
                        │  derives  │  self-copy   │  openat      │  chown       │
                        │  flags    │  path checks │  readdir     │  chmod       │
                        │  into     │              │  mkdirat     │  utimensat   │
                        │  Options  │              │              │  ACL         │
                        │           │              │  slow path:  │              │
                        │           │              │  walkdir     │              │
                        └───────────┴──────────────┴──────┬───────┴──────────────┘
                                                          │
                                              ┌───────────▼───────────┐
                                              │     Copy Engine       │
                                              │                       │
                                              │  FICLONE (reflink)    │
                                              │       ↓ fail          │
                                              │  copy_file_range      │
                                              │       ↓ fail          │
                                              │  sendfile             │
                                              │       ↓ fail          │
                                              │  read / write         │
                                              └───────────────────────┘



Usage

# Basic copy
cp source.txt dest.txt

# Recursive copy preserving everything
cp -a my_project/ backup/

# Copy with progress bar
cp --progress large_file.iso /mnt/usb/

# CoW reflink (instant on Btrfs/XFS)
cp --reflink=auto vm_disk.qcow2 snapshot.qcow2

# Sparse-aware copy
cp --sparse=always database.img /backup/

# Debug mode — shows which copy method was used
cp --debug file.dat /dst/

All CLI flags
Flag Description
-a, --archive Same as -dR --preserve=all
-R, -r, --recursive Copy directories recursively
-p Preserve mode, ownership, timestamps
-f, --force Remove destination before copy if needed
-n, --no-clobber Do not overwrite existing files
-u, --update Copy only when source is newer
-v, --verbose Explain what is being done
-l, --link Hard link files instead of copying
-s, --symbolic-link Create symlinks instead of copying
-L, --dereference Always follow symlinks in source
-P, --no-dereference Never follow symlinks in source
--preserve=ATTR Preserve: mode, ownership, timestamps, links, xattr, all
--no-preserve=ATTR Don't preserve specified attributes
--sparse=WHEN Sparse file creation: auto, always, never
--reflink=WHEN CoW cloning: auto, always, never
--backup[=CONTROL] Backup: numbered, existing, simple, none
-S, --suffix Override backup suffix (default: ~)
-x, --one-file-system Stay on the same filesystem
-t, --target-directory Copy all sources into directory
-T, --no-target-directory Treat destination as normal file
--parents Replicate source path structure under dest
--attributes-only Copy metadata only, no file data
--remove-destination Remove each destination before copy
--debug Show copy method used (implies -v)
--progress Show progress bar during copy



Test Suite

168 tests + 19 benchmarks — all passing

Suite Tests   Suite Tests
security 38 unit_metadata 9
unit_copy 24 unit_sparse 9
unit_options 18 unit_parallel 8
unit_util 18 unit_engine 9
integration 12 unit_backup 11
unit_dir 12 benchmarks 19
# Run all tests
cargo test --release

# Run benchmarks with output
cargo test --release bench_ -- --nocapture



Project Structure

src/
├── main.rs ··········· Entry point, CLI dispatch                125 lines
├── cli.rs ············ Clap-derived CLI definitions              201 lines
├── options.rs ········ CopyOptions resolution from flags         236 lines
├── dir.rs ············ Recursive directory copy (fast + slow)   1030 lines
├── copy.rs ··········· Single file copy logic                    335 lines
├── engine.rs ········· Copy engine (reflink/cfr/sendfile/rw)     199 lines
├── metadata.rs ······· Permission, xattr, ACL, timestamps       225 lines
├── sparse.rs ········· Sparse file hole detection + copy         192 lines
├── error.rs ·········· Error types (thiserror)                   145 lines
├── util.rs ··········· Path utilities, target resolution         120 lines
├── backup.rs ········· Backup file creation                       77 lines
└── progress.rs ······· Progress bar (indicatif)                   24 lines

tests/
├── common/mod.rs ····· Shared test harness (Env fixture)         194 lines
└── 12 test files ····· 168 tests + 19 benchmarks               3560 lines

html/
└── index.html ········ Project showcase page                    1475 lines



Installation

# Build from source
git clone https://github.com/yrbane/cp.git
cd cp
cargo build --release
# Binary is at target/release/cp



Contributing

Contributions are welcome! Feel free to open an issue or submit a pull request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/my-feature)
  3. Run the tests (cargo test --release)
  4. Commit your changes
  5. Push and open a pull request



License

This project is released into the public domain under the Unlicense. You are free to copy, modify, publish, use, compile, sell, or distribute this software for any purpose, commercial or non-commercial, and by any means.




Built with Rust — Unlicense

About

A modern GNU-compatible cp implementation in Rust — zero-copy I/O, parallel directory copy, sparse file detection, reflink support

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages