cp and rsync crawl on hard drives
They read files in directory order, forcing the disk head to jump all over the platter. fast-copy sorts every file by its physical block offset first, so the drive reads in one smooth sweep.
fast-copy is a Python CLI that squeezes every MB/s out of your hardware — block-order I/O, SSH tar pipe streaming, content-aware deduplication, sparse-file awareness, and a tamper-resistant audit log under sudo. 3–5× faster than scp/rsync/SFTP for remote transfers. No bloat. Just fast.
What it does
fast-copy is a command-line tool that copies files and folders as fast as your disks and network physically allow — locally, to USB drives and NAS boxes, or across SSH. It exists because the everyday tools leave most of your hardware's speed on the table. Here's what it fixes:
They read files in directory order, forcing the disk head to jump all over the platter. fast-copy sorts every file by its physical block offset first, so the drive reads in one smooth sweep.
Per-file overhead murders throughput. fast-copy bundles small files into streamed tar batches, so 10,000 little files move as fast as one big one.
fast-copy fingerprints content with xxHash-128, copies each unique file once, and reflinks or hard-links the rest. Identical data is never written twice.
SFTP's chunked protocol is the bottleneck, not your network. fast-copy streams a raw SSH tar pipe with zero temp files — typically 3–5× faster on the same link.
A pre-flight space check refuses to start a copy that can't finish, and every file is hash-verified after landing — so a cheap USB drive can't corrupt your data unnoticed.
Sparse-file awareness (SEEK_DATA / SEEK_HOLE) skips the unallocated holes entirely. A 2.3 TB VM image with 12 GB of real data copies 12 GB, not 2.3 TB.
Get started
Run directly with Python 3.8+, or grab a standalone binary from GitHub Releases — no runtime required on the target machine.
# requires Python 3.8+ python fast_copy.py <source> <destination> # SSH support pip install paramiko # Optional: ~10x faster hashing pip install xxhash
# Linux / macOS — no Python needed curl -L https://github.com/gekap/fast-copy/releases/latest/download/fast_copy-linux -o fast-copy chmod +x fast-copy && ./fast-copy --help # Windows — download fast_copy-windows.exe # from the GitHub Releases page fast-copy.exe "C:\Projects\my-app" "E:\Backup\my-app"
Core features
Every feature in fast-copy exists because it moves bits faster or wastes fewer of them. No GUI. No phone-home. No surprises.
Uses FIEMAP on Linux, fcntl on macOS, and FSCTL on Windows to sort files by physical disk offset before reading — eliminating random-seek overhead and maximising sequential throughput.
Files are fingerprinted with xxHash-128 — the fastest non-cryptographic hash available — before writing. Identical content is skipped, saving bandwidth and write cycles.
Remote transfers bypass SFTP entirely. fast-copy pipes a tar stream over SSH for a true single-hop server-to-server transfer — significantly faster and writing zero bytes to temp storage on either end.
On btrfs / XFS / APFS / bcachefs, files are cloned via FICLONE / clonefile(2) — metadata-only CoW. A 10 GB copy on the same volume completes in milliseconds.
VM disk images and Longhorn replicas are auto-detected via SEEK_DATA / SEEK_HOLE. Holes never hit the wire or the destination disk — 2.3 TB logical → 12 GB on disk on real backups.
--use-sudo + Audit LogRe-execs under sudo for root-only paths, writes a hidden chattr +i JSONL audit log of every elevated run. Even root can't quietly delete a record.
Instead of thousands of individual write calls, small files are bundled into a tar stream and block-written in one pass, then extracted locally. Dramatically improves throughput on directories full of tiny files.
After every transfer, fast-copy re-hashes the destination and compares against the source manifest. Corrupted or incomplete copies are reported immediately, before you delete the source.
First-class support for Linux, macOS, and Windows. PyInstaller standalone binaries on every GitHub release — no Python runtime required on the target machine.
Before writing a single byte, fast-copy calculates exactly how much unique data will land on the destination — accounting for deduplication and sparse-file holes — and verifies the target has enough free space. Works for local paths, USB drives, and remote SSH destinations (walking parent directories as fallback). Copy jobs never fail halfway through a 500 GB transfer because the drive was full.
Under the hood
fast-copy runs a five-stage pipeline optimised for maximum I/O efficiency on every transfer.
Query the OS for the physical disk offset of every file. Sort the read queue to minimise head movement and maximise sequential I/O.
Hash each file with xxHash-128. Cross-reference against the destination manifest. Flag duplicates before a single byte is written.
Calculate exactly how much unique data will land on the destination — after dedup and sparse-hole elision — and verify the target has enough free space.
Write files in block-sorted order — locally or via SSH tar pipe. Small files are bundled first to coalesce write calls into large sequential blocks.
Re-hash the destination and diff against the source manifest. Report any mismatch instantly.
How it stacks up
A feature-level comparison with the tools you're probably already using.
| Feature | fast-copy | rsync | cp (Unix) | robocopy (Win) | scp / SFTP |
|---|---|---|---|---|---|
| Block-order I/O (physical offset sort) | ✓ | ✗ | ✗ | ✗ | ✗ |
| Content deduplication (xxHash-128) | ✓ | checksum only | ✗ | ✗ | ✗ |
| SSH tar pipe (single hop) | ✓ | ✗ | ✗ | ✗ | ✗ |
| Zero temp files on remote transfer | ✓ | partial | ✗ | ✗ | ✗ |
| Reflink / CoW clones (btrfs/XFS/APFS) | ✓ | ✗ | ✗ | ✗ | ✗ |
| Sparse-file awareness (SEEK_DATA) | ✓ | partial | ✗ | ✗ | ✗ |
| Tamper-resistant audit log under sudo | ✓ | ✗ | ✗ | ✗ | ✗ |
| Post-copy hash verification | ✓ | --checksum | ✗ | ✗ | ✗ |
| Pre-flight space check (before writing) | ✓ | ✗ | ✗ | ✗ | ✗ |
| Small-file bundling | ✓ | ✗ | ✗ | ✗ | ✗ |
| Standalone binary (no runtime needed) | ✓ | system pkg | system pkg | ✓ | system pkg |
| Platform support | Linux/macOS/Win | Linux/macOS | Linux/macOS | Windows only | Linux/macOS/Win |
-R, --keep-parents preserves each source's full parent path under the destination (rsync -R semantics). fast-copy -R /etc /var/log dst/ now produces dst/etc/ and dst/var/log/ instead of dst/etc/ and dst/log/.pvc-* replicas with unique names, but wrong for incident snapshots: a future analyst staring at dst/log/ can't tell whether the original was /var/log or /usr/local/log, and two sources sharing a basename would silently merge. -R preserves provenance.--use-sudo hardening, or SSH transfers.fast-copy --use-sudo -R /etc /var/log /home/operator /mnt/snap/ — snapshot tree mirrors the source filesystem exactly, so every analyst tool (Volatility, plaso, sleuthkit) recognizes the layout.fast-copy SRC1 SRC2 … DST/. Shell glob expands to N source trees, each preserved by basename by default. -R opts into full-path layout.SEEK_DATA / SEEK_HOLE. 2.3 TB logical trees with 12 GB of real data no longer reject 900 GB destinations.--use-sudo self-elevation + tamper-resistant audit log (v3.1.0) — re-execs under sudo and writes a hidden chattr +i JSONL audit trail. Even root can't quietly delete a record.O_NOFOLLOW on every destination + source (v3.1.1) — planted symlinks can no longer redirect root-privileged I/O to /root/.bashrc or exfiltrate /etc/shadow.--update refused under sudo (v3.1.1) plus --update-sha256 <hex> for out-of-band integrity pinning. Compromised release can't auto-trojan root.--use-sudo refuses to elevate if fast_copy.py or its directory is group/world-writable. Closes the "edit the script and wait" trojan path.FICLONE / clonefile.Documentation
python fast_copy.py [options] source [source ...] destination
When two or more positionals are given, the last is the destination and earlier ones are sources (cp -r style). Each source can be a local path, a glob pattern, or a remote SSH path in the form user@host:/path.
| Argument | Description |
|---|---|
| source | One or more source folders, files, globs, or remote user@host:/path |
| destination | Destination path or remote user@host:/path |
| Flag | Default | Description |
|---|---|---|
| --buffer BUFFER | 64 | Buffer size in MB. 8 for low-memory systems, 128 for fast SSDs. |
| --threads THREADS | 4 | Threads used for hashing and physical layout resolution. |
| --dry-run | — | Show the copy plan without writing any data. |
| --no-verify | — | Skip post-copy hash verification. |
| --no-dedup | — | Disable deduplication. Faster for known-unique files. |
| --hash ALGO | auto | Hash algorithm: auto (xxh128 if installed, else sha256), xxh128, sha256. |
| --no-cache | — | Disable the persistent SQLite hash cache. |
| --force | — | Skip pre-flight space check. |
| --overwrite | — | Overwrite all files, skipping identical-file detection. |
| --exclude EXCLUDE | — | Exclude files/dirs by name or glob (repeatable). |
| -R, --keep-parents | — | Preserve each source's full parent path under the destination (rsync -R semantics, v3.1.2+). Multi-source and glob copies only — single-source copies emit a one-line note and are unchanged. fast-copy -R /etc /var/log dst/ produces dst/etc/ and dst/var/log/ instead of dst/etc/ and dst/log/. Use for incident snapshots and forensic captures where source provenance must be preserved. |
| --use-sudo | — | Re-exec self under sudo if not already root (v3.1.0+, hardened in v3.1.1+). Refuses to elevate if the script or its directory is group/world-writable. Linux/macOS only. |
| --update [VERSION] | — | Download and install latest (or a specific version). Refused under sudo (v3.1.1+). Supports --update-sha256 <hex> for out-of-band integrity pinning (v3.1.1+). |
| Flag | Description |
|---|---|
| --ssh-src-port PORT | SSH port for the remote source (default: 22) |
| --ssh-src-key PATH | Path to SSH private key for the remote source |
| --ssh-src-password | Prompt for SSH password for the remote source |
| Flag | Description |
|---|---|
| --ssh-dst-port PORT | SSH port for the remote destination (default: 22) |
| --ssh-dst-key PATH | Path to SSH private key for the remote destination |
| --ssh-dst-password | Prompt for SSH password for the remote destination |
| Flag | Description |
|---|---|
| -z, --compress | Enable SSH compression. Recommended for slow or high-latency links. |
python fast_copy.py /home/kai/my-app /mnt/usb/my-appfast-copy /var/lib/longhorn/replicas/pvc-* /mnt/backup_pvc/python fast_copy.py ~/Downloads/Rocky-10.0-x86_64-dvd1.iso /mnt/usb/python fast_copy.py "~/Downloads/*.zip" /mnt/usb/zips/
python fast_copy.py "C:\Projects\my-app" "E:\Backup\my-app"
--use-sudo re-execs the tool under sudo. The audit log is written to ~$SUDO_USER/.fast_copy_audit.jsonl with chattr +i after every write — even root can't quietly delete a record.fast-copy --use-sudo /etc /var/log /home/operator /mnt/incident_snapshot/Multi-source CLI (v3.1.0+) accepts any number of source paths followed by the destination; each source is copied as its own subtree under the destination, preserving its basename.
paramiko: pip install paramiko.tar available, all transfers use raw SSH channels instead of SFTP — bypassing protocol overhead and working even on servers with SFTP disabled (e.g. Synology NAS).python fast_copy.py /data user@server:/backup/data --ssh-dst-passwordpython fast_copy.py user@server:/data /local/backup --ssh-src-passwordpython fast_copy.py user@src-host:/data admin@dst-host:/backup/data \
--ssh-src-password --ssh-dst-passwordpython fast_copy.py user@host:/data /local \
--ssh-src-port 2222 --ssh-src-key ~/.ssh/id_ed25519python fast_copy.py /local/data "user@nas:/volume1/Shared Folder/backup" \ --ssh-dst-port 2205 --ssh-dst-password
python fast_copy.py /data /mnt/usb/data --dry-runpython fast_copy.py /data /mnt/usb/data --no-deduppython fast_copy.py /project /mnt/usb/project \
--exclude node_modules --exclude .gitpython fast_copy.py /data /mnt/usb/data --buffer 8fast-copy --update --update-sha256 <64-hex-from-release-page>
25.8% of files were duplicates. Files read in physical disk order; small files bundled into block streams.
SEEK_DATA / SEEK_HOLE walked data-extents only. Pre-flight space check used allocated count, so a 900 GB destination accepted the job.
51.2% duplicates. Streamed in 6 tar batches of ~100 MB with streaming extraction (no temp files). All 91,669 files verified after copy.
3× faster than SFTP-based transfer. Remote hard links created via batched Python script over SSH (5,000 links per batch).
Questions
The things people usually want to know before trying fast-copy.
For remote transfers, typically 3–5× faster than scp/rsync/SFTP. SFTP often tops out at 1–2 MB/s because of its chunked protocol; fast-copy streams a raw SSH tar pipe instead. Locally, the win comes from reading files in physical disk order and skipping duplicate and sparse data — on the same volume with a reflink-capable filesystem, copies can finish in milliseconds.
No. fast-copy runs on your side and drives the remote over a normal SSH connection using the tar and ssh that are already there — no daemon, agent, or matching install required on the remote. It even works against busybox-based systems like Synology NAS.
No. The source is only ever read. fast-copy never writes to, renames, or deletes anything in the source tree — it builds the copy at the destination and verifies it.
Not necessarily. You can grab the standalone binary from the releases page (no runtime needed), or run it as python fast_copy.py if you already have Python 3. Both behave identically.
Identical files are stored once and the duplicates become reflinks (copy-on-write clones) or hard links on filesystems that support them — the files still appear normally, they just share underlying data. On link-incapable drives like FAT32 or exFAT, nothing is linked; fast-copy simply reports the bandwidth it saved by not re-reading the duplicate.
Yes. The --use-sudo flow is security-hardened: it uses O_NOFOLLOW to resist symlink attacks, runs a script-permission preflight, refuses self-update while elevated, and writes a tamper-resistant (chattr +i) JSONL audit log recording who copied what.
Linux, macOS and Windows — each with native I/O optimizations (FIEMAP on Linux, fcntl on macOS, FSCTL on Windows). Windows long paths over 260 characters are handled too.
No. There is no telemetry, no analytics, and no network calls beyond the SSH connection you explicitly ask for. It's open source under Apache 2.0 — you can read every line.
No. fast-copy is completely free and open source under the Apache 2.0 license. There's no paid tier, no license fee, and nothing locked behind a paywall — every feature you see is the whole tool.
Get in touch
Plain text only — no uploads, no tracking pixels. Spam protected by Cloudflare Turnstile. Goes straight to my inbox.
Open source
fast-copy is Apache 2.0 licensed. Contributions, bug reports, and feature ideas are all welcome on GitHub.