Skip to content
majidninjaPublic

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

16 Commits

Folders and files

Repository files navigation

rotcheck

rotcheck keeps an eye on folders you care about, like photo libraries, music, scanned documents or backups. It tells you when a file has gone missing, been changed, or been quietly corrupted on disk.

Disks and flash drives sometimes flip bits without telling you. You usually find out years later, when an old photo won't open. rotcheck records a SHA-256 checksum for every file once. Later you run it again and it shows you exactly what's different.

  • Offline. No accounts, no network, no services that might shut down.
  • No dependencies. Even SHA-256 is implemented in this repo, so the code will still build years from now.
  • Plain-text manifests. The checksum list uses the same format as sha256sum, so you can still check your files with standard tools if rotcheck ever disappears.

Status: early development, but the core loop works: init records a folder, verify checks it and update accepts your intentional changes. What's left is on the roadmap in DEVLOG.md.

Install

You need a Rust toolchain (rustup.rs).

git clone https://github.com/majidninja/rotcheck
cd rotcheck
cargo install --path .

That builds an optimized binary and puts it in ~/.cargo/bin, which rustup adds to your PATH. Check it worked with rotcheck --version.

rotcheck has no dependencies outside the Rust standard library, so the build needs no network access once you have the source. If you'd rather not install anything, build it and copy the single file wherever you like:

cargo build --release
cp target/release/rotcheck /usr/local/bin/   # or ~/bin, or a USB stick

The binary is small (around 400 KB on Linux) and needs nothing else at run time. Keeping a copy next to an archive, together with this source, means you can still check it in ten years.

To remove it again: cargo uninstall rotcheck. Manifests are plain text files, so nothing else is left behind.

Usage

Print checksums for some files:

$ rotcheck hash Cargo.toml src/main.rs
28e5cc653ee8554c8a510a14b549875029fc6e81275fff2cb178ddf58864bd79  Cargo.toml
0f9280f25be1cbd1f72a520ee3b23992fcd8f22e294ee3be86547441656324f1  src/main.rs

The output is the same as sha256sum's, so you can save it and check it later with sha256sum -c:

rotcheck hash *.jpg > photos.sha256
sha256sum -c photos.sha256

See which files rotcheck would track in a folder:

$ rotcheck list ~/Pictures
2024/beach.jpg
2024/notes.txt
scan.png

Paths are relative to the folder, always use /, and are sorted. Symbolic links are skipped (not followed), so a link can't pull in files from outside the folder or send rotcheck in circles.

Record a checksum for every file in a folder:

$ rotcheck init ~/Pictures
rotcheck: recorded 3 files in /home/you/Pictures/.rotcheck.sha256

This writes .rotcheck.sha256 at the top of the folder. It's a plain text file that looks like this:

# rotcheck manifest v1
# size=48213 mtime=1700000000
9f2c...e41a  2024/beach.jpg

The # lines hold each file's size and modification time. sha256sum skips them, so you can check the folder without rotcheck too:

cd ~/Pictures && sha256sum -c .rotcheck.sha256

init won't overwrite an existing manifest. File names with a backslash, newline or carriage return are written the same way sha256sum writes them: the line starts with \ and the name has \\, \n or \r in it. So those lines still work with sha256sum -c, and checksum lists from sha256sum with such names work as rotcheck manifests. rotcheck's own output (list, hash, and the verify/update reports) escapes these names the same way, so every file is always on exactly one line.

Check the folder against its manifest, whenever you like:

$ rotcheck verify ~/Pictures
MODIFIED    2024/notes.txt
MISSING     old.txt
CORRUPTED   scan.png
NEW         new.txt
rotcheck: 1 ok, 1 corrupted, 1 modified, 1 missing, 1 new

Every recorded file is read and hashed again, so this takes about as long as init did. Files that are fine aren't listed. The words mean:

Word What happened
CORRUPTED The content changed, but the size and timestamp didn't. Likely bit rot.
MODIFIED The content changed and so did the size or timestamp. Probably an edit.
MISSING The file is in the manifest but no longer in the folder.
NEW The file is in the folder but not in the manifest.
UNREADABLE The file is there, but rotcheck couldn't read it.

CORRUPTED is the one to worry about: restore that file from a backup. A file whose timestamp changed while its content stayed the same counts as fine.

verify never changes anything, neither your files nor the manifest.

After you've added, edited or deleted files on purpose, bring the manifest up to date:

$ rotcheck update ~/Pictures
MODIFIED    2024/notes.txt
MISSING     old.txt
CORRUPTED   scan.png
NEW         new.txt
rotcheck: manifest updated: 1 added, 1 updated, 1 removed, 0 unchanged, 1 corrupted (kept)

update reads every file again, like verify, and then rewrites the manifest: new files are added, missing ones are dropped and edited ones get their new checksum.

Files that look corrupted are left alone. They keep their old checksum, so verify goes on flagging them until you've restored them from a backup. If you're sure the current content is what you want, say so explicitly:

rotcheck update --accept-corrupted ~/Pictures

It's worth running verify and reading its output before update, because update accepts every MODIFIED and MISSING file without asking.

Exit codes

Handy for cron jobs and scripts:

  • 0: everything recorded is intact. New files alone don't count as a problem, unless you pass --strict (useful for archive folders that should never grow).
  • 1: something is corrupted, modified, missing or unreadable.
  • 2: rotcheck couldn't do the check (bad arguments, no manifest, unreadable folder).

For cron, add --quiet: verify then prints only the files that make it fail (no summary line, and NEW files only with --strict). No output means all is well, so cron only mails you when there's something to look at:

# every Sunday at 3am
0 3 * * 0  rotcheck verify --quiet ~/Pictures

update uses the same codes: 0 when the manifest now matches the folder, 1 when it left a corrupted or unreadable file as it was. update --quiet works like verify --quiet: it prints only the corrupted or unreadable files (plus the hint on stderr), and nothing at all when the update went fine.

rotcheck verify /mnt/backup/photos || echo "check the photo backup!"

verify also accepts a plain sha256sum list saved as .rotcheck.sha256. Such a list has no sizes or timestamps, so any changed file shows up as MODIFIED. A leading ./ on paths (as find . -type f -exec sha256sum {} + prints them) is fine. Absolute paths and paths with .. are refused, so a manifest can never make rotcheck look outside the folder.

Using the output in scripts

The report lines from verify and update are meant to be stable: one file per line, the status word, spaces up to column 13, then the path (escaped as described above). So plain shell tools are enough, for example to list just the corrupted files:

rotcheck verify --quiet ~/Pictures | grep '^CORRUPTED' | cut -c13-

The summary line and error messages start with rotcheck:, and errors go to stderr.

Progress

On big folders, init, verify and update show a running count of files on the last line of the terminal (rotcheck: hashing [1234/5678]). It goes to stderr, is wiped before each report line, and only appears when stderr is a terminal, so it never shows up in logs, pipes or cron mail. verify --quiet never shows it.

License

MIT, see LICENSE.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages