1 // SPDX-License-Identifier: GPL-2.0+
3 * BTRFS filesystem implementation for U-Boot
5 * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
11 u64
btrfs_lookup_inode_ref(struct btrfs_root
*root
, u64 inr
,
12 struct btrfs_inode_ref
*refp
, char *name
)
14 struct btrfs_path path
;
15 struct btrfs_key
*key
;
16 struct btrfs_inode_ref
*ref
;
19 key
= btrfs_search_tree_key_type(root
, inr
, BTRFS_INODE_REF_KEY
,
25 ref
= btrfs_path_item_ptr(&path
, struct btrfs_inode_ref
);
26 btrfs_inode_ref_to_cpu(ref
);
32 if (ref
->name_len
> BTRFS_NAME_MAX
) {
33 printf("%s: inode name too long: %u\n", __func__
,
38 memcpy(name
, ref
+ 1, ref
->name_len
);
43 btrfs_free_path(&path
);
47 int btrfs_lookup_inode(const struct btrfs_root
*root
,
48 struct btrfs_key
*location
,
49 struct btrfs_inode_item
*item
,
50 struct btrfs_root
*new_root
)
52 struct btrfs_root tmp_root
= *root
;
53 struct btrfs_path path
;
56 if (location
->type
== BTRFS_ROOT_ITEM_KEY
) {
57 if (btrfs_find_root(location
->objectid
, &tmp_root
, NULL
))
60 location
->objectid
= tmp_root
.root_dirid
;
61 location
->type
= BTRFS_INODE_ITEM_KEY
;
65 if (btrfs_search_tree(&tmp_root
, location
, &path
))
68 if (btrfs_comp_keys(location
, btrfs_path_leaf_key(&path
)))
72 *item
= *btrfs_path_item_ptr(&path
, struct btrfs_inode_item
);
73 btrfs_inode_item_to_cpu(item
);
82 btrfs_free_path(&path
);
86 int btrfs_readlink(const struct btrfs_root
*root
, u64 inr
, char *target
)
88 struct btrfs_path path
;
90 struct btrfs_file_extent_item
*extent
;
95 key
.type
= BTRFS_EXTENT_DATA_KEY
;
98 if (btrfs_search_tree(root
, &key
, &path
))
101 if (btrfs_comp_keys(&key
, btrfs_path_leaf_key(&path
)))
104 extent
= btrfs_path_item_ptr(&path
, struct btrfs_file_extent_item
);
105 if (extent
->type
!= BTRFS_FILE_EXTENT_INLINE
) {
106 printf("%s: Extent for symlink %llu not of INLINE type\n",
111 btrfs_file_extent_item_to_cpu_inl(extent
);
113 if (extent
->compression
!= BTRFS_COMPRESS_NONE
) {
114 printf("%s: Symlink %llu extent data compressed!\n", __func__
,
117 } else if (extent
->encryption
!= 0) {
118 printf("%s: Symlink %llu extent data encrypted!\n", __func__
,
121 } else if (extent
->ram_bytes
>= btrfs_info
.sb
.sectorsize
) {
122 printf("%s: Symlink %llu extent data too long (%llu)!\n",
123 __func__
, inr
, extent
->ram_bytes
);
127 data_ptr
= (const char *) extent
128 + offsetof(struct btrfs_file_extent_item
, disk_bytenr
);
130 memcpy(target
, data_ptr
, extent
->ram_bytes
);
131 target
[extent
->ram_bytes
] = '\0';
134 btrfs_free_path(&path
);
138 /* inr must be a directory (for regular files with multiple hard links this
139 function returns only one of the parents of the file) */
140 static u64
get_parent_inode(struct btrfs_root
*root
, u64 inr
,
141 struct btrfs_inode_item
*inode_item
)
143 struct btrfs_key key
;
146 if (inr
== BTRFS_FIRST_FREE_OBJECTID
) {
147 if (root
->objectid
!= btrfs_info
.fs_root
.objectid
) {
149 struct btrfs_root_ref ref
;
151 parent
= btrfs_lookup_root_ref(root
->objectid
, &ref
,
156 if (btrfs_find_root(parent
, root
, NULL
))
164 key
.type
= BTRFS_INODE_ITEM_KEY
;
167 if (btrfs_lookup_inode(root
, &key
, inode_item
, NULL
))
174 res
= btrfs_lookup_inode_ref(root
, inr
, NULL
, NULL
);
180 key
.type
= BTRFS_INODE_ITEM_KEY
;
183 if (btrfs_lookup_inode(root
, &key
, inode_item
, NULL
))
190 static inline int next_length(const char *path
)
193 while (*path
!= '\0' && *path
!= '/' && res
<= BTRFS_NAME_LEN
)
198 static inline const char *skip_current_directories(const char *cur
)
203 else if (cur
[0] == '.' && cur
[1] == '/')
212 u64
btrfs_lookup_path(struct btrfs_root
*root
, u64 inr
, const char *path
,
213 u8
*type_p
, struct btrfs_inode_item
*inode_item_p
,
216 struct btrfs_dir_item item
;
217 struct btrfs_inode_item inode_item
;
218 u8 type
= BTRFS_FT_DIR
;
219 int len
, have_inode
= 0;
220 const char *cur
= path
;
224 inr
= root
->root_dirid
;
228 cur
= skip_current_directories(cur
);
230 len
= next_length(cur
);
231 if (len
> BTRFS_NAME_LEN
) {
232 printf("%s: Name too long at \"%.*s\"\n", __func__
,
233 BTRFS_NAME_LEN
, cur
);
237 if (len
== 1 && cur
[0] == '.')
240 if (len
== 2 && cur
[0] == '.' && cur
[1] == '.') {
242 inr
= get_parent_inode(root
, inr
, &inode_item
);
253 if (btrfs_lookup_dir_item(root
, inr
, cur
, len
, &item
))
258 if (btrfs_lookup_inode(root
, &item
.location
, &inode_item
, root
))
261 if (item
.type
== BTRFS_FT_SYMLINK
&& symlink_limit
>= 0) {
264 if (!symlink_limit
) {
265 printf("%s: Too much symlinks!\n", __func__
);
269 target
= malloc(min(inode_item
.size
+ 1,
270 (u64
) btrfs_info
.sb
.sectorsize
));
274 if (btrfs_readlink(root
, item
.location
.objectid
,
280 inr
= btrfs_lookup_path(root
, inr
, target
, &type
,
281 &inode_item
, symlink_limit
- 1);
287 } else if (item
.type
!= BTRFS_FT_DIR
&& cur
[len
]) {
288 printf("%s: \"%.*s\" not a directory\n", __func__
,
289 (int) (cur
- path
+ len
), path
);
292 inr
= item
.location
.objectid
;
303 struct btrfs_key key
;
306 key
.type
= BTRFS_INODE_ITEM_KEY
;
309 if (btrfs_lookup_inode(root
, &key
, &inode_item
, NULL
))
313 *inode_item_p
= inode_item
;
319 u64
btrfs_file_read(const struct btrfs_root
*root
, u64 inr
, u64 offset
,
322 struct btrfs_path path
;
323 struct btrfs_key key
;
324 struct btrfs_file_extent_item
*extent
;
326 u64 rd
, rd_all
= -1ULL;
329 key
.type
= BTRFS_EXTENT_DATA_KEY
;
332 if (btrfs_search_tree(root
, &key
, &path
))
335 if (btrfs_comp_keys(&key
, btrfs_path_leaf_key(&path
)) < 0) {
336 if (btrfs_prev_slot(&path
))
339 if (btrfs_comp_keys_type(&key
, btrfs_path_leaf_key(&path
)))
346 if (btrfs_comp_keys_type(&key
, btrfs_path_leaf_key(&path
)))
349 extent
= btrfs_path_item_ptr(&path
,
350 struct btrfs_file_extent_item
);
352 if (extent
->type
== BTRFS_FILE_EXTENT_INLINE
) {
353 btrfs_file_extent_item_to_cpu_inl(extent
);
354 rd
= btrfs_read_extent_inline(&path
, extent
, offset
,
357 btrfs_file_extent_item_to_cpu(extent
);
358 rd
= btrfs_read_extent_reg(&path
, extent
, offset
, size
,
363 printf("%s: Error reading extent\n", __func__
);
375 } while (!(res
= btrfs_next_slot(&path
)));
381 btrfs_free_path(&path
);