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.meril...@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
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to