btrfs-progs: check: introduce function to check data backref in extent tree
[platform/upstream/btrfs-progs.git] / btrfs-list.c
index 9effb27..4cc2ed4 100644 (file)
  * Boston, MA 021110-1307, USA.
  */
 
-#define _GNU_SOURCE
 #include <sys/ioctl.h>
 #include <sys/mount.h>
-#include "ioctl.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include "ctree.h"
 #include "transaction.h"
 #include "utils.h"
+#include "ioctl.h"
 #include <uuid/uuid.h>
 #include "btrfs-list.h"
+#include "rbtree-utils.h"
 
 #define BTRFS_LIST_NFILTERS_INCREASE   (2 * BTRFS_LIST_FILTER_MAX)
 #define BTRFS_LIST_NCOMPS_INCREASE     (2 * BTRFS_LIST_COMP_MAX)
@@ -85,6 +85,11 @@ static struct {
                .need_print     = 0,
        },
        {
+               .name           = "received_uuid",
+               .column_name    = "Received UUID",
+               .need_print     = 0,
+       },
+       {
                .name           = "uuid",
                .column_name    = "UUID",
                .need_print     = 0,
@@ -221,13 +226,12 @@ struct btrfs_list_comparer_set *btrfs_list_alloc_comparer_set(void)
 
        size = sizeof(struct btrfs_list_comparer_set) +
               BTRFS_LIST_NCOMPS_INCREASE * sizeof(struct btrfs_list_comparer);
-       set = malloc(size);
+       set = calloc(1, size);
        if (!set) {
                fprintf(stderr, "memory allocation failed\n");
                exit(1);
        }
 
-       memset(set, 0, size);
        set->total = BTRFS_LIST_NCOMPS_INCREASE;
 
        return set;
@@ -249,11 +253,15 @@ static int btrfs_list_setup_comparer(struct btrfs_list_comparer_set **comp_set,
        BUG_ON(set->ncomps > set->total);
 
        if (set->ncomps == set->total) {
+               void *tmp;
+
                size = set->total + BTRFS_LIST_NCOMPS_INCREASE;
                size = sizeof(*set) + size * sizeof(struct btrfs_list_comparer);
+               tmp = set;
                set = realloc(set, size);
                if (!set) {
                        fprintf(stderr, "memory allocation failed\n");
+                       free(tmp);
                        exit(1);
                }
 
@@ -391,7 +399,7 @@ static struct root_info *root_tree_search(struct root_lookup *root_tree,
 static int update_root(struct root_lookup *root_lookup,
                       u64 root_id, u64 ref_tree, u64 root_offset, u64 flags,
                       u64 dir_id, char *name, int name_len, u64 ogen, u64 gen,
-                      time_t ot, void *uuid, void *puuid)
+                      time_t ot, void *uuid, void *puuid, void *ruuid)
 {
        struct root_info *ri;
 
@@ -429,6 +437,8 @@ static int update_root(struct root_lookup *root_lookup,
                memcpy(&ri->uuid, uuid, BTRFS_UUID_SIZE);
        if (puuid)
                memcpy(&ri->puuid, puuid, BTRFS_UUID_SIZE);
+       if (ruuid)
+               memcpy(&ri->ruuid, ruuid, BTRFS_UUID_SIZE);
 
        return 0;
 }
@@ -447,26 +457,27 @@ static int update_root(struct root_lookup *root_lookup,
  * ot: the original time(create time) of the root
  * uuid: uuid of the root
  * puuid: uuid of the root parent if any
+ * ruuid: uuid of the received subvol, if any
  */
 static int add_root(struct root_lookup *root_lookup,
                    u64 root_id, u64 ref_tree, u64 root_offset, u64 flags,
                    u64 dir_id, char *name, int name_len, u64 ogen, u64 gen,
-                   time_t ot, void *uuid, void *puuid)
+                   time_t ot, void *uuid, void *puuid, void *ruuid)
 {
        struct root_info *ri;
        int ret;
 
        ret = update_root(root_lookup, root_id, ref_tree, root_offset, flags,
-                         dir_id, name, name_len, ogen, gen, ot, uuid, puuid);
+                         dir_id, name, name_len, ogen, gen, ot,
+                         uuid, puuid, ruuid);
        if (!ret)
                return 0;
 
-       ri = malloc(sizeof(*ri));
+       ri = calloc(1, sizeof(*ri));
        if (!ri) {
                printf("memory allocation failed\n");
                exit(1);
        }
-       memset(ri, 0, sizeof(*ri));
        ri->root_id = root_id;
 
        if (name && name_len > 0) {
@@ -501,6 +512,9 @@ static int add_root(struct root_lookup *root_lookup,
        if (puuid)
                memcpy(&ri->puuid, puuid, BTRFS_UUID_SIZE);
 
+       if (ruuid)
+               memcpy(&ri->ruuid, ruuid, BTRFS_UUID_SIZE);
+
        ret = root_tree_insert(root_lookup, ri);
        if (ret) {
                printf("failed to insert tree %llu\n", (unsigned long long)root_id);
@@ -550,7 +564,7 @@ static int resolve_root(struct root_lookup *rl, struct root_info *ri,
                int add_len;
 
                /*
-                * ref_tree = 0 indicates the subvolumes
+                * ref_tree = 0 indicates the subvolume
                 * has been deleted.
                 */
                if (!found->ref_tree) {
@@ -616,7 +630,7 @@ static int resolve_root(struct root_lookup *rl, struct root_info *ri,
 static int lookup_ino_path(int fd, struct root_info *ri)
 {
        struct btrfs_ioctl_ino_lookup_args args;
-       int ret, e;
+       int ret;
 
        if (ri->path)
                return 0;
@@ -629,15 +643,14 @@ static int lookup_ino_path(int fd, struct root_info *ri)
        args.objectid = ri->dir_id;
 
        ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
-       e = errno;
-       if (ret) {
-               if (e == ENOENT) {
+       if (ret < 0) {
+               if (errno == ENOENT) {
                        ri->ref_tree = 0;
                        return -ENOENT;
                }
                fprintf(stderr, "ERROR: Failed to lookup path for root %llu - %s\n",
                        (unsigned long long)ri->ref_tree,
-                       strerror(e));
+                       strerror(errno));
                return ret;
        }
 
@@ -665,7 +678,7 @@ static int lookup_ino_path(int fd, struct root_info *ri)
 }
 
 /* finding the generation for a given path is a two step process.
- * First we use the inode loookup routine to find out the root id
+ * First we use the inode lookup routine to find out the root id
  *
  * Then we use the tree search ioctl to scan all the root items for a
  * given root id and spit out the latest generation we can find
@@ -680,18 +693,16 @@ static u64 find_root_gen(int fd)
        unsigned long off = 0;
        u64 max_found = 0;
        int i;
-       int e;
 
        memset(&ino_args, 0, sizeof(ino_args));
        ino_args.objectid = BTRFS_FIRST_FREE_OBJECTID;
 
        /* this ioctl fills in ino_args->treeid */
        ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args);
-       e = errno;
-       if (ret) {
+       if (ret < 0) {
                fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n",
                        (unsigned long long)BTRFS_FIRST_FREE_OBJECTID,
-                       strerror(e));
+                       strerror(errno));
                return 0;
        }
 
@@ -714,10 +725,9 @@ static u64 find_root_gen(int fd)
 
        while (1) {
                ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
-               e = errno;
                if (ret < 0) {
                        fprintf(stderr, "ERROR: can't perform the search - %s\n",
-                               strerror(e));
+                               strerror(errno));
                        return 0;
                }
                /* the ioctl returns the number of item it found in nr_items */
@@ -771,16 +781,14 @@ static char *__ino_resolve(int fd, u64 dirid)
        struct btrfs_ioctl_ino_lookup_args args;
        int ret;
        char *full;
-       int e;
 
        memset(&args, 0, sizeof(args));
        args.objectid = dirid;
 
        ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
-       e = errno;
-       if (ret) {
+       if (ret < 0) {
                fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n",
-                       (unsigned long long)dirid, strerror(e);
+                       (unsigned long long)dirid, strerror(errno));
                return ERR_PTR(ret);
        }
 
@@ -838,7 +846,6 @@ static char *ino_resolve(int fd, u64 ino, u64 *cache_dirid, char **cache_name)
        struct btrfs_ioctl_search_header *sh;
        unsigned long off = 0;
        int namelen;
-       int e;
 
        memset(&args, 0, sizeof(args));
 
@@ -857,10 +864,9 @@ static char *ino_resolve(int fd, u64 ino, u64 *cache_dirid, char **cache_name)
        sk->nr_items = 1;
 
        ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
-       e = errno;
        if (ret < 0) {
                fprintf(stderr, "ERROR: can't perform the search - %s\n",
-                       strerror(e));
+                       strerror(errno));
                return NULL;
        }
        /* the ioctl returns the number of item it found in nr_items */
@@ -870,9 +876,9 @@ static char *ino_resolve(int fd, u64 ino, u64 *cache_dirid, char **cache_name)
        off = 0;
        sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
 
-       if (sh->type == BTRFS_INODE_REF_KEY) {
+       if (btrfs_search_header_type(sh) == BTRFS_INODE_REF_KEY) {
                struct btrfs_inode_ref *ref;
-               dirid = sh->offset;
+               dirid = btrfs_search_header_offset(sh);
 
                ref = (struct btrfs_inode_ref *)(sh + 1);
                namelen = btrfs_stack_inode_ref_name_len(ref);
@@ -941,7 +947,7 @@ int btrfs_list_get_default_subvolume(int fd, u64 *default_id)
 
        sh = (struct btrfs_ioctl_search_header *)args.buf;
 
-       if (sh->type == BTRFS_DIR_ITEM_KEY) {
+       if (btrfs_search_header_type(sh) == BTRFS_DIR_ITEM_KEY) {
                struct btrfs_dir_item *di;
                int name_len;
                char *name;
@@ -978,6 +984,7 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
        time_t t;
        u8 uuid[BTRFS_UUID_SIZE];
        u8 puuid[BTRFS_UUID_SIZE];
+       u8 ruuid[BTRFS_UUID_SIZE];
 
        root_lookup_init(root_lookup);
        memset(&args, 0, sizeof(args));
@@ -1030,7 +1037,7 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
 
                                add_root(root_lookup, sh.objectid, sh.offset,
                                         0, 0, dir_id, name, name_len, 0, 0, 0,
-                                        NULL, NULL);
+                                        NULL, NULL, NULL);
                        } else if (sh.type == BTRFS_ROOT_ITEM_KEY) {
                                ri = (struct btrfs_root_item *)(args.buf + off);
                                gen = btrfs_root_generation(ri);
@@ -1041,16 +1048,18 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
                                        ogen = btrfs_root_otransid(ri);
                                        memcpy(uuid, ri->uuid, BTRFS_UUID_SIZE);
                                        memcpy(puuid, ri->parent_uuid, BTRFS_UUID_SIZE);
+                                       memcpy(ruuid, ri->received_uuid, BTRFS_UUID_SIZE);
                                } else {
                                        t = 0;
                                        ogen = 0;
                                        memset(uuid, 0, BTRFS_UUID_SIZE);
                                        memset(puuid, 0, BTRFS_UUID_SIZE);
+                                       memset(ruuid, 0, BTRFS_UUID_SIZE);
                                }
 
                                add_root(root_lookup, sh.objectid, 0,
                                         sh.offset, flags, 0, NULL, 0, ogen,
-                                        gen, t, uuid, puuid);
+                                        gen, t, uuid, puuid, ruuid);
                        }
 
                        off += sh.len;
@@ -1189,13 +1198,12 @@ struct btrfs_list_filter_set *btrfs_list_alloc_filter_set(void)
 
        size = sizeof(struct btrfs_list_filter_set) +
               BTRFS_LIST_NFILTERS_INCREASE * sizeof(struct btrfs_list_filter);
-       set = malloc(size);
+       set = calloc(1, size);
        if (!set) {
                fprintf(stderr, "memory allocation failed\n");
                exit(1);
        }
 
-       memset(set, 0, size);
        set->total = BTRFS_LIST_NFILTERS_INCREASE;
 
        return set;
@@ -1216,17 +1224,16 @@ int btrfs_list_setup_filter(struct btrfs_list_filter_set **filter_set,
        BUG_ON(filter >= BTRFS_LIST_FILTER_MAX);
        BUG_ON(set->nfilters > set->total);
 
-       if (filter == BTRFS_LIST_FILTER_DELETED) {
-               set->only_deleted = 1;
-               return 0;
-       }
-
        if (set->nfilters == set->total) {
+               void *tmp;
+
                size = set->total + BTRFS_LIST_NFILTERS_INCREASE;
                size = sizeof(*set) + size * sizeof(struct btrfs_list_filter);
+               tmp = set;
                set = realloc(set, size);
                if (!set) {
                        fprintf(stderr, "memory allocation failed\n");
+                       free(tmp);
                        exit(1);
                }
 
@@ -1239,6 +1246,9 @@ int btrfs_list_setup_filter(struct btrfs_list_filter_set **filter_set,
 
        BUG_ON(set->filters[set->nfilters].filter_func);
 
+       if (filter == BTRFS_LIST_FILTER_DELETED)
+               set->only_deleted = 1;
+
        set->filters[set->nfilters].filter_func = all_filter_funcs[filter];
        set->filters[set->nfilters].data = data;
        set->nfilters++;
@@ -1250,7 +1260,7 @@ static int filter_root(struct root_info *ri,
 {
        int i, ret;
 
-       if (!set || !set->nfilters)
+       if (!set)
                return 1;
 
        if (set->only_deleted && !ri->deleted)
@@ -1363,6 +1373,13 @@ static void print_subvolume_column(struct root_info *subv,
                        uuid_unparse(subv->puuid, uuidparse);
                printf("%s", uuidparse);
                break;
+       case BTRFS_LIST_RUUID:
+               if (uuid_is_null(subv->ruuid))
+                       strcpy(uuidparse, "-");
+               else
+                       uuid_unparse(subv->ruuid, uuidparse);
+               printf("%s", uuidparse);
+               break;
        case BTRFS_LIST_PATH:
                BUG_ON(!subv->full_path);
                printf("%s", subv->full_path);
@@ -1585,17 +1602,18 @@ static int print_one_extent(int fd, struct btrfs_ioctl_search_header *sh,
        int flags = 0;
        char *name = NULL;
 
-       if (sh->objectid == *cache_ino) {
+       if (btrfs_search_header_objectid(sh) == *cache_ino) {
                name = *cache_full_name;
        } else if (*cache_full_name) {
                free(*cache_full_name);
                *cache_full_name = NULL;
        }
        if (!name) {
-               name = ino_resolve(fd, sh->objectid, cache_dirid,
+               name = ino_resolve(fd, btrfs_search_header_objectid(sh),
+                                  cache_dirid,
                                   cache_dir_name);
                *cache_full_name = name;
-               *cache_ino = sh->objectid;
+               *cache_ino = btrfs_search_header_objectid(sh);
        }
        if (!name)
                return -EIO;
@@ -1616,16 +1634,16 @@ static int print_one_extent(int fd, struct btrfs_ioctl_search_header *sh,
                printf("unhandled extent type %d for inode %llu "
                       "file offset %llu gen %llu\n",
                        type,
-                       (unsigned long long)sh->objectid,
-                       (unsigned long long)sh->offset,
+                       (unsigned long long)btrfs_search_header_objectid(sh),
+                       (unsigned long long)btrfs_search_header_offset(sh),
                        (unsigned long long)found_gen);
 
                return -EIO;
        }
        printf("inode %llu file offset %llu len %llu disk start %llu "
               "offset %llu gen %llu flags ",
-              (unsigned long long)sh->objectid,
-              (unsigned long long)sh->offset,
+              (unsigned long long)btrfs_search_header_objectid(sh),
+              (unsigned long long)btrfs_search_header_offset(sh),
               (unsigned long long)len,
               (unsigned long long)disk_start,
               (unsigned long long)disk_offset,
@@ -1661,7 +1679,6 @@ int btrfs_list_find_updated_files(int fd, u64 root_id, u64 oldest_gen)
        u64 found_gen;
        u64 max_found = 0;
        int i;
-       int e;
        u64 cache_dirid = 0;
        u64 cache_ino = 0;
        char *cache_dir_name = NULL;
@@ -1688,10 +1705,9 @@ int btrfs_list_find_updated_files(int fd, u64 root_id, u64 oldest_gen)
        max_found = find_root_gen(fd);
        while(1) {
                ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
-               e = errno;
                if (ret < 0) {
-                       fprintf(stderr, "ERROR: can't perform the search- %s\n",
-                               strerror(e));
+                       fprintf(stderr, "ERROR: can't perform the search - %s\n",
+                               strerror(errno));
                        break;
                }
                /* the ioctl returns the number of item it found in nr_items */
@@ -1854,32 +1870,24 @@ int btrfs_list_parse_filter_string(char *opt_arg,
 {
 
        u64 arg;
-       char *ptr_parse_end = NULL;
-       char *ptr_opt_arg_end = opt_arg + strlen(opt_arg);
 
        switch (*(opt_arg++)) {
        case '+':
-               arg = (u64)strtol(opt_arg, &ptr_parse_end, 10);
+               arg = arg_strtou64(opt_arg);
                type += 2;
-               if (ptr_parse_end != ptr_opt_arg_end)
-                       return -1;
 
                btrfs_list_setup_filter(filters, type, arg);
                break;
        case '-':
-               arg = (u64)strtoll(opt_arg, &ptr_parse_end, 10);
+               arg = arg_strtou64(opt_arg);
                type += 1;
-               if (ptr_parse_end != ptr_opt_arg_end)
-                       return -1;
 
                btrfs_list_setup_filter(filters, type, arg);
                break;
        default:
                opt_arg--;
-               arg = (u64)strtoll(opt_arg, &ptr_parse_end, 10);
+               arg = arg_strtou64(opt_arg);
 
-               if (ptr_parse_end != ptr_opt_arg_end)
-                       return -1;
                btrfs_list_setup_filter(filters, type, arg);
                break;
        }
@@ -1898,7 +1906,7 @@ int btrfs_list_get_path_rootid(int fd, u64 *treeid)
        ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
        if (ret < 0) {
                fprintf(stderr,
-                       "ERROR: can't perform the search -%s\n",
+                       "ERROR: can't perform the search - %s\n",
                        strerror(errno));
                return ret;
        }