btrfs-progs: fsck: understand the -s option
[btrfs-progs-unstable/devel.git] / btrfs-list.c
blobc53d01641bf0e307584ffb3e5332f4fb88185338
1 /*
2 * Copyright (C) 2010 Oracle. All rights reserved.
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.
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.
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.
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"
38 /* we store all the roots we find in an rbtree so that we can
39 * search for them later.
41 struct root_lookup {
42 struct rb_root root;
46 * one of these for each root we find.
48 struct root_info {
49 struct rb_node rb_node;
51 /* this root's id */
52 u64 root_id;
54 /* the id of the root that references this one */
55 u64 ref_tree;
57 /* the dir id we're in from ref_tree */
58 u64 dir_id;
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.
63 char *path;
65 /* the name of this root in the directory it lives in */
66 char name[];
69 static void root_lookup_init(struct root_lookup *tree)
71 tree->root.rb_node = NULL;
74 static int comp_entry(struct root_info *entry, u64 root_id, u64 ref_tree)
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;
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
92 static struct rb_node *tree_insert(struct rb_root *root, u64 root_id,
93 u64 ref_tree, struct rb_node *node)
95 struct rb_node ** p = &root->rb_node;
96 struct rb_node * parent = NULL;
97 struct root_info *entry;
98 int comp;
100 while(*p) {
101 parent = *p;
102 entry = rb_entry(parent, struct root_info, rb_node);
104 comp = comp_entry(entry, root_id, ref_tree);
106 if (comp < 0)
107 p = &(*p)->rb_left;
108 else if (comp > 0)
109 p = &(*p)->rb_right;
110 else
111 return parent;
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;
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
124 static struct root_info *tree_search(struct rb_root *root, u64 root_id)
126 struct rb_node * n = root->rb_node;
127 struct root_info *entry;
129 while(n) {
130 entry = rb_entry(n, struct root_info, rb_node);
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;
150 return entry;
153 return NULL;
157 * this allocates a new root in the lookup tree.
159 * root_id should be the object id of the root
161 * ref_tree is the objectid of the referring root.
163 * dir_id is the directory in ref_tree where this root_id can be found.
165 * name is the name of root_id in that directory
167 * name_len is the length of name
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)
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);
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 if (name_len > 0)
187 ri->name[name_len] = 0;
189 ret = tree_insert(&root_lookup->root, root_id, ref_tree, &ri->rb_node);
190 if (ret) {
191 printf("failed to insert tree %llu\n", (unsigned long long)root_id);
192 exit(1);
194 return 0;
198 * for a given root_info, search through the root_lookup tree to construct
199 * the full path name to it.
201 * This can't be called until all the root_info->path fields are filled
202 * in by lookup_ino_path
204 static int resolve_root(struct root_lookup *rl, struct root_info *ri,
205 u64 *parent_id, u64 *top_id, char **path)
207 char *full_path = NULL;
208 int len = 0;
209 struct root_info *found;
212 * we go backwards from the root_info object and add pathnames
213 * from parent directories as we go.
215 *parent_id = 0;
216 found = ri;
217 while (1) {
218 char *tmp;
219 u64 next;
220 int add_len = strlen(found->path);
222 /* room for / and for null */
223 tmp = malloc(add_len + 2 + len);
224 if (full_path) {
225 memcpy(tmp + add_len + 1, full_path, len);
226 tmp[add_len] = '/';
227 memcpy(tmp, found->path, add_len);
228 tmp [add_len + len + 1] = '\0';
229 free(full_path);
230 full_path = tmp;
231 len += add_len + 1;
232 } else {
233 full_path = strdup(found->path);
234 len = add_len;
237 next = found->ref_tree;
238 /* record the first parent */
239 if (*parent_id == 0)
240 *parent_id = next;
242 /* if the ref_tree refers to ourselves, we're at the top */
243 if (next == found->root_id) {
244 *top_id = next;
245 break;
249 * if the ref_tree wasn't in our tree of roots, we're
250 * at the top
252 found = tree_search(&rl->root, next);
253 if (!found) {
254 *top_id = next;
255 break;
259 *path = full_path;
261 return 0;
265 * for a single root_info, ask the kernel to give us a path name
266 * inside it's ref_root for the dir_id where it lives.
268 * This fills in root_info->path with the path to the directory and and
269 * appends this root's name.
271 static int lookup_ino_path(int fd, struct root_info *ri)
273 struct btrfs_ioctl_ino_lookup_args args;
274 int ret, e;
276 if (ri->path)
277 return 0;
279 memset(&args, 0, sizeof(args));
280 args.treeid = ri->ref_tree;
281 args.objectid = ri->dir_id;
283 ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
284 e = errno;
285 if (ret) {
286 fprintf(stderr, "ERROR: Failed to lookup path for root %llu - %s\n",
287 (unsigned long long)ri->ref_tree,
288 strerror(e));
289 return ret;
292 if (args.name[0]) {
294 * we're in a subdirectory of ref_tree, the kernel ioctl
295 * puts a / in there for us
297 ri->path = malloc(strlen(ri->name) + strlen(args.name) + 1);
298 if (!ri->path) {
299 perror("malloc failed");
300 exit(1);
302 strcpy(ri->path, args.name);
303 strcat(ri->path, ri->name);
304 } else {
305 /* we're at the root of ref_tree */
306 ri->path = strdup(ri->name);
307 if (!ri->path) {
308 perror("strdup failed");
309 exit(1);
312 return 0;
315 /* finding the generation for a given path is a two step process.
316 * First we use the inode loookup routine to find out the root id
318 * Then we use the tree search ioctl to scan all the root items for a
319 * given root id and spit out the latest generation we can find
321 static u64 find_root_gen(int fd)
323 struct btrfs_ioctl_ino_lookup_args ino_args;
324 int ret;
325 struct btrfs_ioctl_search_args args;
326 struct btrfs_ioctl_search_key *sk = &args.key;
327 struct btrfs_ioctl_search_header *sh;
328 unsigned long off = 0;
329 u64 max_found = 0;
330 int i;
331 int e;
333 memset(&ino_args, 0, sizeof(ino_args));
334 ino_args.objectid = BTRFS_FIRST_FREE_OBJECTID;
336 /* this ioctl fills in ino_args->treeid */
337 ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args);
338 e = errno;
339 if (ret) {
340 fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n",
341 (unsigned long long)BTRFS_FIRST_FREE_OBJECTID,
342 strerror(e));
343 return 0;
346 memset(&args, 0, sizeof(args));
348 sk->tree_id = 1;
351 * there may be more than one ROOT_ITEM key if there are
352 * snapshots pending deletion, we have to loop through
353 * them.
355 sk->min_objectid = ino_args.treeid;
356 sk->max_objectid = ino_args.treeid;
357 sk->max_type = BTRFS_ROOT_ITEM_KEY;
358 sk->min_type = BTRFS_ROOT_ITEM_KEY;
359 sk->max_offset = (u64)-1;
360 sk->max_transid = (u64)-1;
361 sk->nr_items = 4096;
363 while (1) {
364 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
365 e = errno;
366 if (ret < 0) {
367 fprintf(stderr, "ERROR: can't perform the search - %s\n",
368 strerror(e));
369 return 0;
371 /* the ioctl returns the number of item it found in nr_items */
372 if (sk->nr_items == 0)
373 break;
375 off = 0;
376 for (i = 0; i < sk->nr_items; i++) {
377 struct btrfs_root_item *item;
378 sh = (struct btrfs_ioctl_search_header *)(args.buf +
379 off);
381 off += sizeof(*sh);
382 item = (struct btrfs_root_item *)(args.buf + off);
383 off += sh->len;
385 sk->min_objectid = sh->objectid;
386 sk->min_type = sh->type;
387 sk->min_offset = sh->offset;
389 if (sh->objectid > ino_args.treeid)
390 break;
392 if (sh->objectid == ino_args.treeid &&
393 sh->type == BTRFS_ROOT_ITEM_KEY) {
394 max_found = max(max_found,
395 btrfs_root_generation(item));
398 if (sk->min_offset < (u64)-1)
399 sk->min_offset++;
400 else
401 break;
403 if (sk->min_type != BTRFS_ROOT_ITEM_KEY)
404 break;
405 if (sk->min_objectid != BTRFS_ROOT_ITEM_KEY)
406 break;
408 return max_found;
411 /* pass in a directory id and this will return
412 * the full path of the parent directory inside its
413 * subvolume root.
415 * It may return NULL if it is in the root, or an ERR_PTR if things
416 * go badly.
418 static char *__ino_resolve(int fd, u64 dirid)
420 struct btrfs_ioctl_ino_lookup_args args;
421 int ret;
422 char *full;
423 int e;
425 memset(&args, 0, sizeof(args));
426 args.objectid = dirid;
428 ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
429 e = errno;
430 if (ret) {
431 fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n",
432 (unsigned long long)dirid, strerror(e) );
433 return ERR_PTR(ret);
436 if (args.name[0]) {
438 * we're in a subdirectory of ref_tree, the kernel ioctl
439 * puts a / in there for us
441 full = strdup(args.name);
442 if (!full) {
443 perror("malloc failed");
444 return ERR_PTR(-ENOMEM);
446 } else {
447 /* we're at the root of ref_tree */
448 full = NULL;
450 return full;
454 * simple string builder, returning a new string with both
455 * dirid and name
457 char *build_name(char *dirid, char *name)
459 char *full;
460 if (!dirid)
461 return strdup(name);
463 full = malloc(strlen(dirid) + strlen(name) + 1);
464 if (!full)
465 return NULL;
466 strcpy(full, dirid);
467 strcat(full, name);
468 return full;
472 * given an inode number, this returns the full path name inside the subvolume
473 * to that file/directory. cache_dirid and cache_name are used to
474 * cache the results so we can avoid tree searches if a later call goes
475 * to the same directory or file name
477 static char *ino_resolve(int fd, u64 ino, u64 *cache_dirid, char **cache_name)
480 u64 dirid;
481 char *dirname;
482 char *name;
483 char *full;
484 int ret;
485 struct btrfs_ioctl_search_args args;
486 struct btrfs_ioctl_search_key *sk = &args.key;
487 struct btrfs_ioctl_search_header *sh;
488 unsigned long off = 0;
489 int namelen;
490 int e;
492 memset(&args, 0, sizeof(args));
494 sk->tree_id = 0;
497 * step one, we search for the inode back ref. We just use the first
498 * one
500 sk->min_objectid = ino;
501 sk->max_objectid = ino;
502 sk->max_type = BTRFS_INODE_REF_KEY;
503 sk->max_offset = (u64)-1;
504 sk->min_type = BTRFS_INODE_REF_KEY;
505 sk->max_transid = (u64)-1;
506 sk->nr_items = 1;
508 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
509 e = errno;
510 if (ret < 0) {
511 fprintf(stderr, "ERROR: can't perform the search - %s\n",
512 strerror(e));
513 return NULL;
515 /* the ioctl returns the number of item it found in nr_items */
516 if (sk->nr_items == 0)
517 return NULL;
519 off = 0;
520 sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
522 if (sh->type == BTRFS_INODE_REF_KEY) {
523 struct btrfs_inode_ref *ref;
524 dirid = sh->offset;
526 ref = (struct btrfs_inode_ref *)(sh + 1);
527 namelen = btrfs_stack_inode_ref_name_len(ref);
529 name = (char *)(ref + 1);
530 name = strndup(name, namelen);
532 /* use our cached value */
533 if (dirid == *cache_dirid && *cache_name) {
534 dirname = *cache_name;
535 goto build;
537 } else {
538 return NULL;
541 * the inode backref gives us the file name and the parent directory id.
542 * From here we use __ino_resolve to get the path to the parent
544 dirname = __ino_resolve(fd, dirid);
545 build:
546 full = build_name(dirname, name);
547 if (*cache_name && dirname != *cache_name)
548 free(*cache_name);
550 *cache_name = dirname;
551 *cache_dirid = dirid;
552 free(name);
554 return full;
557 static int get_default_subvolid(int fd, u64 *default_id)
559 struct btrfs_ioctl_search_args args;
560 struct btrfs_ioctl_search_key *sk = &args.key;
561 struct btrfs_ioctl_search_header *sh;
562 u64 found = 0;
563 int ret;
565 memset(&args, 0, sizeof(args));
568 * search for a dir item with a name 'default' in the tree of
569 * tree roots, it should point us to a default root
571 sk->tree_id = 1;
573 /* don't worry about ancient format and request only one item */
574 sk->nr_items = 1;
576 sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
577 sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
578 sk->max_type = BTRFS_DIR_ITEM_KEY;
579 sk->min_type = BTRFS_DIR_ITEM_KEY;
580 sk->max_offset = (u64)-1;
581 sk->max_transid = (u64)-1;
583 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
584 if (ret < 0)
585 return ret;
587 /* the ioctl returns the number of items it found in nr_items */
588 if (sk->nr_items == 0)
589 goto out;
591 sh = (struct btrfs_ioctl_search_header *)args.buf;
593 if (sh->type == BTRFS_DIR_ITEM_KEY) {
594 struct btrfs_dir_item *di;
595 int name_len;
596 char *name;
598 di = (struct btrfs_dir_item *)(sh + 1);
599 name_len = btrfs_stack_dir_name_len(di);
600 name = (char *)(di + 1);
602 if (!strncmp("default", name, name_len))
603 found = btrfs_disk_key_objectid(&di->location);
606 out:
607 *default_id = found;
608 return 0;
611 static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
613 int ret;
614 struct btrfs_ioctl_search_args args;
615 struct btrfs_ioctl_search_key *sk = &args.key;
616 struct btrfs_ioctl_search_header *sh;
617 struct btrfs_root_ref *ref;
618 unsigned long off = 0;
619 int name_len;
620 char *name;
621 u64 dir_id;
622 int i;
624 root_lookup_init(root_lookup);
625 memset(&args, 0, sizeof(args));
627 /* search in the tree of tree roots */
628 sk->tree_id = 1;
631 * set the min and max to backref keys. The search will
632 * only send back this type of key now.
634 sk->max_type = BTRFS_ROOT_BACKREF_KEY;
635 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
638 * set all the other params to the max, we'll take any objectid
639 * and any trans
641 sk->max_objectid = (u64)-1;
642 sk->max_offset = (u64)-1;
643 sk->max_transid = (u64)-1;
645 /* just a big number, doesn't matter much */
646 sk->nr_items = 4096;
648 while(1) {
649 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
650 if (ret < 0)
651 return ret;
652 /* the ioctl returns the number of item it found in nr_items */
653 if (sk->nr_items == 0)
654 break;
656 off = 0;
659 * for each item, pull the key out of the header and then
660 * read the root_ref item it contains
662 for (i = 0; i < sk->nr_items; i++) {
663 sh = (struct btrfs_ioctl_search_header *)(args.buf +
664 off);
665 off += sizeof(*sh);
666 if (sh->type == BTRFS_ROOT_BACKREF_KEY) {
667 ref = (struct btrfs_root_ref *)(args.buf + off);
668 name_len = btrfs_stack_root_ref_name_len(ref);
669 name = (char *)(ref + 1);
670 dir_id = btrfs_stack_root_ref_dirid(ref);
672 add_root(root_lookup, sh->objectid, sh->offset,
673 dir_id, name, name_len);
676 off += sh->len;
679 * record the mins in sk so we can make sure the
680 * next search doesn't repeat this root
682 sk->min_objectid = sh->objectid;
683 sk->min_type = sh->type;
684 sk->min_offset = sh->offset;
686 sk->nr_items = 4096;
687 /* this iteration is done, step forward one root for the next
688 * ioctl
690 if (sk->min_type < BTRFS_ROOT_BACKREF_KEY) {
691 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
692 sk->min_offset = 0;
693 } else if (sk->min_objectid < (u64)-1) {
694 sk->min_objectid++;
695 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
696 sk->min_offset = 0;
697 } else
698 break;
701 return 0;
704 static int __list_subvol_fill_paths(int fd, struct root_lookup *root_lookup)
706 struct rb_node *n;
708 n = rb_first(&root_lookup->root);
709 while (n) {
710 struct root_info *entry;
711 int ret;
712 entry = rb_entry(n, struct root_info, rb_node);
713 ret = lookup_ino_path(fd, entry);
714 if(ret < 0)
715 return ret;
716 n = rb_next(n);
719 return 0;
722 int list_subvols(int fd, int print_parent, int get_default)
724 struct root_lookup root_lookup;
725 struct rb_node *n;
726 u64 default_id;
727 int ret;
729 if (get_default) {
730 ret = get_default_subvolid(fd, &default_id);
731 if (ret) {
732 fprintf(stderr, "ERROR: can't perform the search - %s\n",
733 strerror(errno));
734 return ret;
736 if (default_id == 0) {
737 fprintf(stderr, "ERROR: 'default' dir item not found\n");
738 return ret;
741 /* no need to resolve roots if FS_TREE is default */
742 if (default_id == BTRFS_FS_TREE_OBJECTID) {
743 printf("ID 5 (FS_TREE)\n");
744 return ret;
748 ret = __list_subvol_search(fd, &root_lookup);
749 if (ret) {
750 fprintf(stderr, "ERROR: can't perform the search - %s\n",
751 strerror(errno));
752 return ret;
756 * now we have an rbtree full of root_info objects, but we need to fill
757 * in their path names within the subvol that is referencing each one.
759 ret = __list_subvol_fill_paths(fd, &root_lookup);
760 if (ret < 0)
761 return ret;
763 /* now that we have all the subvol-relative paths filled in,
764 * we have to string the subvols together so that we can get
765 * a path all the way back to the FS root
767 n = rb_last(&root_lookup.root);
768 while (n) {
769 struct root_info *entry;
770 u64 level;
771 u64 parent_id;
772 char *path;
774 entry = rb_entry(n, struct root_info, rb_node);
775 if (get_default && entry->root_id != default_id) {
776 n = rb_prev(n);
777 continue;
780 resolve_root(&root_lookup, entry, &parent_id, &level, &path);
781 if (print_parent) {
782 printf("ID %llu parent %llu top level %llu path %s\n",
783 (unsigned long long)entry->root_id,
784 (unsigned long long)parent_id,
785 (unsigned long long)level, path);
786 } else {
787 printf("ID %llu top level %llu path %s\n",
788 (unsigned long long)entry->root_id,
789 (unsigned long long)level, path);
792 free(path);
793 n = rb_prev(n);
796 return ret;
799 static int print_one_extent(int fd, struct btrfs_ioctl_search_header *sh,
800 struct btrfs_file_extent_item *item,
801 u64 found_gen, u64 *cache_dirid,
802 char **cache_dir_name, u64 *cache_ino,
803 char **cache_full_name)
805 u64 len = 0;
806 u64 disk_start = 0;
807 u64 disk_offset = 0;
808 u8 type;
809 int compressed = 0;
810 int flags = 0;
811 char *name = NULL;
813 if (sh->objectid == *cache_ino) {
814 name = *cache_full_name;
815 } else if (*cache_full_name) {
816 free(*cache_full_name);
817 *cache_full_name = NULL;
819 if (!name) {
820 name = ino_resolve(fd, sh->objectid, cache_dirid,
821 cache_dir_name);
822 *cache_full_name = name;
823 *cache_ino = sh->objectid;
825 if (!name)
826 return -EIO;
828 type = btrfs_stack_file_extent_type(item);
829 compressed = btrfs_stack_file_extent_compression(item);
831 if (type == BTRFS_FILE_EXTENT_REG ||
832 type == BTRFS_FILE_EXTENT_PREALLOC) {
833 disk_start = btrfs_stack_file_extent_disk_bytenr(item);
834 disk_offset = btrfs_stack_file_extent_offset(item);
835 len = btrfs_stack_file_extent_num_bytes(item);
836 } else if (type == BTRFS_FILE_EXTENT_INLINE) {
837 disk_start = 0;
838 disk_offset = 0;
839 len = btrfs_stack_file_extent_ram_bytes(item);
840 } else {
841 printf("unhandled extent type %d for inode %llu "
842 "file offset %llu gen %llu\n",
843 type,
844 (unsigned long long)sh->objectid,
845 (unsigned long long)sh->offset,
846 (unsigned long long)found_gen);
848 return -EIO;
850 printf("inode %llu file offset %llu len %llu disk start %llu "
851 "offset %llu gen %llu flags ",
852 (unsigned long long)sh->objectid,
853 (unsigned long long)sh->offset,
854 (unsigned long long)len,
855 (unsigned long long)disk_start,
856 (unsigned long long)disk_offset,
857 (unsigned long long)found_gen);
859 if (compressed) {
860 printf("COMPRESS");
861 flags++;
863 if (type == BTRFS_FILE_EXTENT_PREALLOC) {
864 printf("%sPREALLOC", flags ? "|" : "");
865 flags++;
867 if (type == BTRFS_FILE_EXTENT_INLINE) {
868 printf("%sINLINE", flags ? "|" : "");
869 flags++;
871 if (!flags)
872 printf("NONE");
874 printf(" %s\n", name);
875 return 0;
878 int find_updated_files(int fd, u64 root_id, u64 oldest_gen)
880 int ret;
881 struct btrfs_ioctl_search_args args;
882 struct btrfs_ioctl_search_key *sk = &args.key;
883 struct btrfs_ioctl_search_header *sh;
884 struct btrfs_file_extent_item *item;
885 unsigned long off = 0;
886 u64 found_gen;
887 u64 max_found = 0;
888 int i;
889 int e;
890 u64 cache_dirid = 0;
891 u64 cache_ino = 0;
892 char *cache_dir_name = NULL;
893 char *cache_full_name = NULL;
894 struct btrfs_file_extent_item backup;
896 memset(&backup, 0, sizeof(backup));
897 memset(&args, 0, sizeof(args));
899 sk->tree_id = root_id;
902 * set all the other params to the max, we'll take any objectid
903 * and any trans
905 sk->max_objectid = (u64)-1;
906 sk->max_offset = (u64)-1;
907 sk->max_transid = (u64)-1;
908 sk->max_type = BTRFS_EXTENT_DATA_KEY;
909 sk->min_transid = oldest_gen;
910 /* just a big number, doesn't matter much */
911 sk->nr_items = 4096;
913 max_found = find_root_gen(fd);
914 while(1) {
915 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
916 e = errno;
917 if (ret < 0) {
918 fprintf(stderr, "ERROR: can't perform the search- %s\n",
919 strerror(e));
920 return ret;
922 /* the ioctl returns the number of item it found in nr_items */
923 if (sk->nr_items == 0)
924 break;
926 off = 0;
929 * for each item, pull the key out of the header and then
930 * read the root_ref item it contains
932 for (i = 0; i < sk->nr_items; i++) {
933 sh = (struct btrfs_ioctl_search_header *)(args.buf +
934 off);
935 off += sizeof(*sh);
938 * just in case the item was too big, pass something other
939 * than garbage
941 if (sh->len == 0)
942 item = &backup;
943 else
944 item = (struct btrfs_file_extent_item *)(args.buf +
945 off);
946 found_gen = btrfs_stack_file_extent_generation(item);
947 if (sh->type == BTRFS_EXTENT_DATA_KEY &&
948 found_gen >= oldest_gen) {
949 print_one_extent(fd, sh, item, found_gen,
950 &cache_dirid, &cache_dir_name,
951 &cache_ino, &cache_full_name);
953 off += sh->len;
956 * record the mins in sk so we can make sure the
957 * next search doesn't repeat this root
959 sk->min_objectid = sh->objectid;
960 sk->min_offset = sh->offset;
961 sk->min_type = sh->type;
963 sk->nr_items = 4096;
964 if (sk->min_offset < (u64)-1)
965 sk->min_offset++;
966 else if (sk->min_objectid < (u64)-1) {
967 sk->min_objectid++;
968 sk->min_offset = 0;
969 sk->min_type = 0;
970 } else
971 break;
973 free(cache_dir_name);
974 free(cache_full_name);
975 printf("transid marker was %llu\n", (unsigned long long)max_found);
976 return ret;
979 char *path_for_root(int fd, u64 root)
981 struct root_lookup root_lookup;
982 struct rb_node *n;
983 char *ret_path = NULL;
984 int ret;
986 ret = __list_subvol_search(fd, &root_lookup);
987 if (ret < 0)
988 return ERR_PTR(ret);
990 ret = __list_subvol_fill_paths(fd, &root_lookup);
991 if (ret < 0)
992 return ERR_PTR(ret);
994 n = rb_last(&root_lookup.root);
995 while (n) {
996 struct root_info *entry;
997 u64 parent_id;
998 u64 level;
999 char *path;
1001 entry = rb_entry(n, struct root_info, rb_node);
1002 resolve_root(&root_lookup, entry, &parent_id, &level, &path);
1003 if (entry->root_id == root)
1004 ret_path = path;
1005 else
1006 free(path);
1008 n = rb_prev(n);
1011 return ret_path;