From: Dan Merillat <dan.merillat@gmail.com>
To: BTRFS <linux-btrfs@vger.kernel.org>
Subject: [PATCH v2 1/1] btrfs-progs: optionally restore metadata
Date: Tue, 21 Apr 2015 01:48:24 -0400 [thread overview]
Message-ID: <5535E4A8.8040600@gmail.com> (raw)
As long as the inode is intact, the file metadata can be restored.
Directory data is restored at the end of search_dir. Errors are
checked and returned, unless ignore_errors is requested.
Signed-off-by: Dan Merillat <dan.merillat@gmail.com>
---
Documentation/btrfs-restore.txt | 3 ++
cmds-restore.c | 114 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 116 insertions(+), 1 deletion(-)
diff --git a/Documentation/btrfs-restore.txt b/Documentation/btrfs-restore.txt
index 20fc366..a4e4d37 100644
--- a/Documentation/btrfs-restore.txt
+++ b/Documentation/btrfs-restore.txt
@@ -29,6 +29,9 @@ get snapshots, btrfs restore skips snapshots in default.
-x::
get extended attributes.
+-m|--metadata::
+set owner, permissions, access time and modify time.
+
-v::
verbose.
diff --git a/cmds-restore.c b/cmds-restore.c
index d2fc951..e95018f 100644
--- a/cmds-restore.c
+++ b/cmds-restore.c
@@ -48,6 +48,7 @@ static char fs_name[4096];
static char path_name[4096];
static int get_snaps = 0;
static int verbose = 0;
+static int restore_metadata = 0;
static int ignore_errors = 0;
static int overwrite = 0;
static int get_xattrs = 0;
@@ -547,6 +548,57 @@ out:
return ret;
}
+static int copy_metadata(struct btrfs_root *root, int fd,
+ struct btrfs_key *key)
+{
+ struct btrfs_path *path;
+ struct btrfs_inode_item *inode_item;
+ int ret;
+
+ path = btrfs_alloc_path();
+ if (!path) {
+ fprintf(stderr, "Ran out of memory\n");
+ return -ENOMEM;
+ }
+
+ ret = btrfs_lookup_inode(NULL, root, path, key, 0);
+ if (ret == 0) {
+
+ inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
+ struct btrfs_inode_item);
+
+ ret=fchown(fd, btrfs_inode_uid(path->nodes[0], inode_item),
+ btrfs_inode_gid(path->nodes[0], inode_item));
+ if (ret) {
+ fprintf(stderr, "Failed to change owner: %s\n", strerror(errno));
+ goto out;
+ }
+ ret=fchmod(fd, btrfs_inode_mode(path->nodes[0], inode_item));
+ if (ret) {
+ fprintf(stderr, "Failed to change mode: %s\n", strerror(errno));
+ goto out;
+ }
+ struct btrfs_timespec *bts;
+ struct timespec times[2];
+
+ bts = btrfs_inode_atime(inode_item);
+ times[0].tv_sec=btrfs_timespec_sec(path->nodes[0], bts);
+ times[0].tv_nsec=btrfs_timespec_nsec(path->nodes[0], bts);
+
+ bts = btrfs_inode_mtime(inode_item);
+ times[1].tv_sec=btrfs_timespec_sec(path->nodes[0], bts);
+ times[1].tv_nsec=btrfs_timespec_nsec(path->nodes[0], bts);
+
+ ret=futimens(fd, times);
+ if (ret) {
+ fprintf(stderr, "Failed to set times: %s\n", strerror(errno));
+ goto out;
+ }
+ }
+out:
+ btrfs_release_path(path);
+ return ret;
+}
static int copy_file(struct btrfs_root *root, int fd, struct btrfs_key *key,
const char *file)
@@ -555,6 +607,7 @@ static int copy_file(struct btrfs_root *root, int fd, struct btrfs_key *key,
struct btrfs_path *path;
struct btrfs_file_extent_item *fi;
struct btrfs_inode_item *inode_item;
+ struct btrfs_timespec *bts;
struct btrfs_key found_key;
int ret;
int extent_type;
@@ -567,12 +620,41 @@ static int copy_file(struct btrfs_root *root, int fd, struct btrfs_key *key,
fprintf(stderr, "Ran out of memory\n");
return -ENOMEM;
}
+ struct timespec times[2];
+ int times_ok=0;
ret = btrfs_lookup_inode(NULL, root, path, key, 0);
if (ret == 0) {
inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_inode_item);
found_size = btrfs_inode_size(path->nodes[0], inode_item);
+
+ if (restore_metadata) {
+ /* change the ownership and mode now, set times when
+ * copyout is finished */
+
+ ret=fchown(fd, btrfs_inode_uid(path->nodes[0], inode_item),
+ btrfs_inode_gid(path->nodes[0], inode_item));
+ if (ret && !ignore_errors) {
+ btrfs_release_path(path);
+ return ret;
+ }
+
+ ret=fchmod(fd, btrfs_inode_mode(path->nodes[0], inode_item));
+ if (ret && !ignore_errors) {
+ btrfs_release_path(path);
+ return ret;
+ }
+
+ bts = btrfs_inode_atime(inode_item);
+ times[0].tv_sec=btrfs_timespec_sec(path->nodes[0], bts);
+ times[0].tv_nsec=btrfs_timespec_nsec(path->nodes[0], bts);
+
+ bts = btrfs_inode_mtime(inode_item);
+ times[1].tv_sec=btrfs_timespec_sec(path->nodes[0], bts);
+ times[1].tv_nsec=btrfs_timespec_nsec(path->nodes[0], bts);
+ times_ok=1;
+ }
}
btrfs_release_path(path);
@@ -680,6 +762,11 @@ set_size:
if (ret)
return ret;
}
+ if (restore_metadata && times_ok) {
+ ret=futimens(fd, times);
+ if (ret)
+ return ret;
+ }
return 0;
}
@@ -929,6 +1016,25 @@ next:
path->slots[0]++;
}
+ if (restore_metadata) {
+ snprintf(path_name, 4096, "%s%s", output_rootdir, in_dir);
+ fd = open(path_name, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Failed to access %s to restore metadata\n", path_name);
+ if (!ignore_errors)
+ return -1;
+ } else {
+ // set owner/mode/time on the directory as well
+ key->type=BTRFS_INODE_ITEM_KEY;
+ ret=copy_metadata(root, fd, key);
+ close(fd);
+ if (ret && !ignore_errors) {
+ btrfs_free_path(path);
+ return ret;
+ }
+ }
+ }
+
if (verbose)
printf("Done searching %s\n", in_dir);
btrfs_free_path(path);
@@ -1126,6 +1232,7 @@ const char * const cmd_restore_usage[] = {
"",
"-s get snapshots",
"-x get extended attributes",
+ "-m|--metadata restore owner, mode and times",
"-v verbose",
"-i ignore errors",
"-o overwrite",
@@ -1168,10 +1275,12 @@ int cmd_restore(int argc, char **argv)
static const struct option long_options[] = {
{ "path-regex", 1, NULL, 256},
{ "dry-run", 0, NULL, 'D'},
+ { "metadata", 0, NULL, 'm'},
+ { "debug-regex", 0, NULL, 257},
{ NULL, 0, NULL, 0}
};
- opt = getopt_long(argc, argv, "sxviot:u:df:r:lDc", long_options,
+ opt = getopt_long(argc, argv, "sxviot:u:dmf:r:lDc", long_options,
&option_index);
if (opt < 0)
break;
@@ -1217,6 +1326,9 @@ int cmd_restore(int argc, char **argv)
case 'l':
list_roots = 1;
break;
+ case 'm':
+ restore_metadata = 1;
+ break;
case 'D':
dry_run = 1;
break;
--
2.1.4
next reply other threads:[~2015-04-21 5:48 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-04-21 5:48 Dan Merillat [this message]
2015-04-22 16:53 ` [PATCH v2 1/1] btrfs-progs: optionally restore metadata David Sterba
2015-04-23 9:31 ` Dan Merillat
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5535E4A8.8040600@gmail.com \
--to=dan.merillat@gmail.com \
--cc=linux-btrfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox