* Boston, MA 021110-1307, USA.
*/
+#define _GNU_SOURCE
#ifndef __CHECKER__
#include <sys/ioctl.h>
#include <sys/mount.h>
#include "ctree.h"
#include "transaction.h"
#include "utils.h"
-#include "version.h"
/* we store all the roots we find in an rbtree so that we can
* search for them later.
ri->root_id = root_id;
ri->ref_tree = ref_tree;
strncpy(ri->name, name, name_len);
+ if (name_len > 0)
+ ri->name[name_len] = 0;
ret = tree_insert(&root_lookup->root, root_id, ref_tree, &ri->rb_node);
if (ret) {
* This can't be called until all the root_info->path fields are filled
* in by lookup_ino_path
*/
-static int resolve_root(struct root_lookup *rl, struct root_info *ri)
+static int resolve_root(struct root_lookup *rl, struct root_info *ri,
+ u64 *parent_id, u64 *top_id, char **path)
{
- u64 top_id;
char *full_path = NULL;
int len = 0;
struct root_info *found;
* we go backwards from the root_info object and add pathnames
* from parent directories as we go.
*/
+ *parent_id = 0;
found = ri;
while (1) {
char *tmp;
}
next = found->ref_tree;
+ /* record the first parent */
+ if (*parent_id == 0)
+ *parent_id = next;
+
/* if the ref_tree refers to ourselves, we're at the top */
if (next == found->root_id) {
- top_id = next;
+ *top_id = next;
break;
}
*/
found = tree_search(&rl->root, next);
if (!found) {
- top_id = next;
+ *top_id = next;
break;
}
}
- printf("ID %llu top level %llu path %s\n", ri->root_id, top_id,
- full_path);
- free(full_path);
+
+ *path = full_path;
+
return 0;
}
static int lookup_ino_path(int fd, struct root_info *ri)
{
struct btrfs_ioctl_ino_lookup_args args;
- int ret;
+ int ret, e;
if (ri->path)
return 0;
args.objectid = ri->dir_id;
ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
+ e = errno;
if (ret) {
- fprintf(stderr, "ERROR: Failed to lookup path for root %llu\n",
- (unsigned long long)ri->ref_tree);
+ fprintf(stderr, "ERROR: Failed to lookup path for root %llu - %s\n",
+ (unsigned long long)ri->ref_tree,
+ strerror(e));
return ret;
}
unsigned long off = 0;
u64 max_found = 0;
int i;
+ int e;
memset(&ino_args, 0, sizeof(ino_args));
ino_args.objectid = BTRFS_FIRST_FREE_OBJECTID;
/* this ioctl fills in ino_args->treeid */
ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args);
+ e = errno;
if (ret) {
- fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu\n",
- (unsigned long long)BTRFS_FIRST_FREE_OBJECTID);
+ fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n",
+ (unsigned long long)BTRFS_FIRST_FREE_OBJECTID,
+ strerror(e));
return 0;
}
while (1) {
ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
+ e = errno;
if (ret < 0) {
- fprintf(stderr, "ERROR: can't perform the search\n");
+ fprintf(stderr, "ERROR: can't perform the search - %s\n",
+ strerror(e));
return 0;
}
/* the ioctl returns the number of item it found in nr_items */
struct btrfs_ioctl_ino_lookup_args args;
int ret;
char *full;
+ int e;
memset(&args, 0, sizeof(args));
args.objectid = dirid;
ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
+ e = errno;
if (ret) {
- fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu\n",
- (unsigned long long)dirid);
+ fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n",
+ (unsigned long long)dirid, strerror(e) );
return ERR_PTR(ret);
}
struct btrfs_ioctl_search_header *sh;
unsigned long off = 0;
int namelen;
+ int e;
memset(&args, 0, sizeof(args));
sk->nr_items = 1;
ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
+ e = errno;
if (ret < 0) {
- fprintf(stderr, "ERROR: can't perform the search\n");
+ fprintf(stderr, "ERROR: can't perform the search - %s\n",
+ strerror(e));
return NULL;
}
/* the ioctl returns the number of item it found in nr_items */
return full;
}
-int list_subvols(int fd)
+static int get_default_subvolid(int fd, u64 *default_id)
+{
+ struct btrfs_ioctl_search_args args;
+ struct btrfs_ioctl_search_key *sk = &args.key;
+ struct btrfs_ioctl_search_header *sh;
+ u64 found = 0;
+ int ret;
+
+ memset(&args, 0, sizeof(args));
+
+ /*
+ * search for a dir item with a name 'default' in the tree of
+ * tree roots, it should point us to a default root
+ */
+ sk->tree_id = 1;
+
+ /* don't worry about ancient format and request only one item */
+ sk->nr_items = 1;
+
+ sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+ sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+ sk->max_type = BTRFS_DIR_ITEM_KEY;
+ sk->min_type = BTRFS_DIR_ITEM_KEY;
+ sk->max_offset = (u64)-1;
+ sk->max_transid = (u64)-1;
+
+ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
+ if (ret < 0)
+ return ret;
+
+ /* the ioctl returns the number of items it found in nr_items */
+ if (sk->nr_items == 0)
+ goto out;
+
+ sh = (struct btrfs_ioctl_search_header *)args.buf;
+
+ if (sh->type == BTRFS_DIR_ITEM_KEY) {
+ struct btrfs_dir_item *di;
+ int name_len;
+ char *name;
+
+ di = (struct btrfs_dir_item *)(sh + 1);
+ name_len = btrfs_stack_dir_name_len(di);
+ name = (char *)(di + 1);
+
+ if (!strncmp("default", name, name_len))
+ found = btrfs_disk_key_objectid(&di->location);
+ }
+
+out:
+ *default_id = found;
+ return 0;
+}
+
+static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
{
- struct root_lookup root_lookup;
- struct rb_node *n;
int ret;
struct btrfs_ioctl_search_args args;
struct btrfs_ioctl_search_key *sk = &args.key;
u64 dir_id;
int i;
- root_lookup_init(&root_lookup);
-
+ root_lookup_init(root_lookup);
memset(&args, 0, sizeof(args));
/* search in the tree of tree roots */
while(1) {
ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
- if (ret < 0) {
- fprintf(stderr, "ERROR: can't perform the search\n");
+ if (ret < 0)
return ret;
- }
/* the ioctl returns the number of item it found in nr_items */
if (sk->nr_items == 0)
break;
name = (char *)(ref + 1);
dir_id = btrfs_stack_root_ref_dirid(ref);
- add_root(&root_lookup, sh->objectid, sh->offset,
+ add_root(root_lookup, sh->objectid, sh->offset,
dir_id, name, name_len);
}
/* this iteration is done, step forward one root for the next
* ioctl
*/
- if (sk->min_objectid < (u64)-1) {
+ if (sk->min_type < BTRFS_ROOT_BACKREF_KEY) {
+ sk->min_type = BTRFS_ROOT_BACKREF_KEY;
+ sk->min_offset = 0;
+ } else if (sk->min_objectid < (u64)-1) {
sk->min_objectid++;
sk->min_type = BTRFS_ROOT_BACKREF_KEY;
sk->min_offset = 0;
} else
break;
}
- /*
- * now we have an rbtree full of root_info objects, but we need to fill
- * in their path names within the subvol that is referencing each one.
- */
- n = rb_first(&root_lookup.root);
+
+ return 0;
+}
+
+static int __list_subvol_fill_paths(int fd, struct root_lookup *root_lookup)
+{
+ struct rb_node *n;
+
+ n = rb_first(&root_lookup->root);
while (n) {
struct root_info *entry;
int ret;
n = rb_next(n);
}
+ return 0;
+}
+
+int list_subvols(int fd, int print_parent, int get_default)
+{
+ struct root_lookup root_lookup;
+ struct rb_node *n;
+ u64 default_id;
+ int ret;
+
+ if (get_default) {
+ ret = get_default_subvolid(fd, &default_id);
+ if (ret) {
+ fprintf(stderr, "ERROR: can't perform the search - %s\n",
+ strerror(errno));
+ return ret;
+ }
+ if (default_id == 0) {
+ fprintf(stderr, "ERROR: 'default' dir item not found\n");
+ return ret;
+ }
+
+ /* no need to resolve roots if FS_TREE is default */
+ if (default_id == BTRFS_FS_TREE_OBJECTID) {
+ printf("ID 5 (FS_TREE)\n");
+ return ret;
+ }
+ }
+
+ ret = __list_subvol_search(fd, &root_lookup);
+ if (ret) {
+ fprintf(stderr, "ERROR: can't perform the search - %s\n",
+ strerror(errno));
+ return ret;
+ }
+
+ /*
+ * now we have an rbtree full of root_info objects, but we need to fill
+ * in their path names within the subvol that is referencing each one.
+ */
+ ret = __list_subvol_fill_paths(fd, &root_lookup);
+ if (ret < 0)
+ return ret;
+
/* now that we have all the subvol-relative paths filled in,
* we have to string the subvols together so that we can get
* a path all the way back to the FS root
n = rb_last(&root_lookup.root);
while (n) {
struct root_info *entry;
+ u64 level;
+ u64 parent_id;
+ char *path;
+
entry = rb_entry(n, struct root_info, rb_node);
- resolve_root(&root_lookup, entry);
+ if (get_default && entry->root_id != default_id) {
+ n = rb_prev(n);
+ continue;
+ }
+
+ resolve_root(&root_lookup, entry, &parent_id, &level, &path);
+ if (print_parent) {
+ printf("ID %llu parent %llu top level %llu path %s\n",
+ (unsigned long long)entry->root_id,
+ (unsigned long long)parent_id,
+ (unsigned long long)level, path);
+ } else {
+ printf("ID %llu top level %llu path %s\n",
+ (unsigned long long)entry->root_id,
+ (unsigned long long)level, path);
+ }
+
+ free(path);
n = rb_prev(n);
}
char **cache_dir_name, u64 *cache_ino,
char **cache_full_name)
{
- u64 len;
- u64 disk_start;
- u64 disk_offset;
+ u64 len = 0;
+ u64 disk_start = 0;
+ u64 disk_offset = 0;
u8 type;
int compressed = 0;
int flags = 0;
disk_start = 0;
disk_offset = 0;
len = btrfs_stack_file_extent_ram_bytes(item);
+ } else {
+ printf("unhandled extent type %d for inode %llu "
+ "file offset %llu gen %llu\n",
+ type,
+ (unsigned long long)sh->objectid,
+ (unsigned long long)sh->offset,
+ (unsigned long long)found_gen);
+
+ return -EIO;
}
printf("inode %llu file offset %llu len %llu disk start %llu "
"offset %llu gen %llu flags ",
u64 found_gen;
u64 max_found = 0;
int i;
+ int e;
u64 cache_dirid = 0;
u64 cache_ino = 0;
char *cache_dir_name = NULL;
max_found = find_root_gen(fd);
while(1) {
ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
+ e = errno;
if (ret < 0) {
- fprintf(stderr, "ERROR: can't perform the search\n");
+ fprintf(stderr, "ERROR: can't perform the search- %s\n",
+ strerror(e));
return ret;
}
/* the ioctl returns the number of item it found in nr_items */
printf("transid marker was %llu\n", (unsigned long long)max_found);
return ret;
}
+
+char *path_for_root(int fd, u64 root)
+{
+ struct root_lookup root_lookup;
+ struct rb_node *n;
+ char *ret_path = NULL;
+ int ret;
+
+ ret = __list_subvol_search(fd, &root_lookup);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ ret = __list_subvol_fill_paths(fd, &root_lookup);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ n = rb_last(&root_lookup.root);
+ while (n) {
+ struct root_info *entry;
+ u64 parent_id;
+ u64 level;
+ char *path;
+
+ entry = rb_entry(n, struct root_info, rb_node);
+ resolve_root(&root_lookup, entry, &parent_id, &level, &path);
+ if (entry->root_id == root)
+ ret_path = path;
+ else
+ free(path);
+
+ n = rb_prev(n);
+ }
+
+ return ret_path;
+}