btrfs-progs: image: drop unused parameter from sanitize_xattr
[platform/upstream/btrfs-progs.git] / image / main.c
index 378a0d4..a5777dd 100644 (file)
 #include "volumes.h"
 #include "extent_io.h"
 #include "help.h"
-
-#define HEADER_MAGIC           0xbd5c25e27295668bULL
-#define MAX_PENDING_SIZE       (256 * 1024)
-#define BLOCK_SIZE             1024
-#define BLOCK_MASK             (BLOCK_SIZE - 1)
-
-#define COMPRESS_NONE          0
-#define COMPRESS_ZLIB          1
+#include "image/metadump.h"
+#include "image/sanitize.h"
 
 #define MAX_WORKER_THREADS     (32)
 
-struct meta_cluster_item {
-       __le64 bytenr;
-       __le32 size;
-} __attribute__ ((__packed__));
-
-struct meta_cluster_header {
-       __le64 magic;
-       __le64 bytenr;
-       __le32 nritems;
-       u8 compress;
-} __attribute__ ((__packed__));
-
-/* cluster header + index items + buffers */
-struct meta_cluster {
-       struct meta_cluster_header header;
-       struct meta_cluster_item items[];
-} __attribute__ ((__packed__));
-
-#define ITEMS_PER_CLUSTER ((BLOCK_SIZE - sizeof(struct meta_cluster)) / \
-                          sizeof(struct meta_cluster_item))
-
-struct fs_chunk {
-       u64 logical;
-       u64 physical;
-       /*
-        * physical_dup only store additonal physical for BTRFS_BLOCK_GROUP_DUP
-        * currently restore only support single and DUP
-        * TODO: modify this structure and the function related to this
-        * structure for support RAID*
-        */
-       u64 physical_dup;
-       u64 bytes;
-       struct rb_node l;
-       struct rb_node p;
-       struct list_head list;
-};
-
 struct async_work {
        struct list_head list;
        struct list_head ordered;
@@ -120,18 +77,11 @@ struct metadump_struct {
        int compress_level;
        int done;
        int data;
-       int sanitize_names;
+       enum sanitize_mode sanitize_names;
 
        int error;
 };
 
-struct name {
-       struct rb_node n;
-       char *val;
-       char *sub;
-       u32 len;
-};
-
 struct mdrestore_struct {
        FILE *in;
        FILE *out;
@@ -408,17 +358,65 @@ static const u32 crc32c_rev_table[256] = {
        0x588982AFL,0x5D65F45EL,0x53516F4DL,0x56BD19BCL
 };
 
-static int find_collision_brute_force(struct name *val, u32 name_len)
+/*
+ * Calculate a 4-byte suffix to match desired CRC32C
+ *
+ * @current_crc: CRC32C checksum of all bytes before the suffix
+ * @desired_crc: the checksum that we want to get after adding the suffix
+ *
+ * Outputs: @suffix: pointer to where the suffix will be written (4-bytes)
+ */
+static void find_collision_calc_suffix(unsigned long current_crc,
+                                      unsigned long desired_crc,
+                                      char *suffix)
+{
+       int i;
+
+       for(i = 3; i >= 0; i--) {
+               desired_crc = (desired_crc << 8)
+                           ^ crc32c_rev_table[desired_crc >> 24 & 0xFF]
+                           ^ ((current_crc >> i * 8) & 0xFF);
+       }
+       for (i = 0; i < 4; i++)
+               suffix[i] = (desired_crc >> i * 8) & 0xFF;
+}
+
+/*
+ * Check if suffix is valid according to our file name conventions
+ */
+static int find_collision_is_suffix_valid(const char *suffix)
+{
+       int i;
+       char c;
+
+       for (i = 0; i < 4; i++) {
+               c = suffix[i];
+               if (c < ' ' || c > 126 || c == '/')
+                       return 0;
+       }
+       return 1;
+}
+
+static int find_collision_reverse_crc32c(struct name *val, u32 name_len)
 {
        unsigned long checksum;
+       unsigned long current_checksum;
        int found = 0;
        int i;
 
+       /* There are no same length collisions of 4 or less bytes */
+       if (name_len <= 4)
+               return 0;
        checksum = crc32c(~1, val->val, name_len);
+       name_len -= 4;
        memset(val->sub, ' ', name_len);
        i = 0;
        while (1) {
-               if (crc32c(~1, val->sub, name_len) == checksum &&
+               current_checksum = crc32c(~1, val->sub, name_len);
+               find_collision_calc_suffix(current_checksum,
+                                          checksum,
+                                          val->sub + name_len);
+               if (find_collision_is_suffix_valid(val->sub + name_len) &&
                    memcmp(val->sub, val->val, val->len)) {
                        found = 1;
                        break;
@@ -448,7 +446,7 @@ static int find_collision_brute_force(struct name *val, u32 name_len)
        return found;
 }
 
-static char *find_collision(struct metadump_struct *md, char *name,
+static char *find_collision(struct rb_root *name_tree, char *name,
                            u32 name_len)
 {
        struct name *val;
@@ -459,7 +457,7 @@ static char *find_collision(struct metadump_struct *md, char *name,
 
        tmp.val = name;
        tmp.len = name_len;
-       entry = tree_search(&md->name_tree, &tmp.n, name_cmp, 0);
+       entry = tree_search(name_tree, &tmp.n, name_cmp, 0);
        if (entry) {
                val = rb_entry(entry, struct name, n);
                free(name);
@@ -485,7 +483,7 @@ static char *find_collision(struct metadump_struct *md, char *name,
                return NULL;
        }
 
-       found = find_collision_brute_force(val, name_len);
+       found = find_collision_reverse_crc32c(val, name_len);
 
        if (!found) {
                warning(
@@ -500,7 +498,7 @@ static char *find_collision(struct metadump_struct *md, char *name,
                }
        }
 
-       tree_insert(&md->name_tree, &val->n, name_cmp);
+       tree_insert(name_tree, &val->n, name_cmp);
        return val->sub;
 }
 
@@ -515,7 +513,7 @@ static void sanitize_dir_item(struct metadump_struct *md, struct extent_buffer *
        u32 cur = 0;
        u32 this_len;
        u32 name_len;
-       int free_garbage = (md->sanitize_names == 1);
+       int free_garbage = (md->sanitize_names == SANITIZE_NAMES);
 
        dir_item = btrfs_item_ptr(eb, slot, struct btrfs_dir_item);
        total_len = btrfs_item_size_nr(eb, slot);
@@ -526,14 +524,14 @@ static void sanitize_dir_item(struct metadump_struct *md, struct extent_buffer *
                name_ptr = (unsigned long)(dir_item + 1);
                name_len = btrfs_dir_name_len(eb, dir_item);
 
-               if (md->sanitize_names > 1) {
+               if (md->sanitize_names == SANITIZE_COLLISIONS) {
                        buf = malloc(name_len);
                        if (!buf) {
                                error("cannot sanitize name, not enough memory");
                                return;
                        }
                        read_extent_buffer(eb, buf, name_ptr, name_len);
-                       garbage = find_collision(md, buf, name_len);
+                       garbage = find_collision(&md->name_tree, buf, name_len);
                } else {
                        garbage = generate_garbage(name_len);
                }
@@ -561,7 +559,7 @@ static void sanitize_inode_ref(struct metadump_struct *md,
        u32 item_size;
        u32 cur_offset = 0;
        int len;
-       int free_garbage = (md->sanitize_names == 1);
+       int free_garbage = (md->sanitize_names == SANITIZE_NAMES);
 
        item_size = btrfs_item_size_nr(eb, slot);
        ptr = btrfs_item_ptr_offset(eb, slot);
@@ -580,14 +578,14 @@ static void sanitize_inode_ref(struct metadump_struct *md,
                }
                cur_offset += len;
 
-               if (md->sanitize_names > 1) {
+               if (md->sanitize_names == SANITIZE_COLLISIONS) {
                        buf = malloc(len);
                        if (!buf) {
                                error("cannot sanitize name, not enough memory");
                                return;
                        }
                        read_extent_buffer(eb, buf, name_ptr, len);
-                       garbage = find_collision(md, buf, len);
+                       garbage = find_collision(&md->name_tree, buf, len);
                } else {
                        garbage = generate_garbage(len);
                }
@@ -602,8 +600,7 @@ static void sanitize_inode_ref(struct metadump_struct *md,
        }
 }
 
-static void sanitize_xattr(struct metadump_struct *md,
-                          struct extent_buffer *eb, int slot)
+static void sanitize_xattr(struct extent_buffer *eb, int slot)
 {
        struct btrfs_dir_item *dir_item;
        unsigned long data_ptr;
@@ -643,7 +640,7 @@ static void sanitize_name(struct metadump_struct *md, u8 *dst,
                sanitize_inode_ref(md, eb, slot, 1);
                break;
        case BTRFS_XATTR_ITEM_KEY:
-               sanitize_xattr(md, eb, slot);
+               sanitize_xattr(eb, slot);
                break;
        default:
                break;
@@ -824,7 +821,7 @@ static void metadump_destroy(struct metadump_struct *md, int num_threads)
 
 static int metadump_init(struct metadump_struct *md, struct btrfs_root *root,
                         FILE *out, int num_threads, int compress_level,
-                        int sanitize_names)
+                        enum sanitize_mode sanitize_names)
 {
        int i, ret = 0;
 
@@ -836,7 +833,7 @@ static int metadump_init(struct metadump_struct *md, struct btrfs_root *root,
        md->pending_start = (u64)-1;
        md->compress_level = compress_level;
        md->sanitize_names = sanitize_names;
-       if (sanitize_names > 1)
+       if (sanitize_names == SANITIZE_COLLISIONS)
                crc32c_optimization_init();
 
        md->name_tree.rb_node = NULL;
@@ -1401,7 +1398,8 @@ static int copy_from_extent_tree(struct metadump_struct *metadump,
 }
 
 static int create_metadump(const char *input, FILE *out, int num_threads,
-                          int compress_level, int sanitize, int walk_trees)
+                          int compress_level, enum sanitize_mode sanitize,
+                          int walk_trees)
 {
        struct btrfs_root *root;
        struct btrfs_path path;
@@ -2817,7 +2815,7 @@ int main(int argc, char *argv[])
        int walk_trees = 0;
        int multi_devices = 0;
        int ret;
-       int sanitize = 0;
+       enum sanitize_mode sanitize = SANITIZE_NONE;
        int dev_cnt = 0;
        int usage_error = 0;
        FILE *out;
@@ -2855,7 +2853,10 @@ int main(int argc, char *argv[])
                        old_restore = 1;
                        break;
                case 's':
-                       sanitize++;
+                       if (sanitize == SANITIZE_NONE)
+                               sanitize = SANITIZE_NAMES;
+                       else if (sanitize == SANITIZE_NAMES)
+                               sanitize = SANITIZE_COLLISIONS;
                        break;
                case 'w':
                        walk_trees = 1;
@@ -2883,7 +2884,7 @@ int main(int argc, char *argv[])
                        usage_error++;
                }
        } else {
-               if (walk_trees || sanitize || compress_level) {
+               if (walk_trees || sanitize != SANITIZE_NONE || compress_level) {
                        error(
                        "useing -w, -s, -c options for restore makes no sense");
                        usage_error++;