feat: Add scripts
This commit is contained in:
1 parent
d15429f870
commit
3bccb79238
10 files changed
+1223
No files matched your search
@@ -0,0 +1,182 @@
|
||||
# Rebuilding the empty directory tree after LVM recovery
|
||||
|
||||
These scripts are **independent** of the file-salvage scripts. Their job is to
|
||||
save the names (and, when available, numeric UID/GID/mode) of directories
|
||||
**before you wipe the damaged array**, then recreate those empty directories
|
||||
on the new `/storage` filesystem.
|
||||
|
||||
## Before rebuilding: export the surviving tree
|
||||
|
||||
The current damaged ext4 volume cannot mount normally. `capture-tree.py` uses
|
||||
`debugfs -c` instead, just as the file-salvage scripts do. It enumerates
|
||||
**directory metadata only**. It does not read or recover the file contents.
|
||||
|
||||
Keep the damaged LV read-only. Check:
|
||||
|
||||
```bash
|
||||
blockdev --getro /dev/mapper/plex--new-plex--new # must print 1
|
||||
findmnt /mnt/recovery # Passport must be mounted
|
||||
```
|
||||
|
||||
Capture all *reachable* top-level directories and their descendants:
|
||||
|
||||
```bash
|
||||
sudo python3 capture-tree.py \
|
||||
--source / \
|
||||
--include /Backups \
|
||||
--output /mnt/recovery/plex-directory-tree.jsonl
|
||||
```
|
||||
|
||||
`--include /Backups` adds that root manually because, in this incident, its
|
||||
inode metadata is zeroed out. **It will not restore unknown children beneath
|
||||
it.** Repeat `--include` for any additional known directory path you need to
|
||||
exist later, including the share roots that have missing metadata.
|
||||
|
||||
To scan only selected trees (less time, but incomplete):
|
||||
|
||||
```bash
|
||||
sudo python3 capture-tree.py \
|
||||
--source /Media \
|
||||
--source /Warez \
|
||||
--include /Backups \
|
||||
--output /mnt/recovery/plex-directory-tree.jsonl
|
||||
```
|
||||
|
||||
This writes three files **to the Passport**:
|
||||
|
||||
- `plex-directory-tree.jsonl` — directory paths with owner/mode metadata (when
|
||||
available); preferred input for the restore script.
|
||||
- `plex-directory-tree.txt` — one absolute filesystem path per line, easy to
|
||||
inspect or edit, and also valid restore input (without ownership/modes).
|
||||
- `plex-directory-tree.warnings.txt` — unreadable directories and ambiguous
|
||||
entries. **Read this** before deciding the capture is complete.
|
||||
|
||||
You can manually append known missing directory paths to the `.txt` file, or
|
||||
re-run the capture with additional `--include` arguments. Save the resulting
|
||||
three files somewhere safe besides the array you're about to rebuild.
|
||||
|
||||
**Important:** If a directory's inode or parent directory block was lost, no
|
||||
metadata-only tool can reconstruct the unknown descendants. Keep a list of
|
||||
missing Samba share roots and any especially important subdirectories to add
|
||||
manually. If a directory entry's type is destroyed, `capture-tree.py` reports
|
||||
it as ambiguous in the warnings file; it does *not* invent a directory.
|
||||
|
||||
## Alternative: use an existing full-path folder list
|
||||
|
||||
`restore-tree.py` also accepts a plain UTF-8 text file with **one full directory
|
||||
path per line**, for example:
|
||||
|
||||
```text
|
||||
/Media
|
||||
/Media/Videos
|
||||
/Media/Videos/Television
|
||||
/Media/Videos/Television/Bob's Burgers
|
||||
/Media/Videos/Movies
|
||||
/Warez
|
||||
/Warez/Books
|
||||
/Backups
|
||||
```
|
||||
|
||||
Folder paths may contain spaces and apostrophes; don't quote individual lines
|
||||
in the text file. Empty directory parents are created automatically. An
|
||||
indented/box-drawing `tree` diagram is **not** valid input; use `tree -dfi
|
||||
--noreport` or `find ... -type d` output that prints a full path on each line.
|
||||
|
||||
If a working source had been mounted under `/storage`, a text export might
|
||||
contain `/storage/Media/...` rather than `/Media/...`; see `--strip-prefix` below.
|
||||
|
||||
## After rebuilding: validate, dry-run, then apply
|
||||
|
||||
**Do not run `restore-tree.py --apply` until the newly rebuilt filesystem is
|
||||
mounted at `/storage`.** The script refuses to apply if `/storage` is just an
|
||||
unmounted directory on the OS disk. It also refuses symlinks/non-directories
|
||||
along the destination path.
|
||||
|
||||
Verify that the *correct* filesystem is mounted:
|
||||
|
||||
```bash
|
||||
findmnt /storage
|
||||
lsblk -f
|
||||
```
|
||||
|
||||
Dry run using the captured JSONL:
|
||||
|
||||
```bash
|
||||
python3 restore-tree.py /mnt/recovery/plex-directory-tree.jsonl \
|
||||
--target /storage
|
||||
```
|
||||
|
||||
If it looks correct, create the empty directories:
|
||||
|
||||
```bash
|
||||
sudo python3 restore-tree.py /mnt/recovery/plex-directory-tree.jsonl \
|
||||
--target /storage --apply
|
||||
```
|
||||
|
||||
**Optional:** Restore original numeric owners and permission modes where the
|
||||
capture has valid metadata. Check that the same service accounts/UIDs exist on
|
||||
the rebuilt host first. Files on the exFAT Passport do not themselves preserve
|
||||
Unix owner/mode metadata; the JSONL does.
|
||||
|
||||
```bash
|
||||
sudo python3 restore-tree.py /mnt/recovery/plex-directory-tree.jsonl \
|
||||
--target /storage --apply --restore-metadata
|
||||
```
|
||||
|
||||
Use `--expect-source /dev/mapper/<your-new-lv>` for an extra safety check if
|
||||
you know the exact `findmnt` SOURCE string for the rebuilt array.
|
||||
|
||||
For an existing text list whose paths include the old mountpoint:
|
||||
|
||||
```bash
|
||||
python3 restore-tree.py old-tree.txt --target /storage \
|
||||
--strip-prefix /storage
|
||||
|
||||
sudo python3 restore-tree.py old-tree.txt --target /storage \
|
||||
--strip-prefix /storage --apply
|
||||
```
|
||||
|
||||
Re-running the restore is supported. Existing directories are retained.
|
||||
`--restore-metadata` **does** change mode and owner of existing directories
|
||||
listed in the snapshot, so use it deliberately.
|
||||
|
||||
## What this does **not** restore
|
||||
|
||||
- File contents, missing/unreachable directory names, symlinks, or hardlinks.
|
||||
- Samba definitions (`smb.conf` or included shares), user accounts, ACLs, and
|
||||
extended attributes. Those must already exist or be separately restored.
|
||||
- Docker bind-mount configuration and application databases. Creating the
|
||||
directory is not sufficient if a container also needs its files or metadata.
|
||||
|
||||
After restoration, verify the expected share root directories exist and have
|
||||
appropriate permissions before starting services. For Samba, `testparm` can
|
||||
validate the existing share configuration; directory creation alone cannot
|
||||
recreate the share definitions.
|
||||
|
||||
## Recovery-incident particulars (Banshee)
|
||||
|
||||
- Damaged logical volume: `/dev/mapper/plex--new-plex--new`.
|
||||
- Filesystem: ext4, 4,096-byte blocks.
|
||||
- Previously calculated missing data-block range: `3418636288–4395389951`.
|
||||
(The directory-tree scripts do **not** use this range; they simply traverse
|
||||
readable directory metadata. See the main salvage README for dead-block
|
||||
calculations.)
|
||||
- `/Backups` root entry survives, but inode `496369665` is zeroed and cannot
|
||||
be traversed. Use `--include /Backups` plus any known child directories.
|
||||
- `/mnt/recovery` is the removable Passport; export onto that or another
|
||||
device, **not** onto the array being rebuilt.
|
||||
|
||||
**Checkpoint:** Copy all three capture files off the recovery system and
|
||||
review the warnings and share roots *before* formatting or recreating the LV.
|
||||
Also make sure your existing Samba configuration and share definitions are
|
||||
backed up independently. Useful commands before the rebuild:
|
||||
|
||||
```bash
|
||||
testparm -s # inspect configured Samba shares and paths
|
||||
cp -a /etc/samba /mnt/recovery/samba-config-pre-rebuild
|
||||
```
|
||||
|
||||
If the new storage will be served by containers instead, independently save
|
||||
their Compose files and bind-mount declarations. If the operating-system disk
|
||||
isn't being rebuilt, those configurations may remain intact, but it's worth
|
||||
having copies before changing the storage layout.
|
||||
Reference in new issue
Block a user