1 // SPDX-License-Identifier: GPL-2.0+
3 * BTRFS filesystem implementation for U-Boot
5 * 2017 Marek BehĂșn, CZ.NIC, kabel@kernel.org
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
);
204 ret
= list_one_subvol(root
, result
);
207 printf("ID %llu gen %llu path %.*s\n",
208 root
->root_key
.objectid
,
209 btrfs_root_generation(&root
->root_item
),
212 ret
= btrfs_next_item(tree_root
, &path
);
225 void btrfs_list_subvols(void)
227 struct btrfs_fs_info
*fs_info
= current_fs_info
;
232 ret
= list_subvolums(fs_info
);
234 error("failed to list subvolume: %d", ret
);