packaging: Enable LTO and set visibility to hidden
[platform/upstream/btrfs-progs.git] / cmds-restore.c
index 09388b2..f228aca 100644 (file)
@@ -29,6 +29,9 @@
 #include <lzo/lzoconf.h>
 #include <lzo/lzo1x.h>
 #include <zlib.h>
+#if BTRFSRESTORE_ZSTD
+#include <zstd.h>
+#endif
 #include <regex.h>
 #include <getopt.h>
 #include <sys/types.h>
@@ -156,6 +159,50 @@ static int decompress_lzo(struct btrfs_root *root, unsigned char *inbuf,
        return 0;
 }
 
+static int decompress_zstd(const char *inbuf, char *outbuf, u64 compress_len,
+                          u64 decompress_len)
+{
+#if !BTRFSRESTORE_ZSTD
+       error("btrfs not compiled with zstd support");
+       return -1;
+#else
+       ZSTD_DStream *strm;
+       size_t zret;
+       int ret = 0;
+       ZSTD_inBuffer in = {inbuf, compress_len, 0};
+       ZSTD_outBuffer out = {outbuf, decompress_len, 0};
+
+       strm = ZSTD_createDStream();
+       if (!strm) {
+               error("zstd create failed");
+               return -1;
+       }
+
+       zret = ZSTD_initDStream(strm);
+       if (ZSTD_isError(zret)) {
+               error("zstd init failed: %s", ZSTD_getErrorName(zret));
+               ret = -1;
+               goto out;
+       }
+
+       zret = ZSTD_decompressStream(strm, &out, &in);
+       if (ZSTD_isError(zret)) {
+               error("zstd decompress failed %s\n", ZSTD_getErrorName(zret));
+               ret = -1;
+               goto out;
+       }
+       if (zret != 0) {
+               error("zstd frame incomplete");
+               ret = -1;
+               goto out;
+       }
+
+out:
+       ZSTD_freeDStream(strm);
+       return ret;
+#endif
+}
+
 static int decompress(struct btrfs_root *root, char *inbuf, char *outbuf,
                        u64 compress_len, u64 *decompress_len, int compress)
 {
@@ -166,6 +213,9 @@ static int decompress(struct btrfs_root *root, char *inbuf, char *outbuf,
        case BTRFS_COMPRESS_LZO:
                return decompress_lzo(root, (unsigned char *)inbuf, outbuf,
                                        compress_len, decompress_len);
+       case BTRFS_COMPRESS_ZSTD:
+               return decompress_zstd(inbuf, outbuf, compress_len,
+                                      *decompress_len);
        default:
                break;
        }
@@ -181,6 +231,7 @@ static int next_leaf(struct btrfs_root *root, struct btrfs_path *path)
        int offset = 1;
        struct extent_buffer *c;
        struct extent_buffer *next = NULL;
+       struct btrfs_fs_info *fs_info = root->fs_info;
 
 again:
        for (; level < BTRFS_MAX_LEVEL; level++) {
@@ -210,7 +261,7 @@ again:
                if (path->reada)
                        reada_for_search(root, path, level, slot, 0);
 
-               next = read_node_slot(root, c, slot);
+               next = read_node_slot(fs_info, c, slot);
                if (extent_buffer_uptodate(next))
                        break;
                offset++;
@@ -226,7 +277,7 @@ again:
                        break;
                if (path->reada)
                        reada_for_search(root, path, level, 0, 0);
-               next = read_node_slot(root, next, 0);
+               next = read_node_slot(fs_info, next, 0);
                if (!extent_buffer_uptodate(next))
                        goto again;
        }
@@ -345,8 +396,8 @@ static int copy_one_extent(struct btrfs_root *root, int fd,
        }
 again:
        length = size_left;
-       ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
-                             bytenr, &length, &multi, mirror_num, NULL);
+       ret = btrfs_map_block(root->fs_info, READ, bytenr, &length, &multi,
+                             mirror_num, NULL);
        if (ret) {
                error("cannot map block logical %llu length %llu: %d",
                                (unsigned long long)bytenr,
@@ -365,8 +416,7 @@ again:
        done = pread(dev_fd, inbuf+count, length, dev_bytenr);
        /* Need both checks, or we miss negative values due to u64 conversion */
        if (done < 0 || done < length) {
-               num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
-                                             bytenr, length);
+               num_copies = btrfs_num_copies(root->fs_info, bytenr, length);
                mirror_num++;
                /* mirror_num is 1-indexed, so num_copies is a valid mirror. */
                if (mirror_num > num_copies) {
@@ -392,7 +442,7 @@ again:
                                      pos+total);
                        if (done < 0) {
                                ret = -1;
-                               error("cannot write data: %d %s", errno, strerror(errno));
+                               error("cannot write data: %d %m", errno);
                                goto out;
                        }
                        total += done;
@@ -403,8 +453,7 @@ again:
 
        ret = decompress(root, inbuf, outbuf, disk_size, &ram_size, compress);
        if (ret) {
-               num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
-                                             bytenr, length);
+               num_copies = btrfs_num_copies(root->fs_info, bytenr, length);
                mirror_num++;
                if (mirror_num >= num_copies) {
                        ret = -1;
@@ -538,8 +587,8 @@ static int set_file_xattrs(struct btrfs_root *root, u64 inode,
                        data_len = len;
 
                        if (fsetxattr(fd, name, data, data_len, 0))
-                               error("setting extended attribute %s on file %s: %s",
-                                       name, file_name, strerror(errno));
+                               error("setting extended attribute %s on file %s: %m",
+                                       name, file_name);
 
                        len = sizeof(*di) + name_len + data_len;
                        cur += len;
@@ -575,13 +624,13 @@ static int copy_metadata(struct btrfs_root *root, int fd,
                ret = fchown(fd, btrfs_inode_uid(path.nodes[0], inode_item),
                                btrfs_inode_gid(path.nodes[0], inode_item));
                if (ret) {
-                       error("failed to change owner: %s", strerror(errno));
+                       error("failed to change owner: %m");
                        goto out;
                }
 
                ret = fchmod(fd, btrfs_inode_mode(path.nodes[0], inode_item));
                if (ret) {
-                       error("failed to change mode: %s", strerror(errno));
+                       error("failed to change mode: %m");
                        goto out;
                }
 
@@ -595,7 +644,7 @@ static int copy_metadata(struct btrfs_root *root, int fd,
 
                ret = futimens(fd, times);
                if (ret) {
-                       error("failed to set times: %s", strerror(errno));
+                       error("failed to set times: %m");
                        goto out;
                }
        }
@@ -855,8 +904,8 @@ static int copy_symlink(struct btrfs_root *root, struct btrfs_key *key,
        if (!dry_run) {
                ret = symlink(symlink_target, path_name);
                if (ret < 0) {
-                       fprintf(stderr, "Failed to restore symlink '%s': %s\n",
-                                       path_name, strerror(errno));
+                       fprintf(stderr, "Failed to restore symlink '%s': %m\n",
+                                       path_name);
                        goto out;
                }
        }
@@ -888,8 +937,7 @@ static int copy_symlink(struct btrfs_root *root, struct btrfs_key *key,
                                   btrfs_inode_gid(path.nodes[0], inode_item),
                                   AT_SYMLINK_NOFOLLOW);
        if (ret) {
-               fprintf(stderr, "Failed to change owner: %s\n",
-                               strerror(errno));
+               fprintf(stderr, "Failed to change owner: %m\n");
                goto out;
        }
 
@@ -903,7 +951,7 @@ static int copy_symlink(struct btrfs_root *root, struct btrfs_key *key,
 
        ret = utimensat(-1, file, times, AT_SYMLINK_NOFOLLOW);
        if (ret)
-               fprintf(stderr, "Failed to set times: %s\n", strerror(errno));
+               fprintf(stderr, "Failed to set times: %m\n");
 out:
        btrfs_release_path(&path);
        return ret;
@@ -1233,8 +1281,15 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location,
 
        for (i = super_mirror; i < BTRFS_SUPER_MIRROR_MAX; i++) {
                bytenr = btrfs_sb_offset(i);
+
+               /*
+                * Restore won't allocate extent and doesn't care anything
+                * in extent tree. Skip block group item search will allow
+                * restore to be executed on heavily damaged fs.
+                */
                fs_info = open_ctree_fs_info(dev, bytenr, root_location, 0,
-                                            OPEN_CTREE_PARTIAL);
+                                            OPEN_CTREE_PARTIAL |
+                                            OPEN_CTREE_NO_BLOCK_GROUPS);
                if (fs_info)
                        break;
                fprintf(stderr, "Could not open root, trying backup super\n");
@@ -1255,8 +1310,8 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location,
                if (!root_location)
                        root_location = btrfs_super_root(fs_info->super_copy);
                generation = btrfs_super_generation(fs_info->super_copy);
-               root->node = read_tree_block(root, root_location,
-                                            fs_info->nodesize, generation);
+               root->node = read_tree_block(fs_info, root_location,
+                                            generation);
                if (!extent_buffer_uptodate(root->node)) {
                        fprintf(stderr, "Error opening tree root\n");
                        close_ctree(root);
@@ -1502,8 +1557,7 @@ int cmd_restore(int argc, char **argv)
 
        if (fs_location != 0) {
                free_extent_buffer(root->node);
-               root->node = read_tree_block(root, fs_location,
-                               root->fs_info->nodesize, 0);
+               root->node = read_tree_block(root->fs_info, fs_location, 0);
                if (!extent_buffer_uptodate(root->node)) {
                        fprintf(stderr, "Failed to read fs location\n");
                        ret = 1;