/btrfs-undelete
| #!/bin/bash | |
| # btrfs-undelete | |
| # Copyright (C) 2013 Jörg Walter <info@syntax-k.de> | |
| # This program is free software; you can redistribute it and/or modify it under | |
| # the term of the GNU General Public License as published by the Free Software | |
| # Foundation; either version 2 of the License, or any later version. | |
| if [ ! -b "$1" -o -z "$2" -o -z "$3" ]; then | |
| echo "Usage: $0 <dev> <file/dir> <dest>" 1>&2 | |
| echo | |
| echo "This program tries to recover the most recent version of the" | |
| echo "given file or directory (recursively)" | |
| echo | |
| echo "<dev> must not be mounted, otherwise this program may appear" | |
| echo "to work but find nothing." | |
| echo | |
| echo "<file/dir> must be specified relative to the filesystem root," | |
| echo "obviously. It may contain * and ? as wildcards, but in that" | |
| echo "case, empty files might be 'recovered'. If <file/dir> is a" | |
| echo "single file name, this program tries to recover the most" | |
| echo "recent non-empty version of the file." | |
| echo | |
| echo "<dest> must be a writable directory with enough free space" | |
| echo "to hold the files you're trying to restore." | |
| exit 1 | |
| fi | |
| dev="$1" | |
| file="$2" | |
| file="${file#/}" | |
| file="${file%/}" | |
| regex="${file//\\/\\\\}" | |
| # quote regex special characters | |
| regex="${regex//./\.}" | |
| regex="${regex//+/\+}" | |
| regex="${regex//|/\|}" | |
| regex="${regex//(/\(}" | |
| regex="${regex//)/\)}" | |
| regex="${regex//\[/\[}" | |
| regex="${regex//]/\]}" | |
| regex="${regex//\{/\{}" | |
| regex="${regex//\}/\}}" | |
| # treat shell wildcards specially | |
| regex="${regex//\*/.*}" | |
| regex="${regex//\?/.}" | |
| # extract number of slashes in order to get correct number of closing parens | |
| slashes="${regex//[^\/]/}" | |
| # build final regex | |
| regex="^/(|${regex//\//(|/}(|/.*${slashes//?/)}))\$" | |
| roots="$(mktemp --tmpdir btrfs-undelete.roots.XXXXX)" | |
| out="$(mktemp --tmpdir="$3" -d btrfs-undelete.XXXXX)" | |
| cd $out | |
| trap "rm $roots" EXIT | |
| trap "rm -r $out &> /dev/null; exit 1" SIGINT | |
| echo -ne "Searching roots..." | |
| btrfs-find-root "$dev" 2>&1 \ | |
| | grep ^Well \ | |
| | sed -r -e 's/Well block ([0-9]+).*/\1/' \ | |
| | sort -rn >$roots || exit 1 | |
| echo | |
| i=0 | |
| max="$(wc -l <$roots)" | |
| while read id; do | |
| ((i+=1)) | |
| echo -e "Trying root $id... ($i/$max)" | |
| btrfs restore -t $id --path-regex "$regex" "$dev" . &>/dev/null | |
| if [ "$?" = 0 ]; then | |
| found=$(find . -type f ! -size 0c | wc -l) | |
| if [ $found -gt 0 ]; then | |
| echo "Recovered $found non-empty file(s) into $out" | |
| exit 0 | |
| fi | |
| find . -type f -size 0c -exec echo "Found {} but it's empty" \; -delete | |
| fi | |
| done <$roots | |
| rm -r $out | |
| echo "Didn't find '$file'" | |
| exit 1 |
This comment has been minimized.
This comment has been minimized.
breznak
commented
Sep 16, 2016
|
Q1: does it recover only delete, or all files in given directory? |
This comment has been minimized.
This comment has been minimized.
Jipok
commented
Nov 13, 2017
|
Thank you! It saved me! For some reason, the file began to occupy 0 bytes. This script is the only thing that helped to restore. |
This comment has been minimized.
This comment has been minimized.
MetaPhaze
commented
Jan 10, 2018
|
doesn't seem to work. |
This comment has been minimized.
This comment has been minimized.
Omnicraft
commented
Mar 6, 2018
|
This script totally saved my movie collection folder! |
This comment has been minimized.
This comment has been minimized.
fjf2002
commented
Apr 2, 2018
|
You are sorting byte-addresses descending instead of generation ids descending, aren't you? |
This comment has been minimized.
This comment has been minimized.
MerloRodrigo
commented
Sep 30, 2018
|
Wow! perfect. It's was a beatful work. Thanks a lot |
This comment has been minimized.
This comment has been minimized.
Payden-Pringle
commented
Dec 28, 2018
|
This script is successfully creating files that appear to be the correct size, but they cannot be opened or read correctly with the relevant programs. Not sure what could be wrong here, as the script seems to be working? |
This comment has been minimized.
This comment has been minimized.
splurben
commented
Apr 26, 2019
|
This worked perfectly, better than I ever could have expected, for me. The files I was recovering had only been deleted about 2 minutes before I used the script and I was able to unmount the drive 10 seconds after I accidentally deleted (rm -r) the files. |
This comment has been minimized.
This comment has been minimized.
minhng99
commented
Oct 13, 2019
|
Perfect! |
This comment has been minimized.
This comment has been minimized.
jamalroger
commented
Mar 1, 2020
|
I try to restore my file but i got this errors recover.sh: 32: Bad substitution command |
This comment has been minimized.
This comment has been minimized.
cpbotha
commented
Mar 18, 2020
|
Thank you very much for this script! Did something silly with dvc remove on a directory containing some files that were not committed yet, and your script was able to recover the files. |
This comment has been minimized.
This comment has been minimized.
StarterX4
commented
Apr 21, 2020
•
And then the destination directory is empty. What's happening? |
This comment has been minimized.
This comment has been minimized.
StarterX4
commented
Apr 21, 2020
•
|
Ah ok, there must be "/" instead of "".
|
This comment has been minimized.
breznak commentedSep 16, 2016