rsync re-implemented in Rust. Wire-compatible with upstream rsync 3.4.2 (and back-compat with 3.4.1, protocol 32), works as a drop-in replacement.
Binary name: oc-rsync - installs alongside system rsync without conflict.
Release: 0.6.2 (alpha) - Wire-compatible drop-in replacement for rsync 3.4.2 (and 3.4.1, protocols 28-32).
All transfer modes (local, SSH, daemon), delta algorithm, metadata preservation, incremental recursion, and compression are complete. Interop tested against upstream rsync 3.0.9, 3.1.3, and 3.4.1.
| Component | Status |
|---|---|
| Transfer | Local, SSH, daemon push/pull |
| Delta | Rolling + strong checksums, block matching |
| Metadata | Permissions, timestamps, ownership, ACLs (-A), xattrs (-X) |
| File handling | Sparse, hardlinks, symlinks, devices, FIFOs |
| Deletion | --delete (before/during/after/delay), --delete-excluded |
| Compression | zlib, zstd, lz4 with level control and auto-negotiation |
| Checksums | MD4, MD5, XXH3/XXH128 with SIMD (AVX2, SSE2, NEON) |
| Incremental recursion | Pull and push directions, enabled by default |
| Batch | --write-batch / --read-batch roundtrip |
| Daemon | Negotiation, auth, modules, chroot, syslog, pre/post-xfer exec |
| Filtering | --filter, --exclude, --include, .rsync-filter, --files-from |
| Reference dirs | --compare-dest, --link-dest, --copy-dest |
| Options | --delay-updates, --inplace, --partial, --iconv, fuzzy matching |
| I/O | io_uring (Linux 5.6+), copy_file_range, clonefile (macOS), adaptive buffers |
| Platforms | Linux, macOS (full); Windows (NTFS DACL partial, xattrs via NTFS ADS, IOCP socket I/O; no symlinks/devices) |
The primary platform is Linux. macOS is well-supported with parity for all metadata, ACL, and xattr features, including AppleDouble (._foo) resource-fork preservation. Windows builds and runs core transfer modes with NTFS DACL preservation (via windows-rs GetNamedSecurityInfoW/SetNamedSecurityInfoW, currently Tier 1C partial - see docs/platform-notes.md for the Windows ACL behavior summary, the –acls entry in docs/oc-rsync.1.md, and docs/design/windows-ntfs-acl-support.md for the documented lossy cases), xattrs (via NTFS Alternate Data Streams), and IOCP socket I/O (WSARecv/WSASend); symlinks and POSIX device nodes remain stubbed.
| Feature | Linux | macOS | Windows | Notes |
|---|---|---|---|---|
Permissions (-p) |
✓ | ✓ | ⚠ | Windows preserves only the read-only flag; POSIX mode bits are not applicable. |
Times (-t) |
✓ | ✓ | ✓ | Nanosecond precision via the filetime crate on all platforms. |
File ownership (-o/-g, uid/gid) |
✓ | ✓ | ✗ | apply_ownership_from_entry is a no-op on non-Unix; uid/gid mapping is Unix-only. |
ACLs (-A) |
✓ | ✓ | ⚠ | Uses exacl on Linux/macOS/FreeBSD. Windows uses windows-rs GetNamedSecurityInfoW/SetNamedSecurityInfoW for NTFS DACL round-trip (Tier 1C partial): deny ACEs, inherited ACEs, the SACL, non-rwx access bits, and unresolvable SIDs are dropped with a one-time warning. SDDL fidelity payload, --audit-acls, --fail-on-windows-acl-loss, and --windows-acls are planned. See docs/platform-notes.md for the Windows ACL behavior summary, docs/design/windows-ntfs-acl-support.md for the full mapping matrix, and the –acls entry in docs/oc-rsync.1.md. |
Extended attributes (-X) |
✓ | ✓ | ✓ | Linux/macOS via the xattr crate (macOS adds AppleDouble resource-fork support); Windows stores xattrs as NTFS Alternate Data Streams. |
Hardlinks (-H) |
✓ | ✓ | ✓ | Uses portable std::fs::hard_link; works on NTFS. |
| Symbolic links | ✓ | ✓ | ✗ | create_symlinks is cfg(not(unix)) no-op; symlink entries are skipped on Windows. |
Devices/specials (-D) |
✓ | ✓ | ✗ | create_fifo and create_device_node are no-ops on non-Unix. |
Sparse files (-S) |
✓ | ✓ | ⚠ | Uses portable seek + set_len; depends on filesystem (NTFS supports sparse but is not explicitly marked via FSCTL_SET_SPARSE). |
| Async I/O backend | ✓ io_uring | ⚠ standard I/O | ⚠ IOCP compiled, not wired | io_uring runtime-detected on Linux 5.6+; IOCP is implemented in fast_io but not yet consumed by the transfer pipeline (#1868). |
| Reflink / clone copy | ✓ FICLONE | ✓ clonefile | ⚠ ReFS reflink | Linux Btrfs/XFS/bcachefs via FICLONE; macOS via clonefile; Windows via FSCTL_DUPLICATE_EXTENTS_TO_FILE (ReFS only). |
| Optimized file copy | ✓ copy_file_range |
✓ fcopyfile |
✓ CopyFileExW |
All three are wired into the local-copy executor with standard-I/O fallback. |
Legend: ✓ supported, ⚠ partial or not yet wired, ✗ not implemented.
Bug fixes
--include='*/' followed by --exclude='*' now allows directory traversal while excluding leaf files, matching upstream byte-for-byte (#4107). Slash modifiers are stripped before wire serialisation and rebuilt on the receiver.--relative single-source daemon-push path stripping aligned with upstream (#4074)--info producer emissions (upstream parity)
--info=NONREG (default-on) reports skipped non-regular source files (generator.c:1687)--info=MOUNT reports --one-file-system mount-boundary skips (flist.c:1319, generator.c:325)--info=SYMSAFE reports unsafe symlink rejections (backup.c:291, flist.c:216)--info=BACKUP reports --backup rename successes (backup.c:352)--info=COPY reports --copy-dest/--link-dest/--compare-dest alt-base resolution (generator.c:919)--info=STATS level 1/2/3 distinction restored - level 1 emits only the trailing summary, level 2 adds the file-count detail block, level 3 surfaces heap stats (main.c:416-465)--debug producer emissions (upstream parity)
--debug=ACL daemon-side default-ACL probes (acls.c:1133-1134)--debug=BACKUP rename/replace/cross-device internal decisions--debug=BIND socket()/bind() failure diagnostics per address family (socket.c:432-470)--debug=CHDIR post-chroot change_dir notice in the daemon (util1.c:1168-1169)--debug=CMD SSH command construction and secluded-args transmission (util1.c:98-117, pipe.c:54-55)--debug=FUZZY fuzzy basis selection (generator.c)--debug=GENR generator entry points--debug=HASH delta-signature hashtable lifecycle (hashtable.c:45-103)--debug=HLINK (previously merged) hardlink resolution--debug=ICONV iconv setup/probe lines (rsync.c:99-145)--debug=OWN uid/gid lookup and chown diagnostics (rsync.c:537-545, uidlist.c:287-291)--info=help / --debug=help golden output now byte-matches upstream (options.c:499-509)INC_RECURSE instrumentation (sender-side)
send_file_listwire_to_flat_ndx / flat_to_wire_ndx partition_point counterswriter.flush() call-rate on the transfer hot pathprepare_pending_acl per-segment call count and elapsed timeencode_and_send_segment per-segment dispatch counterCompression
--compress-threads=N flag wires through to ZSTD_c_nbWorkers for multi-threaded zstd (3.4.2 parity)Checksums
Upstream interop
Code quality
/// rustdoc applied, every // upstream: source reference preserved#[must_use] from Result/Option returning functions across the workspace (#2123)Daemon & metadata
chrono::Local pre-initialised before chroot so timezone-aware log timestamps survive jail entry (3.4.2 parity)--open-noatime properly propagated through sender source-file opens (3.4.2 parity)clean_fname() buffer underflow, xattr qsort parity, allocator-zeroing, and Y2038 paths all audited against 3.4.2Documentation
Tested against upstream rsync 3.0.9, 3.1.3, 3.4.1, and 3.4.2 in CI across protocols 28-32. Both push and pull directions verified for 30+ scenarios covering transfer modes, deletion, compression, metadata, reference dirs, file selection, batch roundtrip, path handling, device nodes, and daemon auth.

Threaded architecture replaces upstream’s fork-based pipeline while keeping full protocol compatibility, reducing syscall overhead and context switches. Adaptive I/O buffers scale from 8KB to 1MB based on file size. Optional io_uring on Linux 5.6+ with three policies: auto (default; probe kernel and fall back to standard I/O), --io-uring (require io_uring; error if unavailable), --no-io-uring (always use standard buffered I/O). The active backend is reported by --version and -vv output. See oc-rsync(1) for details.
oc-rsync is wire-compatible with upstream rsync 3.4.1, but a few architectural choices and unfinished surfaces are worth calling out for operators planning a deployment:
Compression yes in ssh_config), running oc-rsync -z will compress payloads twice. There is currently no auto-detection / auto-disable path; operators should pick one layer.oc-rsync --daemon behind stunnel, ssh -L, or a reverse proxy that terminates TLS. See docs/deployment/daemon-tls.md for runnable terminator configs, hardened systemd units, and host-firewall rules; see SECURITY.md for the broader hardening note..rsync-filter per-directory inheritance. Inheritance semantics match upstream for the common cases tested in the interop suite, but exhaustive parity against upstream’s filter-tree corner cases (deeply nested merges, anchored vs unanchored interactions) is still being validated.--checksum-seed / --fuzzy. These flags are accepted and exercised in the common path; deeper conformance audits against upstream rsync 3.4.1 are tracked separately.brew tap oferchen/rsync https://github.com/oferchen/rsync
brew install oferchen/rsync/oc-rsync
Download from the Releases page:
| Platform | Formats |
|---|---|
| Linux (x86_64, aarch64) | .deb, .rpm (with OpenSSL), static musl .tar.gz |
| macOS (x86_64, aarch64) | .tar.gz |
| Windows (x86_64) | .tar.gz, .zip |
Linux static tarballs are available in two checksum variants:
| Variant | Filename | Description |
|---|---|---|
| Pure Rust (recommended) | *-musl.tar.gz |
Pure-Rust checksums, zero system dependencies |
| OpenSSL | *-musl-openssl.tar.gz |
OpenSSL-accelerated MD4/MD5 checksums (vendored, statically linked) |
Each release also includes three toolchain variants: stable (recommended, no suffix), beta (-beta), and nightly (-nightly).
Requires Rust 1.88+.
git clone https://github.com/oferchen/rsync.git
cd rsync
cargo build --workspace --release
The workspace exposes the following opt-in features. Defaults are tuned for the
release binary on modern Linux/macOS/Windows hosts; everything marked
experimental is wired but not yet promoted to the default set.
| Feature | Crate(s) | Default | Purpose | Status |
|---|---|---|---|---|
zstd |
workspace, core, engine, transfer, compress, protocol, batch |
yes | Enables zstd compression codec and wire negotiation. | stable |
lz4 |
workspace, core, engine, transfer, compress, protocol |
yes | Enables LZ4 compression codec. | stable |
zlib-ng |
workspace, core, engine, transfer, compress, protocol |
no | Selects the SIMD-accelerated zlib-ng C backend instead of pure-Rust zlib. |
stable |
xattr |
workspace, cli, core, transfer, daemon, metadata |
yes | Preserves extended attributes (-X) on Unix and NTFS ADS on Windows. |
stable |
acl |
workspace, cli, core, engine, transfer, daemon, metadata |
yes | Preserves POSIX/NFSv4 ACLs (-A) via exacl, NTFS ACLs via windows-rs. |
stable |
iconv |
workspace, cli, core, transfer, daemon, protocol |
yes | Filename and symlink-target charset transcoding (--iconv). |
stable |
parallel |
workspace, cli, engine, checksums |
yes | Rayon-based multi-core file and checksum operations. | stable |
io_uring |
workspace, transfer, fast_io |
yes | Linux 5.6+ batched async I/O with runtime fallback. | stable |
iocp |
workspace, transfer, fast_io |
yes | Windows I/O Completion Ports for overlapped file and socket I/O. | stable |
copy_file_range |
workspace, fast_io |
yes | Compat alias; the copy_file_range syscall is now always compiled with runtime detection. |
stable |
async |
workspace, core, engine, transfer, daemon |
yes | Brings in tokio for async I/O paths across the orchestrator stack. | stable |
openssl |
workspace, checksums |
no | Routes MD4/MD5 through the system OpenSSL build. | stable |
openssl-vendored |
workspace, checksums |
no | Same as openssl but statically links a vendored OpenSSL. |
stable |
embedded-ssh |
workspace, core, rsync_io |
no | Pure-Rust SSH client via russh; removes the runtime dependency on system ssh. |
stable |
sd-notify |
workspace, core, daemon |
no | systemd sd-notify integration for the daemon. |
stable |
incremental-flist |
transfer |
yes | Incremental file-list processing with failed-directory tracking. | stable |
lazy-metadata |
engine |
yes | Defers stat() calls until metadata is needed. |
stable |
multi-producer |
engine |
no | Relaxes the single-producer compile-time invariant on WorkQueueSender. |
experimental |
thread-slab-pool |
engine |
no | Per-thread bounded LIFO slab in front of BufferPool; pays off above ~32 workers (#1271, #1370). |
experimental |
vmsplice |
fast_io, transfer |
no | Linux vmsplice(2) + splice(2) zero-copy writer for large page-aligned chunks. |
experimental |
async-ssh |
core, rsync_io |
no | Wires AsyncSshTransport into the client remote path; opt-in at runtime via OC_RSYNC_ASYNC_SSH=1 (#1593, #1796, #1805, #1806). |
experimental |
ssh-socketpair-stderr |
rsync_io |
no | Constructs the SSH child’s stderr over a socketpair(AF_UNIX, SOCK_STREAM) instead of an anonymous pipe, enabling epoll/kqueue-integrated async drain and a larger default buffer to absorb chatty remote shells (Linux recommended; Windows shim pending SSE-5). See docs/ssh-transport.md and docs/design/socketpair-stderr-channel.md (#2371, #2372). |
experimental |
async-daemon |
daemon |
no | Hybrid tokio accept loop dispatching sync workers via spawn_blocking (#1935). |
experimental |
concurrent-sessions |
daemon |
no | Shared dashmap session state for multi-session daemons. |
experimental |
tracing |
core, engine, transfer, daemon |
no | Structured tracing instrumentation for diagnostics. |
stable |
SpillPolicyThe concurrent-delta receiver bounds its in-memory ReorderBuffer through a
process-wide SpillPolicy knob. The default policy keeps everything in memory
(byte-equivalent to prior releases). Opt in to disk-backed spill by setting
OC_RSYNC_SPILL_THRESHOLD_BYTES (e.g. 64M) and, optionally,
OC_RSYNC_SPILL_DIR to point at a fast scratch directory. CLI flags
--spill-dir and --spill-threshold-bytes are planned for STN-11 and will
shadow the env vars when present. Full surface (env vars, reclaim mode,
granularity, compression, validation rules, defaults table) is in
docs/design/spill-policy-public-api.md;
the underlying buffer is documented in
docs/design/reorderbuffer-spill-to-tempfile.md.
Operator-facing tuning guidance is in
docs/operator-migration-guide-vNEXT.md
under Receiver spill tunability.
# Default release build (recommended starting point).
cargo build --workspace --release
# Enable the async network paths end-to-end. async-ssh and async-daemon are
# crate-level features, so build the affected crates directly.
cargo build --release -p core --features async-ssh
cargo build --release -p daemon --features async-daemon
# Squeeze out maximum parallelism on a fat machine: keep the workspace
# defaults and add the experimental engine slab and vmsplice writer.
cargo build --workspace --release \
--features "parallel async io_uring" \
&& cargo build --release -p engine --features thread-slab-pool \
&& cargo build --release -p fast_io --features vmsplice
Works like rsync - drop-in compatible:
# Local sync
oc-rsync -av ./source/ ./dest/
# Remote pull (SSH)
oc-rsync -av user@host:/remote/path/ ./local/
# Remote push (SSH)
oc-rsync -av ./local/ user@host:/remote/path/
# Daemon pull
oc-rsync -av rsync://host/module/ ./local/
# Daemon push
oc-rsync -av ./local/ rsync://host/module/
# Run as daemon
oc-rsync --daemon --config=/etc/oc-rsyncd/oc-rsyncd.conf
# Delta transfer with compression
oc-rsync -avz --compress-level=3 ./source/ ./dest/
# Checksum-based sync with deletion
oc-rsync -avc --delete ./source/ ./dest/
# Batch mode (record and replay)
oc-rsync -av --write-batch=changes ./source/ ./dest/
oc-rsync -av --read-batch=changes ./other-dest/
For supported options: oc-rsync --help
rust-toolchain.toml)cargo-nextest: cargo install cargo-nextest --lockedcargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features --no-deps -D warnings
cargo nextest run --workspace --all-features
src/bin/oc-rsync.rs # Entry point
crates/cli/ # CLI flags, help, output formatting
crates/core/ # Orchestration facade, session management, config
crates/protocol/ # Wire protocol (v28-32), multiplex framing
crates/transfer/ # Generator, receiver, delta transfer pipeline
crates/engine/ # Local copy executor, sparse writes, temp-file commit
crates/daemon/ # Daemon mode, module access control, systemd
crates/checksums/ # Rolling and strong checksums (MD4, MD5, XXH3, SIMD)
crates/filters/ # Include/exclude pattern engine, .rsync-filter
crates/metadata/ # Permissions, uid/gid, mtime, ACLs, xattrs
crates/platform/ # Platform-specific unsafe code isolation (signals, chroot)
crates/rsync_io/ # SSH stdio, rsync:// TCP transport, handshake
crates/fast_io/ # Platform I/O (io_uring, copy_file_range, sendfile)
crates/compress/ # zstd, lz4, zlib compression codecs
crates/bandwidth/ # Bandwidth limiting and rate control
crates/signature/ # Signature layout and block-size calculations
crates/matching/ # Delta matching and block search
crates/flist/ # File list generation and traversal
crates/logging/ # Logging macros and verbosity control
crates/logging-sink/ # Message sink and output formatting
crates/batch/ # Batch file read/write support
crates/branding/ # Binary naming and version metadata
crates/embedding/ # Programmatic entry points for library usage
crates/apple-fs/ # macOS filesystem operations (clonefile, FSEvents)
crates/windows-gnu-eh/ # Windows GNU exception handling shims
crates/test-support/ # Shared test utilities (dev-dependency only)
See cargo doc --workspace --no-deps --open for API documentation.
cli -> core -> engine, daemon, rsync_io, logging
core -> protocol -> checksums, filters, compress, bandwidth -> metadata
-> platform
Key crates: cli (Clap v4), core (orchestration facade), protocol (wire v28-32, multiplex framing), transfer (generator/receiver, delta pipeline), engine (local copy, sparse writes, buffer pool), checksums (MD4/MD5/XXH3, SIMD), daemon (TCP, auth, modules), platform (unsafe code isolation).
All crates enforce #![deny(unsafe_code)]. Targeted #[allow(unsafe_code)] is permitted only in crates that wrap platform FFI or SIMD intrinsics:
copy_file_range, sendfile, mmap, IOCP, WSARecv/WSASend, setsockopt with standard I/O fallbacksCopyFileExWmultiplex::helpers for frame parsingNot vulnerable to known upstream rsync CVEs (CVE-2024-12084 through CVE-2024-12088, CVE-2024-12747). OS-level race conditions (TOCTOU) remain possible at filesystem boundaries.
For security issues, see SECURITY.md.
cargo fmt, cargo clippy, and cargo nextest runGNU GPL v3.0 or later. See LICENSE.
Inspired by rsync by Andrew Tridgell and the Samba team.
Thanks to Pieter for his heroic patience in enduring months of my rsync commentary.
Thanks to Elad for his endless patience hearing rsync protocol commentary as I’m introduced to it.