Safety, Recovery, and Limitations

DedupCommando removes and relinks real files. This document explains the guardrails that protect your data, how to recover if something goes wrong, and the tool's limitations. Read it before applying actions, and keep backups.

Safety model

Every destructive batch (delete / hardlink / reflink) runs behind layered guardrails:

1. ZFS snapshot before the batch

Before the first action, dedcom checks every action for what would stop it — a read-only or full filesystem, an immutable or append-only file or directory, a second mount of the dataset, a reflink the host or the pool cannot make — and refuses those actions untouched. It then snapshots every dataset an action will run on, named <dataset>@dedcom-<YYYYMMDD-HHMMSS>-<seq>; if no action can run, it takes none. If any snapshot fails, the entire batch is aborted — no action runs. Snapshots are never auto-removed; they remain as insurance until you delete them with zfs destroy.

"Delete" does not call unlink. The file is moved into a per-dataset quarantine directory, .dedcom-quarantine/<YYYYMMDD-HHMMSS>-<seq>/<path-relative-to-dataset>, preserving permissions, owner, and extended attributes. Space is reclaimed only when you purge the quarantine. The same quarantine is used to publish hardlinks/reflinks atomically (the original is evacuated first, the link is published into the freed slot, and on failure the original is restored).

3. Content revalidation before each action

Immediately before each destructive action, dedcom re-checks the target and the keeper against the last scan:

A mismatch aborts that action; the rest of the batch continues.

4. Atomic publish — renameat2(RENAME_NOREPLACE)

File moves use renameat2 with RENAME_NOREPLACE, so "does the destination exist?" and the move itself are a single kernel operation — there is no check-then-rename window on the destination.

5. Single-instance lock

A writing instance holds an advisory flock on ~/.local/state/dedcom/dedcom.lock. A second instance can only run read-only (or force-seize, which is dangerous). Headless writers never prompt — they exit non-zero if the lock is held.

A one-time disclaimer must be accepted before first use. On busy hosts the scan's resource profile (Turbo / Balanced / Idle) caps threads and I/O priority so a scan does not starve VMs or backups.

7. Cross-dataset moves are refused

A move that would cross a dataset boundary is rejected (with an rsync hint) rather than performed as a silent copy-and-delete, which would lose ownership/permissions/ACLs/xattrs, inflate sparse files, and break hardlinks.

Honest caveat: TOCTOU

Operations act by path, not by an open file descriptor, so a theoretical check-to-act window exists. It is mitigated by the snapshot, the atomic publish, repeated symlink checks, and quarantine-based restore. A full fd + O_NOFOLLOW closure is deliberately deferred for the single-administrator model this tool targets.

Recovery

Limitations

Published from docs/SAFETY.md at v0.9.2 · last changed 2026-09-28