20

How do I undelete (recover) a deleted file on a btrfs partition?

I have not taken a snapshot yet, so I can't use that feature. I know there are some tools for other Linux file systems, but google has not turned up anything specific to btrfs. I came across one vague mention that btrfs includes an undelete tool, but I can't find it. Before trying tools for another file system, I'm asking here.

More info:

  • The (two) deleted files were deleted by a remote rsync command gone wrong.
  • These were small plain text files.
  • I know the names of the files.
  • I might be able to remember some strings in the files.
  • The disk is a regular HDD, but it is large (2TB).
  • I'm running Kubuntu 12.04 (beta2) with all latest updates.
  • I have not written any new data to the partition the files were deleted from.
  • I don't have a snapshot or a backup of these files. (The last backup is just a few hours older than these files.)
  • Strangely, a COW file system seems to have fewer file undelete options than ext3/4...
8

As your files are small and plain text, I would try scanning the output of "strings" into the device where the filesystem resides, ie,

strings /dev/sda1 | less

then use "/" to search for the strings that could be in that file. When you find the text, delimit the start of it with "m" then move to the end and use "|cat >file" to save it to a file.

I've actually done that when I had a similar situation on another filesystem without undelete, a few years back, and it worked great for me.

4

Jörg Walter implemented a btrfs-undelete shell script using the find-root and restore tools from btrfs-progs, which can be found here, and should help others in a similar position.

As it is licensed under GPLv2, I cannot include it here.

  • 3
    Worth noting is that the said script has at least one path hardcoded (presumably by mistake) and has a few other problems, so buyers beware that it must be edited before use. – gamen Jul 15 '14 at 6:32
  • 1
    Here's a cleaned up version of the original script: gist.github.com/Changaco/45f8d171027ea2655d74 – Changaco Oct 30 '15 at 17:03
  • "As it is licensed under GPLv2, I cannot include it here" - maybe you should read what the GPLv2 says, because that makes no sense whatsoever. – slang Dec 12 '16 at 23:37
  • 4
    @slang maybe you should read the terms of service of this site? Contributions must be licensed under the Creative Commons Attribution Share Alike 3.0 license. – suriv Jan 7 '17 at 16:37
  • @suriv - I guess I can understand their reasons for doing that, but that's pretty annoying. Especially since CC-BY-SA is only slightly more restrictive than the GPL (aside from GPLv3s patent stuff). – Omnifarious Sep 8 '18 at 6:53
2

If your btrfs drive has subvolumes you need to pass the additional -r <subvol-id> option to btrfs restore. Unfortunately the scripts out there, like the one user414471 posted (http://oelkers.de/tips/undeleteBtrfs.sh), don't have an option for doing this, but they can probably be adapted to this.

If you want to do this by hand you need to obtain the right subvol-id, either with:

# mount /dev/sdXY /mnt/blah
# btrfs subvolume list /mnt/blah
# umount /mnt/blah

or alternatively with:

# btrfs restore -l /dev/sdXY | grep ROOT_ITEM

Afterwards you use btrfs-find-root to get the block number to which you want to revert (usually the one just before the maximum one which is the current root). For this you need to first set the default subvolume to the one from which you want to revert files (and revert this change afterwards):

# mount /dev/sdXY /mnt/blah
# btrfs subvolume set-default <subvol-id> /mnt/blah
# umount /mnt/blah
# btrfs-find-root /dev/sdXY
Well block 4321280 seems great, but generation doesn't match, have=400760, want=400984 level 0
...
Well block 9928704 seems great, but generation doesn't match, have=400764, want=400984 level 1
Well block 1094836224 seems great, but generation doesn't match, have=400983, want=400984 level 1
Found tree root at 1095270400 gen 400984 level 1

You can finally use btrfs restore with -r <subvol-id> for the recovery (initially with the --dry-run argument if you wish):

# btrfs restore -r <subvol-id> -t 9928704 -v --path-regex '^/(|dir1(|/dir2(|/dir3(|/.*))))$' /dev/sdXY /tmp/recovery

More information about all this here: https://btrfs.wiki.kernel.org/index.php/Restore

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.