From: Martin Wilck <mwi...@arcor.de>

current btrfs restore will discard file attributes. This patch
sets them regular files and directories, as found in the
meta data.

Signed-off-by: Martin Wilck <mwi...@arcor.de>
---
 cmds-restore.c |  116 ++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 101 insertions(+), 15 deletions(-)

diff --git a/cmds-restore.c b/cmds-restore.c
index 2f9b72d..5aa2167 100644
--- a/cmds-restore.c
+++ b/cmds-restore.c
@@ -33,6 +33,7 @@
 #include <zlib.h>
 #include <regex.h>
 #include <getopt.h>
+#include <sys/time.h>
 #include <sys/types.h>
 #include <sys/xattr.h>
 
@@ -549,6 +550,95 @@ out:
        return ret;
 }
 
+#define _INVALID_SIZE ((off_t)~0ULL)
+static int stat_from_inode(struct stat *st, struct btrfs_root *root,
+                          struct btrfs_key *key)
+{
+       static struct btrfs_path *path;
+       struct btrfs_inode_item *inode_item;
+       struct btrfs_timespec *ts;
+       struct extent_buffer *eb;
+
+       if (!path)
+               path = btrfs_alloc_path();
+
+       memset(st, 0, sizeof(*st));
+       st->st_size = _INVALID_SIZE;
+
+       if (!path) {
+               fprintf(stderr, "Ran out of memory\n");
+               return -ENOMEM;
+       }
+
+       if (btrfs_lookup_inode(NULL, root, path, key, 0)) {
+               btrfs_release_path(path);
+               return -ENOENT;
+       }
+
+       inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
+                                   struct btrfs_inode_item);
+       eb = path->nodes[0];
+
+       st->st_size = btrfs_inode_size(eb, inode_item);
+       st->st_uid = btrfs_inode_uid(eb, inode_item);
+       st->st_gid = btrfs_inode_gid(eb, inode_item);
+       st->st_mode = btrfs_inode_mode(eb, inode_item);
+
+       ts = btrfs_inode_atime(eb, inode_item);
+       st->st_atim.tv_sec = ts->sec;
+       st->st_atim.tv_nsec = ts->nsec;
+
+       ts = btrfs_inode_mtime(eb, inode_item);
+       st->st_mtim.tv_sec = ts->sec;
+       st->st_mtim.tv_nsec = ts->nsec;
+
+       ts = btrfs_inode_ctime(eb, inode_item);
+       st->st_ctim.tv_sec = ts->sec;
+       st->st_ctim.tv_nsec = ts->nsec;
+
+       btrfs_release_path(path);
+       return 0;
+}
+
+static void set_fd_attrs(int fd, const struct stat *st, const char *file)
+{
+       struct timeval tv[2];
+       if (st->st_size == _INVALID_SIZE)
+               return;
+
+       tv[0].tv_sec = st->st_atim.tv_sec;
+       tv[0].tv_usec = st->st_atim.tv_nsec/1000;
+       tv[1].tv_sec = st->st_mtim.tv_sec;
+       tv[1].tv_usec = st->st_mtim.tv_nsec/1000;
+       if (S_ISREG(st->st_mode) && ftruncate(fd, st->st_size) == -1)
+               fprintf(stderr, "failed to set file size on %s\n",
+                       file);
+       if (fchown(fd, st->st_uid, st->st_gid) == -1)
+               fprintf(stderr, "failed to set uid/gid on %s\n",
+                       file);
+       if (fchmod(fd, st->st_mode) == -1)
+               fprintf(stderr, "failed to set permissions on %s\n",
+                       file);
+       if (futimes(fd, tv) == -1)
+               fprintf(stderr, "failed to set file times on %s\n",
+                       file);
+}
+
+static int set_file_attrs(const char *output_rootdir, const char *file,
+                         const struct stat *st)
+{
+       int fd;
+       static char path[4096];
+       snprintf(path, sizeof(path), "%s%s", output_rootdir, file);
+       fd = open(path, O_RDONLY|O_NOATIME);
+       if (fd == -1) {
+               fprintf(stderr, "failed to open %s\n", path_name);
+               return -1;
+       }
+       set_fd_attrs(fd, st, path);
+       close(fd);
+       return 0;
+}
 
 static int copy_file(struct btrfs_root *root, int fd, struct btrfs_key *key,
                     const char *file)
@@ -556,13 +646,12 @@ static int copy_file(struct btrfs_root *root, int fd, 
struct btrfs_key *key,
        struct extent_buffer *leaf;
        struct btrfs_path *path;
        struct btrfs_file_extent_item *fi;
-       struct btrfs_inode_item *inode_item;
        struct btrfs_key found_key;
        int ret;
        int extent_type;
        int compression;
        int loops = 0;
-       u64 found_size = 0;
+       struct stat st;
 
        path = btrfs_alloc_path();
        if (!path) {
@@ -570,13 +659,7 @@ static int copy_file(struct btrfs_root *root, int fd, 
struct btrfs_key *key,
                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);
-               found_size = btrfs_inode_size(path->nodes[0], inode_item);
-       }
-       btrfs_release_path(path);
+       stat_from_inode(&st, root, key);
 
        key->offset = 0;
        key->type = BTRFS_EXTENT_DATA_KEY;
@@ -672,16 +755,14 @@ next:
 
        btrfs_free_path(path);
 set_size:
-       if (found_size) {
-               ret = ftruncate(fd, (loff_t)found_size);
-               if (ret)
-                       return ret;
-       }
        if (get_xattrs) {
                ret = set_file_xattrs(root, key->objectid, fd, file);
                if (ret)
-                       return ret;
+                       fprintf(stderr, "failed to set xattrs on %s\n",
+                               file);
        }
+
+       set_fd_attrs(fd, &st, file);
        return 0;
 }
 
@@ -693,6 +774,7 @@ static int search_dir(struct btrfs_root *root, struct 
btrfs_key *key,
        struct extent_buffer *leaf;
        struct btrfs_dir_item *dir_item;
        struct btrfs_key found_key, location;
+       struct stat dirst;
        char filename[BTRFS_NAME_LEN + 1];
        unsigned long name_ptr;
        int name_len;
@@ -707,6 +789,8 @@ static int search_dir(struct btrfs_root *root, struct 
btrfs_key *key,
                return -ENOMEM;
        }
 
+       stat_from_inode(&dirst, root, key);
+
        key->offset = 0;
        key->type = BTRFS_DIR_INDEX_KEY;
 
@@ -931,6 +1015,8 @@ next:
                path->slots[0]++;
        }
 
+       set_file_attrs(output_rootdir, in_dir, &dirst);
+
        if (verbose)
                printf("Done searching %s\n", in_dir);
        btrfs_free_path(path);
-- 
1.7.3.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