2 * BTRFS filesystem implementation for U-Boot
4 * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
6 * SPDX-License-Identifier: GPL-2.0+
12 u64 btrfs_lookup_inode_ref(struct btrfs_root *root, u64 inr,
13 struct btrfs_inode_ref *refp, char *name)
15 struct btrfs_path path;
16 struct btrfs_key *key;
17 struct btrfs_inode_ref *ref;
20 key = btrfs_search_tree_key_type(root, inr, BTRFS_INODE_REF_KEY,
26 ref = btrfs_path_item_ptr(&path, struct btrfs_inode_ref);
27 btrfs_inode_ref_to_cpu(ref);
33 if (ref->name_len > BTRFS_NAME_MAX) {
34 printf("%s: inode name too long: %u\n", __func__,
39 memcpy(name, ref + 1, ref->name_len);
44 btrfs_free_path(&path);
48 int btrfs_lookup_inode(const struct btrfs_root *root,
49 struct btrfs_key *location,
50 struct btrfs_inode_item *item,
51 struct btrfs_root *new_root)
53 struct btrfs_root tmp_root = *root;
54 struct btrfs_path path;
57 if (location->type == BTRFS_ROOT_ITEM_KEY) {
58 if (btrfs_find_root(location->objectid, &tmp_root, NULL))
61 location->objectid = tmp_root.root_dirid;
62 location->type = BTRFS_INODE_ITEM_KEY;
66 if (btrfs_search_tree(&tmp_root, location, &path))
69 if (btrfs_comp_keys(location, btrfs_path_leaf_key(&path)))
73 *item = *btrfs_path_item_ptr(&path, struct btrfs_inode_item);
74 btrfs_inode_item_to_cpu(item);
83 btrfs_free_path(&path);
87 int btrfs_readlink(const struct btrfs_root *root, u64 inr, char *target)
89 struct btrfs_path path;
91 struct btrfs_file_extent_item *extent;
96 key.type = BTRFS_EXTENT_DATA_KEY;
99 if (btrfs_search_tree(root, &key, &path))
102 if (btrfs_comp_keys(&key, btrfs_path_leaf_key(&path)))
105 extent = btrfs_path_item_ptr(&path, struct btrfs_file_extent_item);
106 if (extent->type != BTRFS_FILE_EXTENT_INLINE) {
107 printf("%s: Extent for symlink %llu not of INLINE type\n",
112 btrfs_file_extent_item_to_cpu_inl(extent);
114 if (extent->compression != BTRFS_COMPRESS_NONE) {
115 printf("%s: Symlink %llu extent data compressed!\n", __func__,
118 } else if (extent->encryption != 0) {
119 printf("%s: Symlink %llu extent data encrypted!\n", __func__,
122 } else if (extent->ram_bytes >= btrfs_info.sb.sectorsize) {
123 printf("%s: Symlink %llu extent data too long (%llu)!\n",
124 __func__, inr, extent->ram_bytes);
128 data_ptr = (const char *) extent
129 + offsetof(struct btrfs_file_extent_item, disk_bytenr);
131 memcpy(target, data_ptr, extent->ram_bytes);
132 target[extent->ram_bytes] = '\0';
135 btrfs_free_path(&path);
139 /* inr must be a directory (for regular files with multiple hard links this
140 function returns only one of the parents of the file) */
141 static u64 get_parent_inode(struct btrfs_root *root, u64 inr,
142 struct btrfs_inode_item *inode_item)
144 struct btrfs_key key;
147 if (inr == BTRFS_FIRST_FREE_OBJECTID) {
148 if (root->objectid != btrfs_info.fs_root.objectid) {
150 struct btrfs_root_ref ref;
152 parent = btrfs_lookup_root_ref(root->objectid, &ref,
157 if (btrfs_find_root(parent, root, NULL))
165 key.type = BTRFS_INODE_ITEM_KEY;
168 if (btrfs_lookup_inode(root, &key, inode_item, NULL))
175 res = btrfs_lookup_inode_ref(root, inr, NULL, NULL);
181 key.type = BTRFS_INODE_ITEM_KEY;
184 if (btrfs_lookup_inode(root, &key, inode_item, NULL))
191 static inline int next_length(const char *path)
194 while (*path != '\0' && *path != '/' && res <= BTRFS_NAME_LEN)
199 static inline const char *skip_current_directories(const char *cur)
204 else if (cur[0] == '.' && cur[1] == '/')
213 u64 btrfs_lookup_path(struct btrfs_root *root, u64 inr, const char *path,
214 u8 *type_p, struct btrfs_inode_item *inode_item_p,
217 struct btrfs_dir_item item;
218 struct btrfs_inode_item inode_item;
219 u8 type = BTRFS_FT_DIR;
220 int len, have_inode = 0;
221 const char *cur = path;
225 inr = root->root_dirid;
229 cur = skip_current_directories(cur);
231 len = next_length(cur);
232 if (len > BTRFS_NAME_LEN) {
233 printf("%s: Name too long at \"%.*s\"\n", __func__,
234 BTRFS_NAME_LEN, cur);
238 if (len == 1 && cur[0] == '.')
241 if (len == 2 && cur[0] == '.' && cur[1] == '.') {
243 inr = get_parent_inode(root, inr, &inode_item);
254 if (btrfs_lookup_dir_item(root, inr, cur, len, &item))
259 if (btrfs_lookup_inode(root, &item.location, &inode_item, root))
262 if (item.type == BTRFS_FT_SYMLINK && symlink_limit >= 0) {
265 if (!symlink_limit) {
266 printf("%s: Too much symlinks!\n", __func__);
270 target = malloc(min(inode_item.size + 1,
271 (u64) btrfs_info.sb.sectorsize));
275 if (btrfs_readlink(root, item.location.objectid,
281 inr = btrfs_lookup_path(root, inr, target, &type,
282 &inode_item, symlink_limit - 1);
288 } else if (item.type != BTRFS_FT_DIR && cur[len]) {
289 printf("%s: \"%.*s\" not a directory\n", __func__,
290 (int) (cur - path + len), path);
293 inr = item.location.objectid;
304 struct btrfs_key key;
307 key.type = BTRFS_INODE_ITEM_KEY;
310 if (btrfs_lookup_inode(root, &key, &inode_item, NULL))
314 *inode_item_p = inode_item;
320 u64 btrfs_file_read(const struct btrfs_root *root, u64 inr, u64 offset,
323 struct btrfs_path path;
324 struct btrfs_key key;
325 struct btrfs_file_extent_item *extent;
327 u64 rd, rd_all = -1ULL;
330 key.type = BTRFS_EXTENT_DATA_KEY;
333 if (btrfs_search_tree(root, &key, &path))
336 if (btrfs_comp_keys(&key, btrfs_path_leaf_key(&path)) < 0) {
337 if (btrfs_prev_slot(&path))
340 if (btrfs_comp_keys_type(&key, btrfs_path_leaf_key(&path)))
347 if (btrfs_comp_keys_type(&key, btrfs_path_leaf_key(&path)))
350 extent = btrfs_path_item_ptr(&path,
351 struct btrfs_file_extent_item);
353 if (extent->type == BTRFS_FILE_EXTENT_INLINE) {
354 btrfs_file_extent_item_to_cpu_inl(extent);
355 rd = btrfs_read_extent_inline(&path, extent, offset,
358 btrfs_file_extent_item_to_cpu(extent);
359 rd = btrfs_read_extent_reg(&path, extent, offset, size,
364 printf("%s: Error reading extent\n", __func__);
376 } while (!(res = btrfs_next_slot(&path)));
382 btrfs_free_path(&path);