+ memcpy(tmp + add_len + 1, ri->full_path, len);
+ tmp[len + add_len + 1] = '\0';
+ tmp[add_len] = '/';
+ memcpy(tmp, p, add_len);
+ free(ri->full_path);
+ ri->full_path = tmp;
+ }
+ return 1;
+}
+
+static int filter_by_parent(struct root_info *ri, u64 data)
+{
+ return !uuid_compare(ri->puuid, (u8 *)(unsigned long)data);
+}
+
+static int filter_deleted(struct root_info *ri, u64 data)
+{
+ return ri->deleted;
+}
+
+static btrfs_list_filter_func all_filter_funcs[] = {
+ [BTRFS_LIST_FILTER_ROOTID] = filter_by_rootid,
+ [BTRFS_LIST_FILTER_SNAPSHOT_ONLY] = filter_snapshot,
+ [BTRFS_LIST_FILTER_FLAGS] = filter_flags,
+ [BTRFS_LIST_FILTER_GEN_MORE] = filter_gen_more,
+ [BTRFS_LIST_FILTER_GEN_LESS] = filter_gen_less,
+ [BTRFS_LIST_FILTER_GEN_EQUAL] = filter_gen_equal,
+ [BTRFS_LIST_FILTER_CGEN_MORE] = filter_cgen_more,
+ [BTRFS_LIST_FILTER_CGEN_LESS] = filter_cgen_less,
+ [BTRFS_LIST_FILTER_CGEN_EQUAL] = filter_cgen_equal,
+ [BTRFS_LIST_FILTER_TOPID_EQUAL] = filter_topid_equal,
+ [BTRFS_LIST_FILTER_FULL_PATH] = filter_full_path,
+ [BTRFS_LIST_FILTER_BY_PARENT] = filter_by_parent,
+ [BTRFS_LIST_FILTER_DELETED] = filter_deleted,
+};
+
+struct btrfs_list_filter_set *btrfs_list_alloc_filter_set(void)
+{
+ struct btrfs_list_filter_set *set;
+ int size;
+
+ size = sizeof(struct btrfs_list_filter_set) +
+ BTRFS_LIST_NFILTERS_INCREASE * sizeof(struct btrfs_list_filter);
+ set = calloc(1, size);
+ if (!set) {
+ fprintf(stderr, "memory allocation failed\n");
+ exit(1);
+ }
+
+ set->total = BTRFS_LIST_NFILTERS_INCREASE;
+
+ return set;
+}
+
+/*
+ * Setup list filters. Exit if there's not enough memory, as we can't continue
+ * without the structures set up properly.
+ */
+void btrfs_list_setup_filter(struct btrfs_list_filter_set **filter_set,
+ enum btrfs_list_filter_enum filter, u64 data)
+{
+ struct btrfs_list_filter_set *set = *filter_set;
+ int size;
+
+ ASSERT(set != NULL);
+ ASSERT(filter < BTRFS_LIST_FILTER_MAX);
+ ASSERT(set->nfilters <= set->total);
+
+ 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);
+ }
+
+ memset(&set->filters[set->total], 0,
+ BTRFS_LIST_NFILTERS_INCREASE *
+ sizeof(struct btrfs_list_filter));
+ set->total += BTRFS_LIST_NFILTERS_INCREASE;
+ *filter_set = set;
+ }
+
+ ASSERT(set->filters[set->nfilters].filter_func == NULL);
+
+ 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++;
+}
+
+static int filter_root(struct root_info *ri,
+ struct btrfs_list_filter_set *set)
+{
+ int i, ret;
+
+ if (!set)
+ return 1;
+
+ if (set->only_deleted && !ri->deleted)
+ return 0;
+
+ if (!set->only_deleted && ri->deleted)
+ return 0;
+
+ for (i = 0; i < set->nfilters; i++) {
+ if (!set->filters[i].filter_func)