btrfs-progs: typo review of strings and comments
[platform/upstream/btrfs-progs.git] / btrfs-list.c
1 /*
2  * Copyright (C) 2010 Oracle.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public
6  * License v2 as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public
14  * License along with this program; if not, write to the
15  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16  * Boston, MA 021110-1307, USA.
17  */
18
19 #include <sys/ioctl.h>
20 #include <sys/mount.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <dirent.h>
28 #include <libgen.h>
29 #include "ctree.h"
30 #include "transaction.h"
31 #include "utils.h"
32 #include "ioctl.h"
33 #include <uuid/uuid.h>
34 #include "btrfs-list.h"
35 #include "rbtree-utils.h"
36
37 #define BTRFS_LIST_NFILTERS_INCREASE    (2 * BTRFS_LIST_FILTER_MAX)
38 #define BTRFS_LIST_NCOMPS_INCREASE      (2 * BTRFS_LIST_COMP_MAX)
39
40 /* we store all the roots we find in an rbtree so that we can
41  * search for them later.
42  */
43 struct root_lookup {
44         struct rb_root root;
45 };
46
47 static struct {
48         char    *name;
49         char    *column_name;
50         int     need_print;
51 } btrfs_list_columns[] = {
52         {
53                 .name           = "ID",
54                 .column_name    = "ID",
55                 .need_print     = 0,
56         },
57         {
58                 .name           = "gen",
59                 .column_name    = "Gen",
60                 .need_print     = 0,
61         },
62         {
63                 .name           = "cgen",
64                 .column_name    = "CGen",
65                 .need_print     = 0,
66         },
67         {
68                 .name           = "parent",
69                 .column_name    = "Parent",
70                 .need_print     = 0,
71         },
72         {
73                 .name           = "top level",
74                 .column_name    = "Top Level",
75                 .need_print     = 0,
76         },
77         {
78                 .name           = "otime",
79                 .column_name    = "OTime",
80                 .need_print     = 0,
81         },
82         {
83                 .name           = "parent_uuid",
84                 .column_name    = "Parent UUID",
85                 .need_print     = 0,
86         },
87         {
88                 .name           = "received_uuid",
89                 .column_name    = "Received UUID",
90                 .need_print     = 0,
91         },
92         {
93                 .name           = "uuid",
94                 .column_name    = "UUID",
95                 .need_print     = 0,
96         },
97         {
98                 .name           = "path",
99                 .column_name    = "Path",
100                 .need_print     = 0,
101         },
102         {
103                 .name           = NULL,
104                 .column_name    = NULL,
105                 .need_print     = 0,
106         },
107 };
108
109 static btrfs_list_filter_func all_filter_funcs[];
110 static btrfs_list_comp_func all_comp_funcs[];
111
112 void btrfs_list_setup_print_column(enum btrfs_list_column_enum column)
113 {
114         int i;
115
116         BUG_ON(column < 0 || column > BTRFS_LIST_ALL);
117
118         if (column < BTRFS_LIST_ALL) {
119                 btrfs_list_columns[column].need_print = 1;
120                 return;
121         }
122
123         for (i = 0; i < BTRFS_LIST_ALL; i++)
124                 btrfs_list_columns[i].need_print = 1;
125 }
126
127 static void root_lookup_init(struct root_lookup *tree)
128 {
129         tree->root.rb_node = NULL;
130 }
131
132 static int comp_entry_with_rootid(struct root_info *entry1,
133                                   struct root_info *entry2,
134                                   int is_descending)
135 {
136         int ret;
137
138         if (entry1->root_id > entry2->root_id)
139                 ret = 1;
140         else if (entry1->root_id < entry2->root_id)
141                 ret = -1;
142         else
143                 ret = 0;
144
145         return is_descending ? -ret : ret;
146 }
147
148 static int comp_entry_with_gen(struct root_info *entry1,
149                                struct root_info *entry2,
150                                int is_descending)
151 {
152         int ret;
153
154         if (entry1->gen > entry2->gen)
155                 ret = 1;
156         else if (entry1->gen < entry2->gen)
157                 ret = -1;
158         else
159                 ret = 0;
160
161         return is_descending ? -ret : ret;
162 }
163
164 static int comp_entry_with_ogen(struct root_info *entry1,
165                                 struct root_info *entry2,
166                                 int is_descending)
167 {
168         int ret;
169
170         if (entry1->ogen > entry2->ogen)
171                 ret = 1;
172         else if (entry1->ogen < entry2->ogen)
173                 ret = -1;
174         else
175                 ret = 0;
176
177         return is_descending ? -ret : ret;
178 }
179
180 static int comp_entry_with_path(struct root_info *entry1,
181                                 struct root_info *entry2,
182                                 int is_descending)
183 {
184         int ret;
185
186         if (strcmp(entry1->full_path, entry2->full_path) > 0)
187                 ret = 1;
188         else if (strcmp(entry1->full_path, entry2->full_path) < 0)
189                 ret = -1;
190         else
191                 ret = 0;
192
193         return is_descending ? -ret : ret;
194 }
195
196 static btrfs_list_comp_func all_comp_funcs[] = {
197         [BTRFS_LIST_COMP_ROOTID]        = comp_entry_with_rootid,
198         [BTRFS_LIST_COMP_OGEN]          = comp_entry_with_ogen,
199         [BTRFS_LIST_COMP_GEN]           = comp_entry_with_gen,
200         [BTRFS_LIST_COMP_PATH]          = comp_entry_with_path,
201 };
202
203 static char *all_sort_items[] = {
204         [BTRFS_LIST_COMP_ROOTID]        = "rootid",
205         [BTRFS_LIST_COMP_OGEN]          = "ogen",
206         [BTRFS_LIST_COMP_GEN]           = "gen",
207         [BTRFS_LIST_COMP_PATH]          = "path",
208         [BTRFS_LIST_COMP_MAX]           = NULL,
209 };
210
211 static int  btrfs_list_get_sort_item(char *sort_name)
212 {
213         int i;
214
215         for (i = 0; i < BTRFS_LIST_COMP_MAX; i++) {
216                 if (strcmp(sort_name, all_sort_items[i]) == 0)
217                         return i;
218         }
219         return -1;
220 }
221
222 struct btrfs_list_comparer_set *btrfs_list_alloc_comparer_set(void)
223 {
224         struct btrfs_list_comparer_set *set;
225         int size;
226
227         size = sizeof(struct btrfs_list_comparer_set) +
228                BTRFS_LIST_NCOMPS_INCREASE * sizeof(struct btrfs_list_comparer);
229         set = calloc(1, size);
230         if (!set) {
231                 fprintf(stderr, "memory allocation failed\n");
232                 exit(1);
233         }
234
235         set->total = BTRFS_LIST_NCOMPS_INCREASE;
236
237         return set;
238 }
239
240 void btrfs_list_free_comparer_set(struct btrfs_list_comparer_set *comp_set)
241 {
242         free(comp_set);
243 }
244
245 static int btrfs_list_setup_comparer(struct btrfs_list_comparer_set **comp_set,
246                 enum btrfs_list_comp_enum comparer, int is_descending)
247 {
248         struct btrfs_list_comparer_set *set = *comp_set;
249         int size;
250
251         BUG_ON(!set);
252         BUG_ON(comparer >= BTRFS_LIST_COMP_MAX);
253         BUG_ON(set->ncomps > set->total);
254
255         if (set->ncomps == set->total) {
256                 void *tmp;
257
258                 size = set->total + BTRFS_LIST_NCOMPS_INCREASE;
259                 size = sizeof(*set) + size * sizeof(struct btrfs_list_comparer);
260                 tmp = set;
261                 set = realloc(set, size);
262                 if (!set) {
263                         fprintf(stderr, "memory allocation failed\n");
264                         free(tmp);
265                         exit(1);
266                 }
267
268                 memset(&set->comps[set->total], 0,
269                        BTRFS_LIST_NCOMPS_INCREASE *
270                        sizeof(struct btrfs_list_comparer));
271                 set->total += BTRFS_LIST_NCOMPS_INCREASE;
272                 *comp_set = set;
273         }
274
275         BUG_ON(set->comps[set->ncomps].comp_func);
276
277         set->comps[set->ncomps].comp_func = all_comp_funcs[comparer];
278         set->comps[set->ncomps].is_descending = is_descending;
279         set->ncomps++;
280         return 0;
281 }
282
283 static int sort_comp(struct root_info *entry1, struct root_info *entry2,
284                      struct btrfs_list_comparer_set *set)
285 {
286         int rootid_compared = 0;
287         int i, ret = 0;
288
289         if (!set || !set->ncomps)
290                 goto comp_rootid;
291
292         for (i = 0; i < set->ncomps; i++) {
293                 if (!set->comps[i].comp_func)
294                         break;
295
296                 ret = set->comps[i].comp_func(entry1, entry2,
297                                               set->comps[i].is_descending);
298                 if (ret)
299                         return ret;
300
301                 if (set->comps[i].comp_func == comp_entry_with_rootid)
302                         rootid_compared = 1;
303         }
304
305         if (!rootid_compared) {
306 comp_rootid:
307                 ret = comp_entry_with_rootid(entry1, entry2, 0);
308         }
309
310         return ret;
311 }
312
313 static int sort_tree_insert(struct root_lookup *sort_tree,
314                             struct root_info *ins,
315                             struct btrfs_list_comparer_set *comp_set)
316 {
317         struct rb_node **p = &sort_tree->root.rb_node;
318         struct rb_node *parent = NULL;
319         struct root_info *curr;
320         int ret;
321
322         while (*p) {
323                 parent = *p;
324                 curr = rb_entry(parent, struct root_info, sort_node);
325
326                 ret = sort_comp(ins, curr, comp_set);
327                 if (ret < 0)
328                         p = &(*p)->rb_left;
329                 else if (ret > 0)
330                         p = &(*p)->rb_right;
331                 else
332                         return -EEXIST;
333         }
334
335         rb_link_node(&ins->sort_node, parent, p);
336         rb_insert_color(&ins->sort_node, &sort_tree->root);
337         return 0;
338 }
339
340 /*
341  * insert a new root into the tree.  returns the existing root entry
342  * if one is already there.  Both root_id and ref_tree are used
343  * as the key
344  */
345 static int root_tree_insert(struct root_lookup *root_tree,
346                             struct root_info *ins)
347 {
348         struct rb_node **p = &root_tree->root.rb_node;
349         struct rb_node * parent = NULL;
350         struct root_info *curr;
351         int ret;
352
353         while(*p) {
354                 parent = *p;
355                 curr = rb_entry(parent, struct root_info, rb_node);
356
357                 ret = comp_entry_with_rootid(ins, curr, 0);
358                 if (ret < 0)
359                         p = &(*p)->rb_left;
360                 else if (ret > 0)
361                         p = &(*p)->rb_right;
362                 else
363                         return -EEXIST;
364         }
365
366         rb_link_node(&ins->rb_node, parent, p);
367         rb_insert_color(&ins->rb_node, &root_tree->root);
368         return 0;
369 }
370
371 /*
372  * find a given root id in the tree.  We return the smallest one,
373  * rb_next can be used to move forward looking for more if required
374  */
375 static struct root_info *root_tree_search(struct root_lookup *root_tree,
376                                           u64 root_id)
377 {
378         struct rb_node *n = root_tree->root.rb_node;
379         struct root_info *entry;
380         struct root_info tmp;
381         int ret;
382
383         tmp.root_id = root_id;
384
385         while(n) {
386                 entry = rb_entry(n, struct root_info, rb_node);
387
388                 ret = comp_entry_with_rootid(&tmp, entry, 0);
389                 if (ret < 0)
390                         n = n->rb_left;
391                 else if (ret > 0)
392                         n = n->rb_right;
393                 else
394                         return entry;
395         }
396         return NULL;
397 }
398
399 static int update_root(struct root_lookup *root_lookup,
400                        u64 root_id, u64 ref_tree, u64 root_offset, u64 flags,
401                        u64 dir_id, char *name, int name_len, u64 ogen, u64 gen,
402                        time_t ot, void *uuid, void *puuid, void *ruuid)
403 {
404         struct root_info *ri;
405
406         ri = root_tree_search(root_lookup, root_id);
407         if (!ri || ri->root_id != root_id)
408                 return -ENOENT;
409         if (name && name_len > 0) {
410                 free(ri->name);
411
412                 ri->name = malloc(name_len + 1);
413                 if (!ri->name) {
414                         fprintf(stderr, "memory allocation failed\n");
415                         exit(1);
416                 }
417                 strncpy(ri->name, name, name_len);
418                 ri->name[name_len] = 0;
419         }
420         if (ref_tree)
421                 ri->ref_tree = ref_tree;
422         if (root_offset)
423                 ri->root_offset = root_offset;
424         if (flags)
425                 ri->flags = flags;
426         if (dir_id)
427                 ri->dir_id = dir_id;
428         if (gen)
429                 ri->gen = gen;
430         if (ogen)
431                 ri->ogen = ogen;
432         if (!ri->ogen && root_offset)
433                 ri->ogen = root_offset;
434         if (ot)
435                 ri->otime = ot;
436         if (uuid)
437                 memcpy(&ri->uuid, uuid, BTRFS_UUID_SIZE);
438         if (puuid)
439                 memcpy(&ri->puuid, puuid, BTRFS_UUID_SIZE);
440         if (ruuid)
441                 memcpy(&ri->ruuid, ruuid, BTRFS_UUID_SIZE);
442
443         return 0;
444 }
445
446 /*
447  * add_root - update the existed root, or allocate a new root and insert it
448  *            into the lookup tree.
449  * root_id: object id of the root
450  * ref_tree: object id of the referring root.
451  * root_offset: offset value of the root'key
452  * dir_id: inode id of the directory in ref_tree where this root can be found.
453  * name: the name of root_id in that directory
454  * name_len: the length of name
455  * ogen: the original generation of the root
456  * gen: the current generation of the root
457  * ot: the original time(create time) of the root
458  * uuid: uuid of the root
459  * puuid: uuid of the root parent if any
460  * ruuid: uuid of the received subvol, if any
461  */
462 static int add_root(struct root_lookup *root_lookup,
463                     u64 root_id, u64 ref_tree, u64 root_offset, u64 flags,
464                     u64 dir_id, char *name, int name_len, u64 ogen, u64 gen,
465                     time_t ot, void *uuid, void *puuid, void *ruuid)
466 {
467         struct root_info *ri;
468         int ret;
469
470         ret = update_root(root_lookup, root_id, ref_tree, root_offset, flags,
471                           dir_id, name, name_len, ogen, gen, ot,
472                           uuid, puuid, ruuid);
473         if (!ret)
474                 return 0;
475
476         ri = calloc(1, sizeof(*ri));
477         if (!ri) {
478                 printf("memory allocation failed\n");
479                 exit(1);
480         }
481         ri->root_id = root_id;
482
483         if (name && name_len > 0) {
484                 ri->name = malloc(name_len + 1);
485                 if (!ri->name) {
486                         fprintf(stderr, "memory allocation failed\n");
487                         exit(1);
488                 }
489                 strncpy(ri->name, name, name_len);
490                 ri->name[name_len] = 0;
491         }
492         if (ref_tree)
493                 ri->ref_tree = ref_tree;
494         if (dir_id)
495                 ri->dir_id = dir_id;
496         if (root_offset)
497                 ri->root_offset = root_offset;
498         if (flags)
499                 ri->flags = flags;
500         if (gen)
501                 ri->gen = gen;
502         if (ogen)
503                 ri->ogen = ogen;
504         if (!ri->ogen && root_offset)
505                 ri->ogen = root_offset;
506         if (ot)
507                 ri->otime = ot;
508
509         if (uuid)
510                 memcpy(&ri->uuid, uuid, BTRFS_UUID_SIZE);
511
512         if (puuid)
513                 memcpy(&ri->puuid, puuid, BTRFS_UUID_SIZE);
514
515         if (ruuid)
516                 memcpy(&ri->ruuid, ruuid, BTRFS_UUID_SIZE);
517
518         ret = root_tree_insert(root_lookup, ri);
519         if (ret) {
520                 printf("failed to insert tree %llu\n", (unsigned long long)root_id);
521                 exit(1);
522         }
523         return 0;
524 }
525
526 static void __free_root_info(struct rb_node *node)
527 {
528         struct root_info *ri;
529
530         ri = rb_entry(node, struct root_info, rb_node);
531         free(ri->name);
532         free(ri->path);
533         free(ri->full_path);
534         free(ri);
535 }
536
537 static inline void __free_all_subvolumn(struct root_lookup *root_tree)
538 {
539         rb_free_nodes(&root_tree->root, __free_root_info);
540 }
541
542 /*
543  * for a given root_info, search through the root_lookup tree to construct
544  * the full path name to it.
545  *
546  * This can't be called until all the root_info->path fields are filled
547  * in by lookup_ino_path
548  */
549 static int resolve_root(struct root_lookup *rl, struct root_info *ri,
550                        u64 top_id)
551 {
552         char *full_path = NULL;
553         int len = 0;
554         struct root_info *found;
555
556         /*
557          * we go backwards from the root_info object and add pathnames
558          * from parent directories as we go.
559          */
560         found = ri;
561         while (1) {
562                 char *tmp;
563                 u64 next;
564                 int add_len;
565
566                 /*
567                  * ref_tree = 0 indicates the subvolume
568                  * has been deleted.
569                  */
570                 if (!found->ref_tree) {
571                         free(full_path);
572                         return -ENOENT;
573                 }
574
575                 add_len = strlen(found->path);
576
577                 if (full_path) {
578                         /* room for / and for null */
579                         tmp = malloc(add_len + 2 + len);
580                         if (!tmp) {
581                                 perror("malloc failed");
582                                 exit(1);
583                         }
584                         memcpy(tmp + add_len + 1, full_path, len);
585                         tmp[add_len] = '/';
586                         memcpy(tmp, found->path, add_len);
587                         tmp [add_len + len + 1] = '\0';
588                         free(full_path);
589                         full_path = tmp;
590                         len += add_len + 1;
591                 } else {
592                         full_path = strdup(found->path);
593                         len = add_len;
594                 }
595                 if (!ri->top_id)
596                         ri->top_id = found->ref_tree;
597
598                 next = found->ref_tree;
599                 if (next == top_id)
600                         break;
601                 /*
602                 * if the ref_tree = BTRFS_FS_TREE_OBJECTID,
603                 * we are at the top
604                 */
605                 if (next == BTRFS_FS_TREE_OBJECTID)
606                         break;
607                 /*
608                 * if the ref_tree wasn't in our tree of roots, the
609                 * subvolume was deleted.
610                 */
611                 found = root_tree_search(rl, next);
612                 if (!found) {
613                         free(full_path);
614                         return -ENOENT;
615                 }
616         }
617
618         ri->full_path = full_path;
619
620         return 0;
621 }
622
623 /*
624  * for a single root_info, ask the kernel to give us a path name
625  * inside it's ref_root for the dir_id where it lives.
626  *
627  * This fills in root_info->path with the path to the directory and and
628  * appends this root's name.
629  */
630 static int lookup_ino_path(int fd, struct root_info *ri)
631 {
632         struct btrfs_ioctl_ino_lookup_args args;
633         int ret;
634
635         if (ri->path)
636                 return 0;
637
638         if (!ri->ref_tree)
639                 return -ENOENT;
640
641         memset(&args, 0, sizeof(args));
642         args.treeid = ri->ref_tree;
643         args.objectid = ri->dir_id;
644
645         ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
646         if (ret < 0) {
647                 if (errno == ENOENT) {
648                         ri->ref_tree = 0;
649                         return -ENOENT;
650                 }
651                 fprintf(stderr, "ERROR: Failed to lookup path for root %llu - %s\n",
652                         (unsigned long long)ri->ref_tree,
653                         strerror(errno));
654                 return ret;
655         }
656
657         if (args.name[0]) {
658                 /*
659                  * we're in a subdirectory of ref_tree, the kernel ioctl
660                  * puts a / in there for us
661                  */
662                 ri->path = malloc(strlen(ri->name) + strlen(args.name) + 1);
663                 if (!ri->path) {
664                         perror("malloc failed");
665                         exit(1);
666                 }
667                 strcpy(ri->path, args.name);
668                 strcat(ri->path, ri->name);
669         } else {
670                 /* we're at the root of ref_tree */
671                 ri->path = strdup(ri->name);
672                 if (!ri->path) {
673                         perror("strdup failed");
674                         exit(1);
675                 }
676         }
677         return 0;
678 }
679
680 /* finding the generation for a given path is a two step process.
681  * First we use the inode lookup routine to find out the root id
682  *
683  * Then we use the tree search ioctl to scan all the root items for a
684  * given root id and spit out the latest generation we can find
685  */
686 static u64 find_root_gen(int fd)
687 {
688         struct btrfs_ioctl_ino_lookup_args ino_args;
689         int ret;
690         struct btrfs_ioctl_search_args args;
691         struct btrfs_ioctl_search_key *sk = &args.key;
692         struct btrfs_ioctl_search_header sh;
693         unsigned long off = 0;
694         u64 max_found = 0;
695         int i;
696
697         memset(&ino_args, 0, sizeof(ino_args));
698         ino_args.objectid = BTRFS_FIRST_FREE_OBJECTID;
699
700         /* this ioctl fills in ino_args->treeid */
701         ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args);
702         if (ret < 0) {
703                 fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n",
704                         (unsigned long long)BTRFS_FIRST_FREE_OBJECTID,
705                         strerror(errno));
706                 return 0;
707         }
708
709         memset(&args, 0, sizeof(args));
710
711         sk->tree_id = 1;
712
713         /*
714          * there may be more than one ROOT_ITEM key if there are
715          * snapshots pending deletion, we have to loop through
716          * them.
717          */
718         sk->min_objectid = ino_args.treeid;
719         sk->max_objectid = ino_args.treeid;
720         sk->max_type = BTRFS_ROOT_ITEM_KEY;
721         sk->min_type = BTRFS_ROOT_ITEM_KEY;
722         sk->max_offset = (u64)-1;
723         sk->max_transid = (u64)-1;
724         sk->nr_items = 4096;
725
726         while (1) {
727                 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
728                 if (ret < 0) {
729                         fprintf(stderr, "ERROR: can't perform the search - %s\n",
730                                 strerror(errno));
731                         return 0;
732                 }
733                 /* the ioctl returns the number of item it found in nr_items */
734                 if (sk->nr_items == 0)
735                         break;
736
737                 off = 0;
738                 for (i = 0; i < sk->nr_items; i++) {
739                         struct btrfs_root_item *item;
740
741                         memcpy(&sh, args.buf + off, sizeof(sh));
742                         off += sizeof(sh);
743                         item = (struct btrfs_root_item *)(args.buf + off);
744                         off += sh.len;
745
746                         sk->min_objectid = sh.objectid;
747                         sk->min_type = sh.type;
748                         sk->min_offset = sh.offset;
749
750                         if (sh.objectid > ino_args.treeid)
751                                 break;
752
753                         if (sh.objectid == ino_args.treeid &&
754                             sh.type == BTRFS_ROOT_ITEM_KEY) {
755                                 max_found = max(max_found,
756                                                 btrfs_root_generation(item));
757                         }
758                 }
759                 if (sk->min_offset < (u64)-1)
760                         sk->min_offset++;
761                 else
762                         break;
763
764                 if (sk->min_type != BTRFS_ROOT_ITEM_KEY)
765                         break;
766                 if (sk->min_objectid != ino_args.treeid)
767                         break;
768         }
769         return max_found;
770 }
771
772 /* pass in a directory id and this will return
773  * the full path of the parent directory inside its
774  * subvolume root.
775  *
776  * It may return NULL if it is in the root, or an ERR_PTR if things
777  * go badly.
778  */
779 static char *__ino_resolve(int fd, u64 dirid)
780 {
781         struct btrfs_ioctl_ino_lookup_args args;
782         int ret;
783         char *full;
784
785         memset(&args, 0, sizeof(args));
786         args.objectid = dirid;
787
788         ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
789         if (ret < 0) {
790                 fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n",
791                         (unsigned long long)dirid, strerror(errno));
792                 return ERR_PTR(ret);
793         }
794
795         if (args.name[0]) {
796                 /*
797                  * we're in a subdirectory of ref_tree, the kernel ioctl
798                  * puts a / in there for us
799                  */
800                 full = strdup(args.name);
801                 if (!full) {
802                         perror("malloc failed");
803                         return ERR_PTR(-ENOMEM);
804                 }
805         } else {
806                 /* we're at the root of ref_tree */
807                 full = NULL;
808         }
809         return full;
810 }
811
812 /*
813  * simple string builder, returning a new string with both
814  * dirid and name
815  */
816 static char *build_name(char *dirid, char *name)
817 {
818         char *full;
819         if (!dirid)
820                 return strdup(name);
821
822         full = malloc(strlen(dirid) + strlen(name) + 1);
823         if (!full)
824                 return NULL;
825         strcpy(full, dirid);
826         strcat(full, name);
827         return full;
828 }
829
830 /*
831  * given an inode number, this returns the full path name inside the subvolume
832  * to that file/directory.  cache_dirid and cache_name are used to
833  * cache the results so we can avoid tree searches if a later call goes
834  * to the same directory or file name
835  */
836 static char *ino_resolve(int fd, u64 ino, u64 *cache_dirid, char **cache_name)
837
838 {
839         u64 dirid;
840         char *dirname;
841         char *name;
842         char *full;
843         int ret;
844         struct btrfs_ioctl_search_args args;
845         struct btrfs_ioctl_search_key *sk = &args.key;
846         struct btrfs_ioctl_search_header *sh;
847         unsigned long off = 0;
848         int namelen;
849
850         memset(&args, 0, sizeof(args));
851
852         sk->tree_id = 0;
853
854         /*
855          * step one, we search for the inode back ref.  We just use the first
856          * one
857          */
858         sk->min_objectid = ino;
859         sk->max_objectid = ino;
860         sk->max_type = BTRFS_INODE_REF_KEY;
861         sk->max_offset = (u64)-1;
862         sk->min_type = BTRFS_INODE_REF_KEY;
863         sk->max_transid = (u64)-1;
864         sk->nr_items = 1;
865
866         ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
867         if (ret < 0) {
868                 fprintf(stderr, "ERROR: can't perform the search - %s\n",
869                         strerror(errno));
870                 return NULL;
871         }
872         /* the ioctl returns the number of item it found in nr_items */
873         if (sk->nr_items == 0)
874                 return NULL;
875
876         off = 0;
877         sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
878
879         if (btrfs_search_header_type(sh) == BTRFS_INODE_REF_KEY) {
880                 struct btrfs_inode_ref *ref;
881                 dirid = btrfs_search_header_offset(sh);
882
883                 ref = (struct btrfs_inode_ref *)(sh + 1);
884                 namelen = btrfs_stack_inode_ref_name_len(ref);
885
886                 name = (char *)(ref + 1);
887                 name = strndup(name, namelen);
888
889                 /* use our cached value */
890                 if (dirid == *cache_dirid && *cache_name) {
891                         dirname = *cache_name;
892                         goto build;
893                 }
894         } else {
895                 return NULL;
896         }
897         /*
898          * the inode backref gives us the file name and the parent directory id.
899          * From here we use __ino_resolve to get the path to the parent
900          */
901         dirname = __ino_resolve(fd, dirid);
902 build:
903         full = build_name(dirname, name);
904         if (*cache_name && dirname != *cache_name)
905                 free(*cache_name);
906
907         *cache_name = dirname;
908         *cache_dirid = dirid;
909         free(name);
910
911         return full;
912 }
913
914 int btrfs_list_get_default_subvolume(int fd, u64 *default_id)
915 {
916         struct btrfs_ioctl_search_args args;
917         struct btrfs_ioctl_search_key *sk = &args.key;
918         struct btrfs_ioctl_search_header *sh;
919         u64 found = 0;
920         int ret;
921
922         memset(&args, 0, sizeof(args));
923
924         /*
925          * search for a dir item with a name 'default' in the tree of
926          * tree roots, it should point us to a default root
927          */
928         sk->tree_id = 1;
929
930         /* don't worry about ancient format and request only one item */
931         sk->nr_items = 1;
932
933         sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
934         sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
935         sk->max_type = BTRFS_DIR_ITEM_KEY;
936         sk->min_type = BTRFS_DIR_ITEM_KEY;
937         sk->max_offset = (u64)-1;
938         sk->max_transid = (u64)-1;
939
940         ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
941         if (ret < 0)
942                 return ret;
943
944         /* the ioctl returns the number of items it found in nr_items */
945         if (sk->nr_items == 0)
946                 goto out;
947
948         sh = (struct btrfs_ioctl_search_header *)args.buf;
949
950         if (btrfs_search_header_type(sh) == BTRFS_DIR_ITEM_KEY) {
951                 struct btrfs_dir_item *di;
952                 int name_len;
953                 char *name;
954
955                 di = (struct btrfs_dir_item *)(sh + 1);
956                 name_len = btrfs_stack_dir_name_len(di);
957                 name = (char *)(di + 1);
958
959                 if (!strncmp("default", name, name_len))
960                         found = btrfs_disk_key_objectid(&di->location);
961         }
962
963 out:
964         *default_id = found;
965         return 0;
966 }
967
968 static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
969 {
970         int ret;
971         struct btrfs_ioctl_search_args args;
972         struct btrfs_ioctl_search_key *sk = &args.key;
973         struct btrfs_ioctl_search_header sh;
974         struct btrfs_root_ref *ref;
975         struct btrfs_root_item *ri;
976         unsigned long off = 0;
977         int name_len;
978         char *name;
979         u64 dir_id;
980         u64 gen = 0;
981         u64 ogen;
982         u64 flags;
983         int i;
984         time_t t;
985         u8 uuid[BTRFS_UUID_SIZE];
986         u8 puuid[BTRFS_UUID_SIZE];
987         u8 ruuid[BTRFS_UUID_SIZE];
988
989         root_lookup_init(root_lookup);
990         memset(&args, 0, sizeof(args));
991
992         /* search in the tree of tree roots */
993         sk->tree_id = 1;
994
995         /*
996          * set the min and max to backref keys.  The search will
997          * only send back this type of key now.
998          */
999         sk->max_type = BTRFS_ROOT_BACKREF_KEY;
1000         sk->min_type = BTRFS_ROOT_ITEM_KEY;
1001
1002         sk->min_objectid = BTRFS_FIRST_FREE_OBJECTID;
1003
1004         /*
1005          * set all the other params to the max, we'll take any objectid
1006          * and any trans
1007          */
1008         sk->max_objectid = BTRFS_LAST_FREE_OBJECTID;
1009         sk->max_offset = (u64)-1;
1010         sk->max_transid = (u64)-1;
1011
1012         /* just a big number, doesn't matter much */
1013         sk->nr_items = 4096;
1014
1015         while(1) {
1016                 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1017                 if (ret < 0)
1018                         return ret;
1019                 /* the ioctl returns the number of item it found in nr_items */
1020                 if (sk->nr_items == 0)
1021                         break;
1022
1023                 off = 0;
1024
1025                 /*
1026                  * for each item, pull the key out of the header and then
1027                  * read the root_ref item it contains
1028                  */
1029                 for (i = 0; i < sk->nr_items; i++) {
1030                         memcpy(&sh, args.buf + off, sizeof(sh));
1031                         off += sizeof(sh);
1032                         if (sh.type == BTRFS_ROOT_BACKREF_KEY) {
1033                                 ref = (struct btrfs_root_ref *)(args.buf + off);
1034                                 name_len = btrfs_stack_root_ref_name_len(ref);
1035                                 name = (char *)(ref + 1);
1036                                 dir_id = btrfs_stack_root_ref_dirid(ref);
1037
1038                                 add_root(root_lookup, sh.objectid, sh.offset,
1039                                          0, 0, dir_id, name, name_len, 0, 0, 0,
1040                                          NULL, NULL, NULL);
1041                         } else if (sh.type == BTRFS_ROOT_ITEM_KEY) {
1042                                 ri = (struct btrfs_root_item *)(args.buf + off);
1043                                 gen = btrfs_root_generation(ri);
1044                                 flags = btrfs_root_flags(ri);
1045                                 if(sh.len >
1046                                    sizeof(struct btrfs_root_item_v0)) {
1047                                         t = btrfs_stack_timespec_sec(&ri->otime);
1048                                         ogen = btrfs_root_otransid(ri);
1049                                         memcpy(uuid, ri->uuid, BTRFS_UUID_SIZE);
1050                                         memcpy(puuid, ri->parent_uuid, BTRFS_UUID_SIZE);
1051                                         memcpy(ruuid, ri->received_uuid, BTRFS_UUID_SIZE);
1052                                 } else {
1053                                         t = 0;
1054                                         ogen = 0;
1055                                         memset(uuid, 0, BTRFS_UUID_SIZE);
1056                                         memset(puuid, 0, BTRFS_UUID_SIZE);
1057                                         memset(ruuid, 0, BTRFS_UUID_SIZE);
1058                                 }
1059
1060                                 add_root(root_lookup, sh.objectid, 0,
1061                                          sh.offset, flags, 0, NULL, 0, ogen,
1062                                          gen, t, uuid, puuid, ruuid);
1063                         }
1064
1065                         off += sh.len;
1066
1067                         /*
1068                          * record the mins in sk so we can make sure the
1069                          * next search doesn't repeat this root
1070                          */
1071                         sk->min_objectid = sh.objectid;
1072                         sk->min_type = sh.type;
1073                         sk->min_offset = sh.offset;
1074                 }
1075                 sk->nr_items = 4096;
1076                 sk->min_offset++;
1077                 if (!sk->min_offset)    /* overflow */
1078                         sk->min_type++;
1079                 else
1080                         continue;
1081
1082                 if (sk->min_type > BTRFS_ROOT_BACKREF_KEY) {
1083                         sk->min_type = BTRFS_ROOT_ITEM_KEY;
1084                         sk->min_objectid++;
1085                 } else
1086                         continue;
1087
1088                 if (sk->min_objectid > sk->max_objectid)
1089                         break;
1090         }
1091
1092         return 0;
1093 }
1094
1095 static int filter_by_rootid(struct root_info *ri, u64 data)
1096 {
1097         return ri->root_id == data;
1098 }
1099
1100 static int filter_snapshot(struct root_info *ri, u64 data)
1101 {
1102         return !!ri->root_offset;
1103 }
1104
1105 static int filter_flags(struct root_info *ri, u64 flags)
1106 {
1107         return ri->flags & flags;
1108 }
1109
1110 static int filter_gen_more(struct root_info *ri, u64 data)
1111 {
1112         return ri->gen >= data;
1113 }
1114
1115 static int filter_gen_less(struct root_info *ri, u64 data)
1116 {
1117         return ri->gen <= data;
1118 }
1119
1120 static int filter_gen_equal(struct root_info  *ri, u64 data)
1121 {
1122         return ri->gen == data;
1123 }
1124
1125 static int filter_cgen_more(struct root_info *ri, u64 data)
1126 {
1127         return ri->ogen >= data;
1128 }
1129
1130 static int filter_cgen_less(struct root_info *ri, u64 data)
1131 {
1132         return ri->ogen <= data;
1133 }
1134
1135 static int filter_cgen_equal(struct root_info *ri, u64 data)
1136 {
1137         return ri->ogen == data;
1138 }
1139
1140 static int filter_topid_equal(struct root_info *ri, u64 data)
1141 {
1142         return ri->top_id == data;
1143 }
1144
1145 static int filter_full_path(struct root_info *ri, u64 data)
1146 {
1147         if (ri->full_path && ri->top_id != data) {
1148                 char *tmp;
1149                 char p[] = "<FS_TREE>";
1150                 int add_len = strlen(p);
1151                 int len = strlen(ri->full_path);
1152
1153                 tmp = malloc(len + add_len + 2);
1154                 if (!tmp) {
1155                         fprintf(stderr, "memory allocation failed\n");
1156                         exit(1);
1157                 }
1158                 memcpy(tmp + add_len + 1, ri->full_path, len);
1159                 tmp[len + add_len + 1] = '\0';
1160                 tmp[add_len] = '/';
1161                 memcpy(tmp, p, add_len);
1162                 free(ri->full_path);
1163                 ri->full_path = tmp;
1164         }
1165         return 1;
1166 }
1167
1168 static int filter_by_parent(struct root_info *ri, u64 data)
1169 {
1170         return !uuid_compare(ri->puuid, (u8 *)(unsigned long)data);
1171 }
1172
1173 static int filter_deleted(struct root_info *ri, u64 data)
1174 {
1175         return ri->deleted;
1176 }
1177
1178 static btrfs_list_filter_func all_filter_funcs[] = {
1179         [BTRFS_LIST_FILTER_ROOTID]              = filter_by_rootid,
1180         [BTRFS_LIST_FILTER_SNAPSHOT_ONLY]       = filter_snapshot,
1181         [BTRFS_LIST_FILTER_FLAGS]               = filter_flags,
1182         [BTRFS_LIST_FILTER_GEN_MORE]            = filter_gen_more,
1183         [BTRFS_LIST_FILTER_GEN_LESS]            = filter_gen_less,
1184         [BTRFS_LIST_FILTER_GEN_EQUAL]           = filter_gen_equal,
1185         [BTRFS_LIST_FILTER_CGEN_MORE]           = filter_cgen_more,
1186         [BTRFS_LIST_FILTER_CGEN_LESS]           = filter_cgen_less,
1187         [BTRFS_LIST_FILTER_CGEN_EQUAL]          = filter_cgen_equal,
1188         [BTRFS_LIST_FILTER_TOPID_EQUAL]         = filter_topid_equal,
1189         [BTRFS_LIST_FILTER_FULL_PATH]           = filter_full_path,
1190         [BTRFS_LIST_FILTER_BY_PARENT]           = filter_by_parent,
1191         [BTRFS_LIST_FILTER_DELETED]             = filter_deleted,
1192 };
1193
1194 struct btrfs_list_filter_set *btrfs_list_alloc_filter_set(void)
1195 {
1196         struct btrfs_list_filter_set *set;
1197         int size;
1198
1199         size = sizeof(struct btrfs_list_filter_set) +
1200                BTRFS_LIST_NFILTERS_INCREASE * sizeof(struct btrfs_list_filter);
1201         set = calloc(1, size);
1202         if (!set) {
1203                 fprintf(stderr, "memory allocation failed\n");
1204                 exit(1);
1205         }
1206
1207         set->total = BTRFS_LIST_NFILTERS_INCREASE;
1208
1209         return set;
1210 }
1211
1212 void btrfs_list_free_filter_set(struct btrfs_list_filter_set *filter_set)
1213 {
1214         free(filter_set);
1215 }
1216
1217 int btrfs_list_setup_filter(struct btrfs_list_filter_set **filter_set,
1218                             enum btrfs_list_filter_enum filter, u64 data)
1219 {
1220         struct btrfs_list_filter_set *set = *filter_set;
1221         int size;
1222
1223         BUG_ON(!set);
1224         BUG_ON(filter >= BTRFS_LIST_FILTER_MAX);
1225         BUG_ON(set->nfilters > set->total);
1226
1227         if (set->nfilters == set->total) {
1228                 void *tmp;
1229
1230                 size = set->total + BTRFS_LIST_NFILTERS_INCREASE;
1231                 size = sizeof(*set) + size * sizeof(struct btrfs_list_filter);
1232                 tmp = set;
1233                 set = realloc(set, size);
1234                 if (!set) {
1235                         fprintf(stderr, "memory allocation failed\n");
1236                         free(tmp);
1237                         exit(1);
1238                 }
1239
1240                 memset(&set->filters[set->total], 0,
1241                        BTRFS_LIST_NFILTERS_INCREASE *
1242                        sizeof(struct btrfs_list_filter));
1243                 set->total += BTRFS_LIST_NFILTERS_INCREASE;
1244                 *filter_set = set;
1245         }
1246
1247         BUG_ON(set->filters[set->nfilters].filter_func);
1248
1249         if (filter == BTRFS_LIST_FILTER_DELETED)
1250                 set->only_deleted = 1;
1251
1252         set->filters[set->nfilters].filter_func = all_filter_funcs[filter];
1253         set->filters[set->nfilters].data = data;
1254         set->nfilters++;
1255         return 0;
1256 }
1257
1258 static int filter_root(struct root_info *ri,
1259                        struct btrfs_list_filter_set *set)
1260 {
1261         int i, ret;
1262
1263         if (!set)
1264                 return 1;
1265
1266         if (set->only_deleted && !ri->deleted)
1267                 return 0;
1268
1269         if (!set->only_deleted && ri->deleted)
1270                 return 0;
1271
1272         for (i = 0; i < set->nfilters; i++) {
1273                 if (!set->filters[i].filter_func)
1274                         break;
1275                 ret = set->filters[i].filter_func(ri, set->filters[i].data);
1276                 if (!ret)
1277                         return 0;
1278         }
1279         return 1;
1280 }
1281
1282 static void __filter_and_sort_subvol(struct root_lookup *all_subvols,
1283                                     struct root_lookup *sort_tree,
1284                                     struct btrfs_list_filter_set *filter_set,
1285                                     struct btrfs_list_comparer_set *comp_set,
1286                                     u64 top_id)
1287 {
1288         struct rb_node *n;
1289         struct root_info *entry;
1290         int ret;
1291
1292         root_lookup_init(sort_tree);
1293
1294         n = rb_last(&all_subvols->root);
1295         while (n) {
1296                 entry = rb_entry(n, struct root_info, rb_node);
1297
1298                 ret = resolve_root(all_subvols, entry, top_id);
1299                 if (ret == -ENOENT) {
1300                         entry->full_path = strdup("DELETED");
1301                         entry->deleted = 1;
1302                 }
1303                 ret = filter_root(entry, filter_set);
1304                 if (ret)
1305                         sort_tree_insert(sort_tree, entry, comp_set);
1306                 n = rb_prev(n);
1307         }
1308 }
1309
1310 static int __list_subvol_fill_paths(int fd, struct root_lookup *root_lookup)
1311 {
1312         struct rb_node *n;
1313
1314         n = rb_first(&root_lookup->root);
1315         while (n) {
1316                 struct root_info *entry;
1317                 int ret;
1318                 entry = rb_entry(n, struct root_info, rb_node);
1319                 ret = lookup_ino_path(fd, entry);
1320                 if (ret && ret != -ENOENT)
1321                         return ret;
1322                 n = rb_next(n);
1323         }
1324
1325         return 0;
1326 }
1327
1328 static void print_subvolume_column(struct root_info *subv,
1329                                    enum btrfs_list_column_enum column)
1330 {
1331         char tstr[256];
1332         char uuidparse[BTRFS_UUID_UNPARSED_SIZE];
1333
1334         BUG_ON(column >= BTRFS_LIST_ALL || column < 0);
1335
1336         switch (column) {
1337         case BTRFS_LIST_OBJECTID:
1338                 printf("%llu", subv->root_id);
1339                 break;
1340         case BTRFS_LIST_GENERATION:
1341                 printf("%llu", subv->gen);
1342                 break;
1343         case BTRFS_LIST_OGENERATION:
1344                 printf("%llu", subv->ogen);
1345                 break;
1346         case BTRFS_LIST_PARENT:
1347                 printf("%llu", subv->ref_tree);
1348                 break;
1349         case BTRFS_LIST_TOP_LEVEL:
1350                 printf("%llu", subv->top_id);
1351                 break;
1352         case BTRFS_LIST_OTIME:
1353                 if (subv->otime) {
1354                         struct tm tm;
1355
1356                         localtime_r(&subv->otime, &tm);
1357                         strftime(tstr, 256, "%Y-%m-%d %X", &tm);
1358                 } else
1359                         strcpy(tstr, "-");
1360                 printf("%s", tstr);
1361                 break;
1362         case BTRFS_LIST_UUID:
1363                 if (uuid_is_null(subv->uuid))
1364                         strcpy(uuidparse, "-");
1365                 else
1366                         uuid_unparse(subv->uuid, uuidparse);
1367                 printf("%s", uuidparse);
1368                 break;
1369         case BTRFS_LIST_PUUID:
1370                 if (uuid_is_null(subv->puuid))
1371                         strcpy(uuidparse, "-");
1372                 else
1373                         uuid_unparse(subv->puuid, uuidparse);
1374                 printf("%s", uuidparse);
1375                 break;
1376         case BTRFS_LIST_RUUID:
1377                 if (uuid_is_null(subv->ruuid))
1378                         strcpy(uuidparse, "-");
1379                 else
1380                         uuid_unparse(subv->ruuid, uuidparse);
1381                 printf("%s", uuidparse);
1382                 break;
1383         case BTRFS_LIST_PATH:
1384                 BUG_ON(!subv->full_path);
1385                 printf("%s", subv->full_path);
1386                 break;
1387         default:
1388                 break;
1389         }
1390 }
1391
1392 static void print_single_volume_info_raw(struct root_info *subv, char *raw_prefix)
1393 {
1394         int i;
1395
1396         for (i = 0; i < BTRFS_LIST_ALL; i++) {
1397                 if (!btrfs_list_columns[i].need_print)
1398                         continue;
1399
1400                 if (raw_prefix)
1401                         printf("%s",raw_prefix);
1402
1403                 print_subvolume_column(subv, i);
1404         }
1405         printf("\n");
1406 }
1407
1408 static void print_single_volume_info_table(struct root_info *subv)
1409 {
1410         int i;
1411
1412         for (i = 0; i < BTRFS_LIST_ALL; i++) {
1413                 if (!btrfs_list_columns[i].need_print)
1414                         continue;
1415
1416                 print_subvolume_column(subv, i);
1417
1418                 if (i != BTRFS_LIST_PATH)
1419                         printf("\t");
1420
1421                 if (i == BTRFS_LIST_TOP_LEVEL)
1422                         printf("\t");
1423         }
1424         printf("\n");
1425 }
1426
1427 static void print_single_volume_info_default(struct root_info *subv)
1428 {
1429         int i;
1430
1431         for (i = 0; i < BTRFS_LIST_ALL; i++) {
1432                 if (!btrfs_list_columns[i].need_print)
1433                         continue;
1434
1435                 printf("%s ", btrfs_list_columns[i].name);
1436                 print_subvolume_column(subv, i);
1437
1438                 if (i != BTRFS_LIST_PATH)
1439                         printf(" ");
1440         }
1441         printf("\n");
1442 }
1443
1444 static void print_all_volume_info_tab_head(void)
1445 {
1446         int i;
1447         int len;
1448         char barrier[20];
1449
1450         for (i = 0; i < BTRFS_LIST_ALL; i++) {
1451                 if (btrfs_list_columns[i].need_print)
1452                         printf("%s\t", btrfs_list_columns[i].name);
1453
1454                 if (i == BTRFS_LIST_ALL-1)
1455                         printf("\n");
1456         }
1457
1458         for (i = 0; i < BTRFS_LIST_ALL; i++) {
1459                 memset(barrier, 0, sizeof(barrier));
1460
1461                 if (btrfs_list_columns[i].need_print) {
1462                         len = strlen(btrfs_list_columns[i].name);
1463                         while (len--)
1464                                 strcat(barrier, "-");
1465
1466                         printf("%s\t", barrier);
1467                 }
1468                 if (i == BTRFS_LIST_ALL-1)
1469                         printf("\n");
1470         }
1471 }
1472
1473 static void print_all_volume_info(struct root_lookup *sorted_tree,
1474                                   int layout, char *raw_prefix)
1475 {
1476         struct rb_node *n;
1477         struct root_info *entry;
1478
1479         if (layout == BTRFS_LIST_LAYOUT_TABLE)
1480                 print_all_volume_info_tab_head();
1481
1482         n = rb_first(&sorted_tree->root);
1483         while (n) {
1484                 entry = rb_entry(n, struct root_info, sort_node);
1485                 switch (layout) {
1486                 case BTRFS_LIST_LAYOUT_DEFAULT:
1487                         print_single_volume_info_default(entry);
1488                         break;
1489                 case BTRFS_LIST_LAYOUT_TABLE:
1490                         print_single_volume_info_table(entry);
1491                         break;
1492                 case BTRFS_LIST_LAYOUT_RAW:
1493                         print_single_volume_info_raw(entry, raw_prefix);
1494                         break;
1495                 }
1496                 n = rb_next(n);
1497         }
1498 }
1499
1500 static int btrfs_list_subvols(int fd, struct root_lookup *root_lookup)
1501 {
1502         int ret;
1503
1504         ret = __list_subvol_search(fd, root_lookup);
1505         if (ret) {
1506                 fprintf(stderr, "ERROR: can't perform the search - %s\n",
1507                                 strerror(errno));
1508                 return ret;
1509         }
1510
1511         /*
1512          * now we have an rbtree full of root_info objects, but we need to fill
1513          * in their path names within the subvol that is referencing each one.
1514          */
1515         ret = __list_subvol_fill_paths(fd, root_lookup);
1516         return ret;
1517 }
1518
1519 int btrfs_list_subvols_print(int fd, struct btrfs_list_filter_set *filter_set,
1520                        struct btrfs_list_comparer_set *comp_set,
1521                        int layout, int full_path, char *raw_prefix)
1522 {
1523         struct root_lookup root_lookup;
1524         struct root_lookup root_sort;
1525         int ret = 0;
1526         u64 top_id = 0;
1527
1528         if (full_path)
1529                 ret = btrfs_list_get_path_rootid(fd, &top_id);
1530         if (ret)
1531                 return ret;
1532
1533         ret = btrfs_list_subvols(fd, &root_lookup);
1534         if (ret)
1535                 return ret;
1536         __filter_and_sort_subvol(&root_lookup, &root_sort, filter_set,
1537                                  comp_set, top_id);
1538
1539         print_all_volume_info(&root_sort, layout, raw_prefix);
1540         __free_all_subvolumn(&root_lookup);
1541
1542         return 0;
1543 }
1544
1545 static char *strdup_or_null(const char *s)
1546 {
1547         if (!s)
1548                 return NULL;
1549         return strdup(s);
1550 }
1551
1552 int btrfs_get_subvol(int fd, struct root_info *the_ri)
1553 {
1554         int ret, rr;
1555         struct root_lookup rl;
1556         struct rb_node *rbn;
1557         struct root_info *ri;
1558         u64 root_id;
1559
1560         ret = btrfs_list_get_path_rootid(fd, &root_id);
1561         if (ret)
1562                 return ret;
1563
1564         ret = btrfs_list_subvols(fd, &rl);
1565         if (ret)
1566                 return ret;
1567
1568         rbn = rb_first(&rl.root);
1569         while(rbn) {
1570                 ri = rb_entry(rbn, struct root_info, rb_node);
1571                 rr = resolve_root(&rl, ri, root_id);
1572                 if (rr == -ENOENT) {
1573                         ret = -ENOENT;
1574                         rbn = rb_next(rbn);
1575                         continue;
1576                 }
1577                 if (!comp_entry_with_rootid(the_ri, ri, 0)) {
1578                         memcpy(the_ri, ri, offsetof(struct root_info, path));
1579                         the_ri->path = strdup_or_null(ri->path);
1580                         the_ri->name = strdup_or_null(ri->name);
1581                         the_ri->full_path = strdup_or_null(ri->full_path);
1582                         ret = 0;
1583                         break;
1584                 }
1585                 rbn = rb_next(rbn);
1586         }
1587         __free_all_subvolumn(&rl);
1588         return ret;
1589 }
1590
1591 static int print_one_extent(int fd, struct btrfs_ioctl_search_header *sh,
1592                             struct btrfs_file_extent_item *item,
1593                             u64 found_gen, u64 *cache_dirid,
1594                             char **cache_dir_name, u64 *cache_ino,
1595                             char **cache_full_name)
1596 {
1597         u64 len = 0;
1598         u64 disk_start = 0;
1599         u64 disk_offset = 0;
1600         u8 type;
1601         int compressed = 0;
1602         int flags = 0;
1603         char *name = NULL;
1604
1605         if (btrfs_search_header_objectid(sh) == *cache_ino) {
1606                 name = *cache_full_name;
1607         } else if (*cache_full_name) {
1608                 free(*cache_full_name);
1609                 *cache_full_name = NULL;
1610         }
1611         if (!name) {
1612                 name = ino_resolve(fd, btrfs_search_header_objectid(sh),
1613                                    cache_dirid,
1614                                    cache_dir_name);
1615                 *cache_full_name = name;
1616                 *cache_ino = btrfs_search_header_objectid(sh);
1617         }
1618         if (!name)
1619                 return -EIO;
1620
1621         type = btrfs_stack_file_extent_type(item);
1622         compressed = btrfs_stack_file_extent_compression(item);
1623
1624         if (type == BTRFS_FILE_EXTENT_REG ||
1625             type == BTRFS_FILE_EXTENT_PREALLOC) {
1626                 disk_start = btrfs_stack_file_extent_disk_bytenr(item);
1627                 disk_offset = btrfs_stack_file_extent_offset(item);
1628                 len = btrfs_stack_file_extent_num_bytes(item);
1629         } else if (type == BTRFS_FILE_EXTENT_INLINE) {
1630                 disk_start = 0;
1631                 disk_offset = 0;
1632                 len = btrfs_stack_file_extent_ram_bytes(item);
1633         } else {
1634                 printf("unhandled extent type %d for inode %llu "
1635                        "file offset %llu gen %llu\n",
1636                         type,
1637                         (unsigned long long)btrfs_search_header_objectid(sh),
1638                         (unsigned long long)btrfs_search_header_offset(sh),
1639                         (unsigned long long)found_gen);
1640
1641                 return -EIO;
1642         }
1643         printf("inode %llu file offset %llu len %llu disk start %llu "
1644                "offset %llu gen %llu flags ",
1645                (unsigned long long)btrfs_search_header_objectid(sh),
1646                (unsigned long long)btrfs_search_header_offset(sh),
1647                (unsigned long long)len,
1648                (unsigned long long)disk_start,
1649                (unsigned long long)disk_offset,
1650                (unsigned long long)found_gen);
1651
1652         if (compressed) {
1653                 printf("COMPRESS");
1654                 flags++;
1655         }
1656         if (type == BTRFS_FILE_EXTENT_PREALLOC) {
1657                 printf("%sPREALLOC", flags ? "|" : "");
1658                 flags++;
1659         }
1660         if (type == BTRFS_FILE_EXTENT_INLINE) {
1661                 printf("%sINLINE", flags ? "|" : "");
1662                 flags++;
1663         }
1664         if (!flags)
1665                 printf("NONE");
1666
1667         printf(" %s\n", name);
1668         return 0;
1669 }
1670
1671 int btrfs_list_find_updated_files(int fd, u64 root_id, u64 oldest_gen)
1672 {
1673         int ret;
1674         struct btrfs_ioctl_search_args args;
1675         struct btrfs_ioctl_search_key *sk = &args.key;
1676         struct btrfs_ioctl_search_header sh;
1677         struct btrfs_file_extent_item *item;
1678         unsigned long off = 0;
1679         u64 found_gen;
1680         u64 max_found = 0;
1681         int i;
1682         u64 cache_dirid = 0;
1683         u64 cache_ino = 0;
1684         char *cache_dir_name = NULL;
1685         char *cache_full_name = NULL;
1686         struct btrfs_file_extent_item backup;
1687
1688         memset(&backup, 0, sizeof(backup));
1689         memset(&args, 0, sizeof(args));
1690
1691         sk->tree_id = root_id;
1692
1693         /*
1694          * set all the other params to the max, we'll take any objectid
1695          * and any trans
1696          */
1697         sk->max_objectid = (u64)-1;
1698         sk->max_offset = (u64)-1;
1699         sk->max_transid = (u64)-1;
1700         sk->max_type = BTRFS_EXTENT_DATA_KEY;
1701         sk->min_transid = oldest_gen;
1702         /* just a big number, doesn't matter much */
1703         sk->nr_items = 4096;
1704
1705         max_found = find_root_gen(fd);
1706         while(1) {
1707                 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1708                 if (ret < 0) {
1709                         fprintf(stderr, "ERROR: can't perform the search - %s\n",
1710                                 strerror(errno));
1711                         break;
1712                 }
1713                 /* the ioctl returns the number of item it found in nr_items */
1714                 if (sk->nr_items == 0)
1715                         break;
1716
1717                 off = 0;
1718
1719                 /*
1720                  * for each item, pull the key out of the header and then
1721                  * read the root_ref item it contains
1722                  */
1723                 for (i = 0; i < sk->nr_items; i++) {
1724                         memcpy(&sh, args.buf + off, sizeof(sh));
1725                         off += sizeof(sh);
1726
1727                         /*
1728                          * just in case the item was too big, pass something other
1729                          * than garbage
1730                          */
1731                         if (sh.len == 0)
1732                                 item = &backup;
1733                         else
1734                                 item = (struct btrfs_file_extent_item *)(args.buf +
1735                                                                  off);
1736                         found_gen = btrfs_stack_file_extent_generation(item);
1737                         if (sh.type == BTRFS_EXTENT_DATA_KEY &&
1738                             found_gen >= oldest_gen) {
1739                                 print_one_extent(fd, &sh, item, found_gen,
1740                                                  &cache_dirid, &cache_dir_name,
1741                                                  &cache_ino, &cache_full_name);
1742                         }
1743                         off += sh.len;
1744
1745                         /*
1746                          * record the mins in sk so we can make sure the
1747                          * next search doesn't repeat this root
1748                          */
1749                         sk->min_objectid = sh.objectid;
1750                         sk->min_offset = sh.offset;
1751                         sk->min_type = sh.type;
1752                 }
1753                 sk->nr_items = 4096;
1754                 if (sk->min_offset < (u64)-1)
1755                         sk->min_offset++;
1756                 else if (sk->min_objectid < (u64)-1) {
1757                         sk->min_objectid++;
1758                         sk->min_offset = 0;
1759                         sk->min_type = 0;
1760                 } else
1761                         break;
1762         }
1763         free(cache_dir_name);
1764         free(cache_full_name);
1765         printf("transid marker was %llu\n", (unsigned long long)max_found);
1766         return ret;
1767 }
1768
1769 char *btrfs_list_path_for_root(int fd, u64 root)
1770 {
1771         struct root_lookup root_lookup;
1772         struct rb_node *n;
1773         char *ret_path = NULL;
1774         int ret;
1775         u64 top_id;
1776
1777         ret = btrfs_list_get_path_rootid(fd, &top_id);
1778         if (ret)
1779                 return ERR_PTR(ret);
1780
1781         ret = __list_subvol_search(fd, &root_lookup);
1782         if (ret < 0)
1783                 return ERR_PTR(ret);
1784
1785         ret = __list_subvol_fill_paths(fd, &root_lookup);
1786         if (ret < 0)
1787                 return ERR_PTR(ret);
1788
1789         n = rb_last(&root_lookup.root);
1790         while (n) {
1791                 struct root_info *entry;
1792
1793                 entry = rb_entry(n, struct root_info, rb_node);
1794                 ret = resolve_root(&root_lookup, entry, top_id);
1795                 if (ret == -ENOENT && entry->root_id == root) {
1796                         ret_path = NULL;
1797                         break;
1798                 }
1799                 if (entry->root_id == root) {
1800                         ret_path = entry->full_path;
1801                         entry->full_path = NULL;
1802                 }
1803
1804                 n = rb_prev(n);
1805         }
1806         __free_all_subvolumn(&root_lookup);
1807
1808         return ret_path;
1809 }
1810
1811 int btrfs_list_parse_sort_string(char *opt_arg,
1812                                  struct btrfs_list_comparer_set **comps)
1813 {
1814         int order;
1815         int flag;
1816         char *p;
1817         char **ptr_argv;
1818         int what_to_sort;
1819
1820         while ((p = strtok(opt_arg, ",")) != NULL) {
1821                 flag = 0;
1822                 ptr_argv = all_sort_items;
1823
1824                 while (*ptr_argv) {
1825                         if (strcmp(*ptr_argv, p) == 0) {
1826                                 flag = 1;
1827                                 break;
1828                         } else {
1829                                 p++;
1830                                 if (strcmp(*ptr_argv, p) == 0) {
1831                                         flag = 1;
1832                                         p--;
1833                                         break;
1834                                 }
1835                                 p--;
1836                         }
1837                         ptr_argv++;
1838                 }
1839
1840                 if (flag == 0)
1841                         return -1;
1842
1843                 else {
1844                         if (*p == '+') {
1845                                 order = 0;
1846                                 p++;
1847                         } else if (*p == '-') {
1848                                 order = 1;
1849                                 p++;
1850                         } else
1851                                 order = 0;
1852
1853                         what_to_sort = btrfs_list_get_sort_item(p);
1854                         btrfs_list_setup_comparer(comps, what_to_sort, order);
1855                 }
1856                 opt_arg = NULL;
1857         }
1858
1859         return 0;
1860 }
1861
1862 /*
1863  * This function is used to parse the argument of filter condition.
1864  *
1865  * type is the filter object.
1866  */
1867 int btrfs_list_parse_filter_string(char *opt_arg,
1868                                    struct btrfs_list_filter_set **filters,
1869                                    enum btrfs_list_filter_enum type)
1870 {
1871
1872         u64 arg;
1873
1874         switch (*(opt_arg++)) {
1875         case '+':
1876                 arg = arg_strtou64(opt_arg);
1877                 type += 2;
1878
1879                 btrfs_list_setup_filter(filters, type, arg);
1880                 break;
1881         case '-':
1882                 arg = arg_strtou64(opt_arg);
1883                 type += 1;
1884
1885                 btrfs_list_setup_filter(filters, type, arg);
1886                 break;
1887         default:
1888                 opt_arg--;
1889                 arg = arg_strtou64(opt_arg);
1890
1891                 btrfs_list_setup_filter(filters, type, arg);
1892                 break;
1893         }
1894
1895         return 0;
1896 }
1897
1898 int btrfs_list_get_path_rootid(int fd, u64 *treeid)
1899 {
1900         int  ret;
1901         struct btrfs_ioctl_ino_lookup_args args;
1902
1903         memset(&args, 0, sizeof(args));
1904         args.objectid = BTRFS_FIRST_FREE_OBJECTID;
1905
1906         ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
1907         if (ret < 0) {
1908                 fprintf(stderr,
1909                         "ERROR: can't perform the search - %s\n",
1910                         strerror(errno));
1911                 return ret;
1912         }
1913         *treeid = args.treeid;
1914         return 0;
1915 }