1 // SPDX-License-Identifier: GPL-2.0+
3 * BTRFS filesystem implementation for U-Boot
5 * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
14 * Resolve the path of ino inside subvolume @root into @path_ret.
16 * @path_ret must be at least PATH_MAX size.
18 static int get_path_in_subvol(struct btrfs_root *root, u64 ino, char *path_ret)
20 struct btrfs_path path;
26 tmp = malloc(PATH_MAX);
31 btrfs_init_path(&path);
32 while (cur != BTRFS_FIRST_FREE_OBJECTID) {
33 struct btrfs_inode_ref *iref;
36 btrfs_release_path(&path);
38 key.type = BTRFS_INODE_REF_KEY;
41 ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
47 ret = btrfs_previous_item(root, &path, cur,
54 strncpy(tmp, path_ret, PATH_MAX);
55 iref = btrfs_item_ptr(path.nodes[0], path.slots[0],
56 struct btrfs_inode_ref);
57 name_len = btrfs_inode_ref_name_len(path.nodes[0],
59 if (name_len > BTRFS_NAME_LEN) {
63 read_extent_buffer(path.nodes[0], path_ret,
64 (unsigned long)(iref + 1), name_len);
65 path_ret[name_len] = '/';
66 path_ret[name_len + 1] = '\0';
67 strncat(path_ret, tmp, PATH_MAX);
69 btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
73 btrfs_release_path(&path);
78 static int list_one_subvol(struct btrfs_root *root, char *path_ret)
80 struct btrfs_fs_info *fs_info = root->fs_info;
81 struct btrfs_root *tree_root = fs_info->tree_root;
82 struct btrfs_path path;
85 u64 cur = root->root_key.objectid;
88 tmp = malloc(PATH_MAX);
93 btrfs_init_path(&path);
94 while (cur != BTRFS_FS_TREE_OBJECTID) {
95 struct btrfs_root_ref *rr;
96 struct btrfs_key location;
101 key.type = BTRFS_ROOT_BACKREF_KEY;
102 key.offset = (u64)-1;
103 btrfs_release_path(&path);
105 ret = btrfs_search_slot(NULL, tree_root, &key, &path, 0, 0);
110 ret = btrfs_previous_item(tree_root, &path, cur,
111 BTRFS_ROOT_BACKREF_KEY);
117 /* Get the subvolume name */
118 rr = btrfs_item_ptr(path.nodes[0], path.slots[0],
119 struct btrfs_root_ref);
120 strncpy(tmp, path_ret, PATH_MAX);
121 name_len = btrfs_root_ref_name_len(path.nodes[0], rr);
122 if (name_len > BTRFS_NAME_LEN) {
126 ino = btrfs_root_ref_dirid(path.nodes[0], rr);
127 read_extent_buffer(path.nodes[0], path_ret,
128 (unsigned long)(rr + 1), name_len);
129 path_ret[name_len] = '/';
130 path_ret[name_len + 1] = '\0';
131 strncat(path_ret, tmp, PATH_MAX);
133 /* Get the path inside the parent subvolume */
134 btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
135 location.objectid = key.offset;
136 location.type = BTRFS_ROOT_ITEM_KEY;
137 location.offset = (u64)-1;
138 root = btrfs_read_fs_root(fs_info, &location);
143 ret = get_path_in_subvol(root, ino, path_ret);
148 /* Add the leading '/' */
149 strncpy(tmp, path_ret, PATH_MAX);
150 strncpy(path_ret, "/", PATH_MAX);
151 strncat(path_ret, tmp, PATH_MAX);
153 btrfs_release_path(&path);
158 static int list_subvolums(struct btrfs_fs_info *fs_info)
160 struct btrfs_root *tree_root = fs_info->tree_root;
161 struct btrfs_root *root;
162 struct btrfs_path path;
163 struct btrfs_key key;
167 result = malloc(PATH_MAX);
171 ret = list_one_subvol(fs_info->fs_root, result);
174 root = fs_info->fs_root;
175 printf("ID %llu gen %llu path %.*s\n",
176 root->root_key.objectid, btrfs_root_generation(&root->root_item),
179 key.objectid = BTRFS_FIRST_FREE_OBJECTID;
180 key.type = BTRFS_ROOT_ITEM_KEY;
182 btrfs_init_path(&path);
183 ret = btrfs_search_slot(NULL, tree_root, &key, &path, 0, 0);
187 if (path.slots[0] >= btrfs_header_nritems(path.nodes[0]))
190 btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
191 if (key.objectid > BTRFS_LAST_FREE_OBJECTID)
193 if (key.objectid < BTRFS_FIRST_FREE_OBJECTID ||
194 key.type != BTRFS_ROOT_ITEM_KEY)
196 key.offset = (u64)-1;
197 root = btrfs_read_fs_root(fs_info, &key);
203 ret = list_one_subvol(root, result);
206 printf("ID %llu gen %llu path %.*s\n",
207 root->root_key.objectid,
208 btrfs_root_generation(&root->root_item),
211 ret = btrfs_next_item(tree_root, &path);
224 void btrfs_list_subvols(void)
226 struct btrfs_fs_info *fs_info = current_fs_info;
231 ret = list_subvolums(fs_info);
233 error("failed to list subvolume: %d", ret);