How do I generate a regex to restore a specific folder for "btrfs restore"?

I am trying to recover files after a crash of a btrfs filesystem using:

btrfs restore --path-regex 'regex' -sv -D /dev/sdXX /mnt/destination

for example, to retrieve all files in /snapshots/@_2018-06-01T23:29:33-04:00.preupgrade/ I tried following http://www.kossboss.com/?p=2277 and got (among many other attempts):

^/(|/snapshots(|/\@\_2018\-06\-01T23\:29\:33\-04\:00\.preupgrade(|/.*)))$

This failed to select any files. I have tried 5 hrs of things. I am at a loss.

What am I doing wrong? How can I make it work?

It needs to be selective for a number of reasons. Manly because it fails in the middle and I need to script selective attempts to retrieve viable files beyond the fails.


Solution 1:

btrfs restore scans through the filesystem starting at the root and compares each entry to the regex. If the path matches the regex and it is a directory, it will scan that directory. If it's a file and it matches, it will restore it.

What this means is that every parent directory of the file/directory that you're trying to restore needs to be matched by the regex to ensure that the restore program will eventually get to it.

What the sample regex from the manpage ^/(|home(|/username(|/Desktop(|/.*))))$ really means is, "/ followed by nothing or home followed by nothing or /username followed by nothing or /Desktop followed by nothing or /.*", which is equivalent to "/ or /home or /home/username or /home/username/Desktop or /home/username/Desktop/.*".

The unsual (|/foo) construction is matching nothing or /foo and the nested capture groups are just to be able to nest the or statements.

For readability's sake, I would suggest writing the regex as ^(/|/home|/home/username|/home/username/Desktop/|/home/username/Desktop/.*)$, which I think is a lot clearer as to what it is doing.