mtree: File Integrity Verification on macOS
Most people have never heard of mtree. It ships with every Mac,
has been in BSD since the early 90s, and does one thing extremely well:
it tells you whether your files have changed.
No install. No dependencies. Already on your machine.
What Is mtree?
mtree was originally written to verify that OS distribution trees arrived intact
after installation. You generate a manifest — a snapshot of a directory's contents,
permissions, and checksums — then verify against it later.
Think of it as a fingerprint for a directory. Run it now, run it again in six months. If anything changed, it tells you exactly what.
Why You'd Use It
- You have an archive drive and want to know if anything silently corrupted
- You want to verify a backup was written correctly
- You want to detect unexpected file changes
- You want a dead-simple integrity check with no third-party tools
How to Use mtree on macOS
Create a Manifest
mtree -c -K sha256digest -p /path/to/directory > manifest.mtree
Flags:
-c— create mode (build a manifest)-K sha256digest— include SHA-256 checksums for every file-p /path— the directory to fingerprint
Store the manifest somewhere other than the directory you're verifying. If it lives on the same drive, you can't trust it.
Verify Against a Manifest
mtree -f manifest.mtree -p /path/to/directory
Silence means nothing changed. Output means something did.
Reading the Output
$ mtree -f manifest.mtree -p /Volumes/Archive
./file1.txt changed
modification time expected Sat Feb 28 10:00:00 2026 found Sat Feb 28 11:00:00 2026
sha256digest expected 3d4f8ac2... found 9b1e3f77...
./notes.txt missing
./newfile.pdf extra
| Output | Meaning |
|---|---|
filename changed (multi-line) | File modified; field-level diffs follow on indented lines |
filename missing | File was deleted |
filename extra | New file appeared |
filename: size (old, new) | File size changed |
filename: mode (old, new) | Permissions changed |
| (no output) | Everything matches ✓ |
What a Manifest Looks Like
# user: yourname
# machine: your-mac
# tree: /Volumes/Archive
# date: Sat Feb 28 10:00:00 2026
/set type=file uid=501 gid=20 mode=0644
. type=dir mode=0755 time=1740750000.0
taxes-2025.pdf \
size=204800 \
sha256digest=3d4f8ac2e1b97f44c8a02193d5e6f8b1...
resume.pdf \
size=98304 \
sha256digest=7c2e1b44f9a83d52c017e4b8a63f2d90...
Plain text. Human-readable. Diffable with standard tools.
mtree Workflow: Archive Drives and Backups
Archive Drive
You write files to an external drive once and store it offline. Before putting it away, fingerprint it. On every spin-up, verify before touching anything.
# Step 1: Write your files to the drive
# Step 2: Fingerprint it — store the manifest in iCloud, not on the drive
# (A manifest on the drive it describes cannot be trusted)
MANIFEST="$HOME/Library/Mobile Documents/com~apple~CloudDocs/Manifests/Archive-manifest.mtree"
/usr/sbin/mtree -c -K sha256digest -p /Volumes/Archive > "$MANIFEST"
# Step 3: Set immutable flag to prevent accidental modification (not a security control — easily reversed by file owner)
chflags -R uchg /Volumes/Archive
# This prevents accidental Finder writes. It does not protect against anyone with file ownership access.
# Step 4: Eject and store offline
Note: An mtree manifest contains filenames, sizes, and directory structure — metadata about your drive. Storing it in iCloud is convenient but means Apple can see what files are on your archive. For sensitive archives, store the manifest on your local machine only.
On every spin-up:
# Verify before doing anything else
MANIFEST="$HOME/Library/Mobile Documents/com~apple~CloudDocs/Manifests/Archive-manifest.mtree"
/usr/sbin/mtree -f "$MANIFEST" -p /Volumes/Archive
# Clean output = all good
# Any output = investigate before proceeding
Verifying a Tar Archive
mtree verifies live directory trees, not archives. To check a tar, use sha256 directly:
# Checksum the archive
shasum -a 256 backup.tar.gz > backup.sha256
# Verify later
shasum -a 256 -c backup.sha256
Use mtree for directories, sha256 for archives. They complement each other.
Filtering What Gets Checked
By default mtree checks everything. Narrow it with -K:
# Check content and size only (ignore permission/ownership changes)
mtree -c -K sha256digest,size -p /Volumes/Archive > manifest.mtree
| Keyword | What It Checks |
|---|---|
sha256digest | File content (SHA-256) |
size | File size in bytes |
mode | Permissions |
uid, gid | Ownership |
time | Modification time |
link | Symlink target |
For data integrity, sha256digest is the one that matters.
Excluding Files
Use -X with a file listing patterns to exclude:
# Create exclusion list
cat > mtree-exclude.txt << 'EOF'
.DS_Store
.Spotlight-V100
.fseventsd
Thumbs.db
EOF
# Generate manifest excluding those patterns
mtree -c -K sha256digest -p /Volumes/Archive \
-X mtree-exclude.txt > manifest.mtree
macOS drops .DS_Store everywhere. Exclude it or your manifest will be full of noise.
Practical Tips
Always store the manifest off the drive.
A manifest on the same drive it describes can't detect tampering. Store it in iCloud,
on your main machine, or in a second location.
Date your manifests.
mtree -c -K sha256digest -p /Volumes/Archive \
> "Archive-manifest-$(date +%Y-%m-%d).mtree"
Keep multiple manifests.
One from when you first wrote the data. One from last verification.
If something changes, you know when it happened.
Pipe through a clean report script.
RESULT=$(mtree -f manifest.mtree -p /Volumes/Archive 2>&1)
if [ -z "$RESULT" ]; then
echo "✓ All files verified clean — $(date)"
else
echo "⚠ Changes detected:"
echo "$RESULT"
fi
mtree Limitations on macOS
Extended attributes and resource forks.
macOS uses xattrs heavily — Finder tags, quarantine flags, metadata. mtree doesn't
capture these by default. For data integrity (has the file content changed)
it's fine. For exact filesystem reproduction, you'd need additional tooling.
Detection only — not repair.
mtree tells you something changed. It doesn't fix it or tell you what the content
was before. Your backups handle recovery; mtree tells you recovery is needed.
Not a continuous monitor.
mtree is a point-in-time comparison tool. It doesn't watch for changes in real time.
Run it on spin-up, before writes, and after writes.
Large drives take time.
SHA-256 checksumming a 2TB drive takes a while. Plan accordingly on first manifest generation.
Quick Reference
# Create manifest
mtree -c -K sha256digest -p /path > manifest.mtree
# Verify
mtree -f manifest.mtree -p /path
# Create with exclusions
mtree -c -K sha256digest -p /path -X exclude.txt > manifest.mtree
# Check content and size only
mtree -c -K sha256digest,size -p /path > manifest.mtree
# Read the manual
man 8 mtree
The Full Verification Script
Drop this in your path. Run it every time you spin up an archive drive.
#!/bin/bash
# verify-archive.sh — spin-up verification for offline drive
DRIVE="/Volumes/Archive"
MANIFEST="$HOME/Library/Mobile Documents/com~apple~CloudDocs/Manifests/Archive-manifest.mtree"
if [ ! -d "$DRIVE" ]; then
echo "Drive not mounted at $DRIVE"
exit 1
fi
if [ ! -f "$MANIFEST" ]; then
echo "✗ No manifest found at: $MANIFEST"
echo " To create an initial manifest, run:"
echo " /usr/sbin/mtree -c -K sha256digest -p \"$DRIVE\" > \"$MANIFEST\""
echo " Only do this if you trust the current state of the drive."
exit 2
fi
echo "→ Verifying $DRIVE against manifest..."
RESULT=$(mtree -f "$MANIFEST" -p "$DRIVE" 2>&1)
if [ -z "$RESULT" ]; then
echo "✓ All files verified clean — $(date)"
else
echo "⚠ Changes detected:"
echo "$RESULT"
exit 1
fi
mtree has been sitting quietly in /usr/sbin on your Mac the whole time.
Now you know it's there.