restore: Add regex matching of paths and files to be restored

The option -m is used to specify the regex string. -c is used to
specify case insensitive matching. -i was already taken.

In order to restore only a single folder somewhere in the btrfs
tree, it is unfortunately neccessary to construct a slightly
nontrivial regex, e.g.:

restore -m '^/(|home(|/username(|/Desktop(|/.*))))$' /dev/sdb2 /output

This is needed in order to match each directory along the way to the
Desktop directory, as well as all contents below the Desktop directory.

Signed-off-by: Peter Stuge <peter@stuge.se>
Signed-off-by: Josef Bacik <josef@redhat.com>
Signed-off-by: David Sterba <dsterba@suse.cz>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
This commit is contained in:
Peter Stuge 2011-11-25 01:03:58 +01:00 committed by David Sterba
parent 3d86ac20b7
commit e35450fa53

View File

@ -27,9 +27,11 @@
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h>
#include <lzo/lzoconf.h> #include <lzo/lzoconf.h>
#include <lzo/lzo1x.h> #include <lzo/lzo1x.h>
#include <zlib.h> #include <zlib.h>
#include <regex.h>
#include "ctree.h" #include "ctree.h"
#include "disk-io.h" #include "disk-io.h"
@ -539,7 +541,8 @@ set_size:
} }
static int search_dir(struct btrfs_root *root, struct btrfs_key *key, static int search_dir(struct btrfs_root *root, struct btrfs_key *key,
const char *output_rootdir, const char *dir) const char *output_rootdir, const char *dir,
const regex_t *mreg)
{ {
struct btrfs_path *path; struct btrfs_path *path;
struct extent_buffer *leaf; struct extent_buffer *leaf;
@ -646,6 +649,9 @@ static int search_dir(struct btrfs_root *root, struct btrfs_key *key,
/* full path from root of btrfs being restored */ /* full path from root of btrfs being restored */
snprintf(fs_name, 4096, "%s/%s", dir, filename); snprintf(fs_name, 4096, "%s/%s", dir, filename);
if (REG_NOMATCH == regexec(mreg, fs_name, 0, NULL, 0))
goto next;
/* full path from system root */ /* full path from system root */
snprintf(path_name, 4096, "%s%s", output_rootdir, fs_name); snprintf(path_name, 4096, "%s%s", output_rootdir, fs_name);
@ -759,7 +765,7 @@ static int search_dir(struct btrfs_root *root, struct btrfs_key *key,
} }
loops = 0; loops = 0;
ret = search_dir(search_root, &location, ret = search_dir(search_root, &location,
output_rootdir, dir); output_rootdir, dir, mreg);
free(dir); free(dir);
if (ret) { if (ret) {
if (ignore_errors) if (ignore_errors)
@ -990,8 +996,13 @@ int cmd_restore(int argc, char **argv)
int super_mirror = 0; int super_mirror = 0;
int find_dir = 0; int find_dir = 0;
int list_roots = 0; int list_roots = 0;
const char *match_regstr = NULL;
int match_cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
regex_t match_reg, *mreg = NULL;
char reg_err[256];
while ((opt = getopt(argc, argv, "sviot:u:df:r:lcm:")) != -1) {
while ((opt = getopt(argc, argv, "sviot:u:df:r:l")) != -1) {
switch (opt) { switch (opt) {
case 's': case 's':
get_snaps = 1; get_snaps = 1;
@ -1045,6 +1056,12 @@ int cmd_restore(int argc, char **argv)
case 'l': case 'l':
list_roots = 1; list_roots = 1;
break; break;
case 'c':
match_cflags |= REG_ICASE;
break;
case 'm':
match_regstr = optarg;
break;
default: default:
usage(cmd_restore_usage); usage(cmd_restore_usage);
} }
@ -1116,9 +1133,21 @@ int cmd_restore(int argc, char **argv)
key.objectid = BTRFS_FIRST_FREE_OBJECTID; key.objectid = BTRFS_FIRST_FREE_OBJECTID;
} }
ret = search_dir(root, &key, dir_name, ""); if (match_regstr) {
ret = regcomp(&match_reg, match_regstr, match_cflags);
if (ret) {
regerror(ret, &match_reg, reg_err, sizeof(reg_err));
fprintf(stderr, "Regex compile failed: %s\n", reg_err);
goto out;
}
mreg = &match_reg;
}
ret = search_dir(root, &key, dir_name, "", mreg);
out: out:
if (mreg)
regfree(mreg);
close_ctree(root); close_ctree(root);
return ret; return ret;
} }