Btrfs-progs: refactor resolve_root() function a bit
[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 #define _GNU_SOURCE
20 #ifndef __CHECKER__
21 #include <sys/ioctl.h>
22 #include <sys/mount.h>
23 #include "ioctl.h"
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <dirent.h>
32 #include <libgen.h>
33 #include "kerncompat.h"
34 #include "ctree.h"
35 #include "transaction.h"
36 #include "utils.h"
37
38 /* we store all the roots we find in an rbtree so that we can
39  * search for them later.
40  */
41 struct root_lookup {
42         struct rb_root root;
43 };
44
45 /*
46  * one of these for each root we find.
47  */
48 struct root_info {
49         struct rb_node rb_node;
50
51         /* this root's id */
52         u64 root_id;
53
54         /* the id of the root that references this one */
55         u64 ref_tree;
56
57         /* the dir id we're in from ref_tree */
58         u64 dir_id;
59
60         /* path from the subvol we live in to this root, including the
61          * root's name.  This is null until we do the extra lookup ioctl.
62          */
63         char *path;
64
65         /* the name of this root in the directory it lives in */
66         char name[];
67 };
68
69 static void root_lookup_init(struct root_lookup *tree)
70 {
71         tree->root.rb_node = NULL;
72 }
73
74 static int comp_entry(struct root_info *entry, u64 root_id, u64 ref_tree)
75 {
76         if (entry->root_id > root_id)
77                 return 1;
78         if (entry->root_id < root_id)
79                 return -1;
80         if (entry->ref_tree > ref_tree)
81                 return 1;
82         if (entry->ref_tree < ref_tree)
83                 return -1;
84         return 0;
85 }
86
87 /*
88  * insert a new root into the tree.  returns the existing root entry
89  * if one is already there.  Both root_id and ref_tree are used
90  * as the key
91  */
92 static struct rb_node *tree_insert(struct rb_root *root, u64 root_id,
93                                    u64 ref_tree, struct rb_node *node)
94 {
95         struct rb_node ** p = &root->rb_node;
96         struct rb_node * parent = NULL;
97         struct root_info *entry;
98         int comp;
99
100         while(*p) {
101                 parent = *p;
102                 entry = rb_entry(parent, struct root_info, rb_node);
103
104                 comp = comp_entry(entry, root_id, ref_tree);
105
106                 if (comp < 0)
107                         p = &(*p)->rb_left;
108                 else if (comp > 0)
109                         p = &(*p)->rb_right;
110                 else
111                         return parent;
112         }
113
114         entry = rb_entry(parent, struct root_info, rb_node);
115         rb_link_node(node, parent, p);
116         rb_insert_color(node, root);
117         return NULL;
118 }
119
120 /*
121  * find a given root id in the tree.  We return the smallest one,
122  * rb_next can be used to move forward looking for more if required
123  */
124 static struct root_info *tree_search(struct rb_root *root, u64 root_id)
125 {
126         struct rb_node * n = root->rb_node;
127         struct root_info *entry;
128
129         while(n) {
130                 entry = rb_entry(n, struct root_info, rb_node);
131
132                 if (entry->root_id < root_id)
133                         n = n->rb_left;
134                 else if (entry->root_id > root_id)
135                         n = n->rb_right;
136                 else {
137                         struct root_info *prev;
138                         struct rb_node *prev_n;
139                         while (1) {
140                                 prev_n = rb_prev(n);
141                                 if (!prev_n)
142                                         break;
143                                 prev = rb_entry(prev_n, struct root_info,
144                                                       rb_node);
145                                 if (prev->root_id != root_id)
146                                         break;
147                                 entry = prev;
148                                 n = prev_n;
149                         }
150                         return entry;
151                 }
152         }
153         return NULL;
154 }
155
156 /*
157  * this allocates a new root in the lookup tree.
158  *
159  * root_id should be the object id of the root
160  *
161  * ref_tree is the objectid of the referring root.
162  *
163  * dir_id is the directory in ref_tree where this root_id can be found.
164  *
165  * name is the name of root_id in that directory
166  *
167  * name_len is the length of name
168  */
169 static int add_root(struct root_lookup *root_lookup,
170                     u64 root_id, u64 ref_tree, u64 dir_id, char *name,
171                     int name_len)
172 {
173         struct root_info *ri;
174         struct rb_node *ret;
175         ri = malloc(sizeof(*ri) + name_len + 1);
176         if (!ri) {
177                 printf("memory allocation failed\n");
178                 exit(1);
179         }
180         memset(ri, 0, sizeof(*ri) + name_len + 1);
181         ri->path = NULL;
182         ri->dir_id = dir_id;
183         ri->root_id = root_id;
184         ri->ref_tree = ref_tree;
185         strncpy(ri->name, name, name_len);
186
187         ret = tree_insert(&root_lookup->root, root_id, ref_tree, &ri->rb_node);
188         if (ret) {
189                 printf("failed to insert tree %llu\n", (unsigned long long)root_id);
190                 exit(1);
191         }
192         return 0;
193 }
194
195 /*
196  * for a given root_info, search through the root_lookup tree to construct
197  * the full path name to it.
198  *
199  * This can't be called until all the root_info->path fields are filled
200  * in by lookup_ino_path
201  */
202 static int resolve_root(struct root_lookup *rl, struct root_info *ri,
203                         u64 *parent_id, u64 *top_id, char **path)
204 {
205         char *full_path = NULL;
206         int len = 0;
207         struct root_info *found;
208
209         /*
210          * we go backwards from the root_info object and add pathnames
211          * from parent directories as we go.
212          */
213         *parent_id = 0;
214         found = ri;
215         while (1) {
216                 char *tmp;
217                 u64 next;
218                 int add_len = strlen(found->path);
219
220                 /* room for / and for null */
221                 tmp = malloc(add_len + 2 + len);
222                 if (full_path) {
223                         memcpy(tmp + add_len + 1, full_path, len);
224                         tmp[add_len] = '/';
225                         memcpy(tmp, found->path, add_len);
226                         tmp [add_len + len + 1] = '\0';
227                         free(full_path);
228                         full_path = tmp;
229                         len += add_len + 1;
230                 } else {
231                         full_path = strdup(found->path);
232                         len = add_len;
233                 }
234
235                 next = found->ref_tree;
236                 /* record the first parent */
237                 if (*parent_id == 0)
238                         *parent_id = next;
239
240                 /* if the ref_tree refers to ourselves, we're at the top */
241                 if (next == found->root_id) {
242                         *top_id = next;
243                         break;
244                 }
245
246                 /*
247                  * if the ref_tree wasn't in our tree of roots, we're
248                  * at the top
249                  */
250                 found = tree_search(&rl->root, next);
251                 if (!found) {
252                         *top_id = next;
253                         break;
254                 }
255         }
256
257         *path = full_path;
258
259         return 0;
260 }
261
262 /*
263  * for a single root_info, ask the kernel to give us a path name
264  * inside it's ref_root for the dir_id where it lives.
265  *
266  * This fills in root_info->path with the path to the directory and and
267  * appends this root's name.
268  */
269 static int lookup_ino_path(int fd, struct root_info *ri)
270 {
271         struct btrfs_ioctl_ino_lookup_args args;
272         int ret, e;
273
274         if (ri->path)
275                 return 0;
276
277         memset(&args, 0, sizeof(args));
278         args.treeid = ri->ref_tree;
279         args.objectid = ri->dir_id;
280
281         ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
282         e = errno;
283         if (ret) {
284                 fprintf(stderr, "ERROR: Failed to lookup path for root %llu - %s\n",
285                         (unsigned long long)ri->ref_tree,
286                         strerror(e));
287                 return ret;
288         }
289
290         if (args.name[0]) {
291                 /*
292                  * we're in a subdirectory of ref_tree, the kernel ioctl
293                  * puts a / in there for us
294                  */
295                 ri->path = malloc(strlen(ri->name) + strlen(args.name) + 1);
296                 if (!ri->path) {
297                         perror("malloc failed");
298                         exit(1);
299                 }
300                 strcpy(ri->path, args.name);
301                 strcat(ri->path, ri->name);
302         } else {
303                 /* we're at the root of ref_tree */
304                 ri->path = strdup(ri->name);
305                 if (!ri->path) {
306                         perror("strdup failed");
307                         exit(1);
308                 }
309         }
310         return 0;
311 }
312
313 /* finding the generation for a given path is a two step process.
314  * First we use the inode loookup routine to find out the root id
315  *
316  * Then we use the tree search ioctl to scan all the root items for a
317  * given root id and spit out the latest generation we can find
318  */
319 static u64 find_root_gen(int fd)
320 {
321         struct btrfs_ioctl_ino_lookup_args ino_args;
322         int ret;
323         struct btrfs_ioctl_search_args args;
324         struct btrfs_ioctl_search_key *sk = &args.key;
325         struct btrfs_ioctl_search_header *sh;
326         unsigned long off = 0;
327         u64 max_found = 0;
328         int i;
329         int e;
330
331         memset(&ino_args, 0, sizeof(ino_args));
332         ino_args.objectid = BTRFS_FIRST_FREE_OBJECTID;
333
334         /* this ioctl fills in ino_args->treeid */
335         ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args);
336         e = errno;
337         if (ret) {
338                 fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n",
339                         (unsigned long long)BTRFS_FIRST_FREE_OBJECTID,
340                         strerror(e));
341                 return 0;
342         }
343
344         memset(&args, 0, sizeof(args));
345
346         sk->tree_id = 1;
347
348         /*
349          * there may be more than one ROOT_ITEM key if there are
350          * snapshots pending deletion, we have to loop through
351          * them.
352          */
353         sk->min_objectid = ino_args.treeid;
354         sk->max_objectid = ino_args.treeid;
355         sk->max_type = BTRFS_ROOT_ITEM_KEY;
356         sk->min_type = BTRFS_ROOT_ITEM_KEY;
357         sk->max_offset = (u64)-1;
358         sk->max_transid = (u64)-1;
359         sk->nr_items = 4096;
360
361         while (1) {
362                 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
363                 e = errno;
364                 if (ret < 0) {
365                         fprintf(stderr, "ERROR: can't perform the search - %s\n",
366                                 strerror(e));
367                         return 0;
368                 }
369                 /* the ioctl returns the number of item it found in nr_items */
370                 if (sk->nr_items == 0)
371                         break;
372
373                 off = 0;
374                 for (i = 0; i < sk->nr_items; i++) {
375                         struct btrfs_root_item *item;
376                         sh = (struct btrfs_ioctl_search_header *)(args.buf +
377                                                                   off);
378
379                         off += sizeof(*sh);
380                         item = (struct btrfs_root_item *)(args.buf + off);
381                         off += sh->len;
382
383                         sk->min_objectid = sh->objectid;
384                         sk->min_type = sh->type;
385                         sk->min_offset = sh->offset;
386
387                         if (sh->objectid > ino_args.treeid)
388                                 break;
389
390                         if (sh->objectid == ino_args.treeid &&
391                             sh->type == BTRFS_ROOT_ITEM_KEY) {
392                                 max_found = max(max_found,
393                                                 btrfs_root_generation(item));
394                         }
395                 }
396                 if (sk->min_offset < (u64)-1)
397                         sk->min_offset++;
398                 else
399                         break;
400
401                 if (sk->min_type != BTRFS_ROOT_ITEM_KEY)
402                         break;
403                 if (sk->min_objectid != BTRFS_ROOT_ITEM_KEY)
404                         break;
405         }
406         return max_found;
407 }
408
409 /* pass in a directory id and this will return
410  * the full path of the parent directory inside its
411  * subvolume root.
412  *
413  * It may return NULL if it is in the root, or an ERR_PTR if things
414  * go badly.
415  */
416 static char *__ino_resolve(int fd, u64 dirid)
417 {
418         struct btrfs_ioctl_ino_lookup_args args;
419         int ret;
420         char *full;
421         int e;
422
423         memset(&args, 0, sizeof(args));
424         args.objectid = dirid;
425
426         ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
427         e = errno;
428         if (ret) {
429                 fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n",
430                         (unsigned long long)dirid, strerror(e) );
431                 return ERR_PTR(ret);
432         }
433
434         if (args.name[0]) {
435                 /*
436                  * we're in a subdirectory of ref_tree, the kernel ioctl
437                  * puts a / in there for us
438                  */
439                 full = strdup(args.name);
440                 if (!full) {
441                         perror("malloc failed");
442                         return ERR_PTR(-ENOMEM);
443                 }
444         } else {
445                 /* we're at the root of ref_tree */
446                 full = NULL;
447         }
448         return full;
449 }
450
451 /*
452  * simple string builder, returning a new string with both
453  * dirid and name
454  */
455 char *build_name(char *dirid, char *name)
456 {
457         char *full;
458         if (!dirid)
459                 return strdup(name);
460
461         full = malloc(strlen(dirid) + strlen(name) + 1);
462         if (!full)
463                 return NULL;
464         strcpy(full, dirid);
465         strcat(full, name);
466         return full;
467 }
468
469 /*
470  * given an inode number, this returns the full path name inside the subvolume
471  * to that file/directory.  cache_dirid and cache_name are used to
472  * cache the results so we can avoid tree searches if a later call goes
473  * to the same directory or file name
474  */
475 static char *ino_resolve(int fd, u64 ino, u64 *cache_dirid, char **cache_name)
476
477 {
478         u64 dirid;
479         char *dirname;
480         char *name;
481         char *full;
482         int ret;
483         struct btrfs_ioctl_search_args args;
484         struct btrfs_ioctl_search_key *sk = &args.key;
485         struct btrfs_ioctl_search_header *sh;
486         unsigned long off = 0;
487         int namelen;
488         int e;
489
490         memset(&args, 0, sizeof(args));
491
492         sk->tree_id = 0;
493
494         /*
495          * step one, we search for the inode back ref.  We just use the first
496          * one
497          */
498         sk->min_objectid = ino;
499         sk->max_objectid = ino;
500         sk->max_type = BTRFS_INODE_REF_KEY;
501         sk->max_offset = (u64)-1;
502         sk->min_type = BTRFS_INODE_REF_KEY;
503         sk->max_transid = (u64)-1;
504         sk->nr_items = 1;
505
506         ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
507         e = errno;
508         if (ret < 0) {
509                 fprintf(stderr, "ERROR: can't perform the search - %s\n",
510                         strerror(e));
511                 return NULL;
512         }
513         /* the ioctl returns the number of item it found in nr_items */
514         if (sk->nr_items == 0)
515                 return NULL;
516
517         off = 0;
518         sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
519
520         if (sh->type == BTRFS_INODE_REF_KEY) {
521                 struct btrfs_inode_ref *ref;
522                 dirid = sh->offset;
523
524                 ref = (struct btrfs_inode_ref *)(sh + 1);
525                 namelen = btrfs_stack_inode_ref_name_len(ref);
526
527                 name = (char *)(ref + 1);
528                 name = strndup(name, namelen);
529
530                 /* use our cached value */
531                 if (dirid == *cache_dirid && *cache_name) {
532                         dirname = *cache_name;
533                         goto build;
534                 }
535         } else {
536                 return NULL;
537         }
538         /*
539          * the inode backref gives us the file name and the parent directory id.
540          * From here we use __ino_resolve to get the path to the parent
541          */
542         dirname = __ino_resolve(fd, dirid);
543 build:
544         full = build_name(dirname, name);
545         if (*cache_name && dirname != *cache_name)
546                 free(*cache_name);
547
548         *cache_name = dirname;
549         *cache_dirid = dirid;
550         free(name);
551
552         return full;
553 }
554
555 static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
556 {
557         int ret;
558         struct btrfs_ioctl_search_args args;
559         struct btrfs_ioctl_search_key *sk = &args.key;
560         struct btrfs_ioctl_search_header *sh;
561         struct btrfs_root_ref *ref;
562         unsigned long off = 0;
563         int name_len;
564         char *name;
565         u64 dir_id;
566         int i;
567
568         root_lookup_init(root_lookup);
569         memset(&args, 0, sizeof(args));
570
571         /* search in the tree of tree roots */
572         sk->tree_id = 1;
573
574         /*
575          * set the min and max to backref keys.  The search will
576          * only send back this type of key now.
577          */
578         sk->max_type = BTRFS_ROOT_BACKREF_KEY;
579         sk->min_type = BTRFS_ROOT_BACKREF_KEY;
580
581         /*
582          * set all the other params to the max, we'll take any objectid
583          * and any trans
584          */
585         sk->max_objectid = (u64)-1;
586         sk->max_offset = (u64)-1;
587         sk->max_transid = (u64)-1;
588
589         /* just a big number, doesn't matter much */
590         sk->nr_items = 4096;
591
592         while(1) {
593                 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
594                 if (ret < 0)
595                         return ret;
596                 /* the ioctl returns the number of item it found in nr_items */
597                 if (sk->nr_items == 0)
598                         break;
599
600                 off = 0;
601
602                 /*
603                  * for each item, pull the key out of the header and then
604                  * read the root_ref item it contains
605                  */
606                 for (i = 0; i < sk->nr_items; i++) {
607                         sh = (struct btrfs_ioctl_search_header *)(args.buf +
608                                                                   off);
609                         off += sizeof(*sh);
610                         if (sh->type == BTRFS_ROOT_BACKREF_KEY) {
611                                 ref = (struct btrfs_root_ref *)(args.buf + off);
612                                 name_len = btrfs_stack_root_ref_name_len(ref);
613                                 name = (char *)(ref + 1);
614                                 dir_id = btrfs_stack_root_ref_dirid(ref);
615
616                                 add_root(root_lookup, sh->objectid, sh->offset,
617                                          dir_id, name, name_len);
618                         }
619
620                         off += sh->len;
621
622                         /*
623                          * record the mins in sk so we can make sure the
624                          * next search doesn't repeat this root
625                          */
626                         sk->min_objectid = sh->objectid;
627                         sk->min_type = sh->type;
628                         sk->min_offset = sh->offset;
629                 }
630                 sk->nr_items = 4096;
631                 /* this iteration is done, step forward one root for the next
632                  * ioctl
633                  */
634                 if (sk->min_type < BTRFS_ROOT_BACKREF_KEY) {
635                         sk->min_type = BTRFS_ROOT_BACKREF_KEY;
636                         sk->min_offset = 0;
637                 } else  if (sk->min_objectid < (u64)-1) {
638                         sk->min_objectid++;
639                         sk->min_type = BTRFS_ROOT_BACKREF_KEY;
640                         sk->min_offset = 0;
641                 } else
642                         break;
643         }
644
645         return 0;
646 }
647
648 static int __list_subvol_fill_paths(int fd, struct root_lookup *root_lookup)
649 {
650         struct rb_node *n;
651
652         n = rb_first(&root_lookup->root);
653         while (n) {
654                 struct root_info *entry;
655                 int ret;
656                 entry = rb_entry(n, struct root_info, rb_node);
657                 ret = lookup_ino_path(fd, entry);
658                 if(ret < 0)
659                         return ret;
660                 n = rb_next(n);
661         }
662
663         return 0;
664 }
665
666 int list_subvols(int fd, int print_parent)
667 {
668         struct root_lookup root_lookup;
669         struct rb_node *n;
670         int ret;
671
672         ret = __list_subvol_search(fd, &root_lookup);
673         if (ret) {
674                 fprintf(stderr, "ERROR: can't perform the search - %s\n",
675                                 strerror(errno));
676                 return ret;
677         }
678
679         /*
680          * now we have an rbtree full of root_info objects, but we need to fill
681          * in their path names within the subvol that is referencing each one.
682          */
683         ret = __list_subvol_fill_paths(fd, &root_lookup);
684         if (ret < 0)
685                 return ret;
686
687         /* now that we have all the subvol-relative paths filled in,
688          * we have to string the subvols together so that we can get
689          * a path all the way back to the FS root
690          */
691         n = rb_last(&root_lookup.root);
692         while (n) {
693                 struct root_info *entry;
694                 u64 level;
695                 u64 parent_id;
696                 char *path;
697
698                 entry = rb_entry(n, struct root_info, rb_node);
699                 resolve_root(&root_lookup, entry, &parent_id, &level, &path);
700                 if (print_parent) {
701                         printf("ID %llu parent %llu top level %llu path %s\n",
702                                 (unsigned long long)entry->root_id,
703                                 (unsigned long long)parent_id,
704                                 (unsigned long long)level, path);
705                 } else {
706                         printf("ID %llu top level %llu path %s\n",
707                                 (unsigned long long)entry->root_id,
708                                 (unsigned long long)level, path);
709                 }
710
711                 free(path);
712                 n = rb_prev(n);
713         }
714
715         return ret;
716 }
717
718 static int print_one_extent(int fd, struct btrfs_ioctl_search_header *sh,
719                             struct btrfs_file_extent_item *item,
720                             u64 found_gen, u64 *cache_dirid,
721                             char **cache_dir_name, u64 *cache_ino,
722                             char **cache_full_name)
723 {
724         u64 len = 0;
725         u64 disk_start = 0;
726         u64 disk_offset = 0;
727         u8 type;
728         int compressed = 0;
729         int flags = 0;
730         char *name = NULL;
731
732         if (sh->objectid == *cache_ino) {
733                 name = *cache_full_name;
734         } else if (*cache_full_name) {
735                 free(*cache_full_name);
736                 *cache_full_name = NULL;
737         }
738         if (!name) {
739                 name = ino_resolve(fd, sh->objectid, cache_dirid,
740                                    cache_dir_name);
741                 *cache_full_name = name;
742                 *cache_ino = sh->objectid;
743         }
744         if (!name)
745                 return -EIO;
746
747         type = btrfs_stack_file_extent_type(item);
748         compressed = btrfs_stack_file_extent_compression(item);
749
750         if (type == BTRFS_FILE_EXTENT_REG ||
751             type == BTRFS_FILE_EXTENT_PREALLOC) {
752                 disk_start = btrfs_stack_file_extent_disk_bytenr(item);
753                 disk_offset = btrfs_stack_file_extent_offset(item);
754                 len = btrfs_stack_file_extent_num_bytes(item);
755         } else if (type == BTRFS_FILE_EXTENT_INLINE) {
756                 disk_start = 0;
757                 disk_offset = 0;
758                 len = btrfs_stack_file_extent_ram_bytes(item);
759         } else {
760                 printf("unhandled extent type %d for inode %llu "
761                        "file offset %llu gen %llu\n",
762                         type,
763                         (unsigned long long)sh->objectid,
764                         (unsigned long long)sh->offset,
765                         (unsigned long long)found_gen);
766
767                 return -EIO;
768         }
769         printf("inode %llu file offset %llu len %llu disk start %llu "
770                "offset %llu gen %llu flags ",
771                (unsigned long long)sh->objectid,
772                (unsigned long long)sh->offset,
773                (unsigned long long)len,
774                (unsigned long long)disk_start,
775                (unsigned long long)disk_offset,
776                (unsigned long long)found_gen);
777
778         if (compressed) {
779                 printf("COMPRESS");
780                 flags++;
781         }
782         if (type == BTRFS_FILE_EXTENT_PREALLOC) {
783                 printf("%sPREALLOC", flags ? "|" : "");
784                 flags++;
785         }
786         if (type == BTRFS_FILE_EXTENT_INLINE) {
787                 printf("%sINLINE", flags ? "|" : "");
788                 flags++;
789         }
790         if (!flags)
791                 printf("NONE");
792
793         printf(" %s\n", name);
794         return 0;
795 }
796
797 int find_updated_files(int fd, u64 root_id, u64 oldest_gen)
798 {
799         int ret;
800         struct btrfs_ioctl_search_args args;
801         struct btrfs_ioctl_search_key *sk = &args.key;
802         struct btrfs_ioctl_search_header *sh;
803         struct btrfs_file_extent_item *item;
804         unsigned long off = 0;
805         u64 found_gen;
806         u64 max_found = 0;
807         int i;
808         int e;
809         u64 cache_dirid = 0;
810         u64 cache_ino = 0;
811         char *cache_dir_name = NULL;
812         char *cache_full_name = NULL;
813         struct btrfs_file_extent_item backup;
814
815         memset(&backup, 0, sizeof(backup));
816         memset(&args, 0, sizeof(args));
817
818         sk->tree_id = root_id;
819
820         /*
821          * set all the other params to the max, we'll take any objectid
822          * and any trans
823          */
824         sk->max_objectid = (u64)-1;
825         sk->max_offset = (u64)-1;
826         sk->max_transid = (u64)-1;
827         sk->max_type = BTRFS_EXTENT_DATA_KEY;
828         sk->min_transid = oldest_gen;
829         /* just a big number, doesn't matter much */
830         sk->nr_items = 4096;
831
832         max_found = find_root_gen(fd);
833         while(1) {
834                 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
835                 e = errno;
836                 if (ret < 0) {
837                         fprintf(stderr, "ERROR: can't perform the search- %s\n",
838                                 strerror(e));
839                         return ret;
840                 }
841                 /* the ioctl returns the number of item it found in nr_items */
842                 if (sk->nr_items == 0)
843                         break;
844
845                 off = 0;
846
847                 /*
848                  * for each item, pull the key out of the header and then
849                  * read the root_ref item it contains
850                  */
851                 for (i = 0; i < sk->nr_items; i++) {
852                         sh = (struct btrfs_ioctl_search_header *)(args.buf +
853                                                                   off);
854                         off += sizeof(*sh);
855
856                         /*
857                          * just in case the item was too big, pass something other
858                          * than garbage
859                          */
860                         if (sh->len == 0)
861                                 item = &backup;
862                         else
863                                 item = (struct btrfs_file_extent_item *)(args.buf +
864                                                                  off);
865                         found_gen = btrfs_stack_file_extent_generation(item);
866                         if (sh->type == BTRFS_EXTENT_DATA_KEY &&
867                             found_gen >= oldest_gen) {
868                                 print_one_extent(fd, sh, item, found_gen,
869                                                  &cache_dirid, &cache_dir_name,
870                                                  &cache_ino, &cache_full_name);
871                         }
872                         off += sh->len;
873
874                         /*
875                          * record the mins in sk so we can make sure the
876                          * next search doesn't repeat this root
877                          */
878                         sk->min_objectid = sh->objectid;
879                         sk->min_offset = sh->offset;
880                         sk->min_type = sh->type;
881                 }
882                 sk->nr_items = 4096;
883                 if (sk->min_offset < (u64)-1)
884                         sk->min_offset++;
885                 else if (sk->min_objectid < (u64)-1) {
886                         sk->min_objectid++;
887                         sk->min_offset = 0;
888                         sk->min_type = 0;
889                 } else
890                         break;
891         }
892         free(cache_dir_name);
893         free(cache_full_name);
894         printf("transid marker was %llu\n", (unsigned long long)max_found);
895         return ret;
896 }
897
898 char *path_for_root(int fd, u64 root)
899 {
900         struct root_lookup root_lookup;
901         struct rb_node *n;
902         char *ret_path = NULL;
903         int ret;
904
905         ret = __list_subvol_search(fd, &root_lookup);
906         if (ret < 0)
907                 return ERR_PTR(ret);
908
909         ret = __list_subvol_fill_paths(fd, &root_lookup);
910         if (ret < 0)
911                 return ERR_PTR(ret);
912
913         n = rb_last(&root_lookup.root);
914         while (n) {
915                 struct root_info *entry;
916                 u64 parent_id;
917                 u64 level;
918                 char *path;
919
920                 entry = rb_entry(n, struct root_info, rb_node);
921                 resolve_root(&root_lookup, entry, &parent_id, &level, &path);
922                 if (entry->root_id == root)
923                         ret_path = path;
924                 else
925                         free(path);
926
927                 n = rb_prev(n);
928         }
929
930         return ret_path;
931 }