121a14facSMarek Behún /* 221a14facSMarek Behún * BTRFS filesystem implementation for U-Boot 321a14facSMarek Behún * 421a14facSMarek Behún * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz 521a14facSMarek Behún * 621a14facSMarek Behún * SPDX-License-Identifier: GPL-2.0+ 721a14facSMarek Behún */ 821a14facSMarek Behún 921a14facSMarek Behún #include "btrfs.h" 1021a14facSMarek Behún #include <malloc.h> 1121a14facSMarek Behún 1221a14facSMarek Behún u64 btrfs_lookup_inode_ref(struct btrfs_root *root, u64 inr, 1321a14facSMarek Behún struct btrfs_inode_ref *refp, char *name) 1421a14facSMarek Behún { 1521a14facSMarek Behún struct btrfs_path path; 1621a14facSMarek Behún struct btrfs_key *key; 1721a14facSMarek Behún struct btrfs_inode_ref *ref; 1821a14facSMarek Behún u64 res = -1ULL; 1921a14facSMarek Behún 2021a14facSMarek Behún key = btrfs_search_tree_key_type(root, inr, BTRFS_INODE_REF_KEY, 2121a14facSMarek Behún &path); 2221a14facSMarek Behún 2321a14facSMarek Behún if (!key) 2421a14facSMarek Behún return -1ULL; 2521a14facSMarek Behún 2621a14facSMarek Behún ref = btrfs_path_item_ptr(&path, struct btrfs_inode_ref); 2721a14facSMarek Behún btrfs_inode_ref_to_cpu(ref); 2821a14facSMarek Behún 2921a14facSMarek Behún if (refp) 3021a14facSMarek Behún *refp = *ref; 3121a14facSMarek Behún 3221a14facSMarek Behún if (name) { 3321a14facSMarek Behún if (ref->name_len > BTRFS_NAME_MAX) { 3421a14facSMarek Behún printf("%s: inode name too long: %u\n", __func__, 3521a14facSMarek Behún ref->name_len); 3621a14facSMarek Behún goto out; 3721a14facSMarek Behún } 3821a14facSMarek Behún 3921a14facSMarek Behún memcpy(name, ref + 1, ref->name_len); 4021a14facSMarek Behún } 4121a14facSMarek Behún 4221a14facSMarek Behún res = key->offset; 4321a14facSMarek Behún out: 4421a14facSMarek Behún btrfs_free_path(&path); 4521a14facSMarek Behún return res; 4621a14facSMarek Behún } 4721a14facSMarek Behún 4821a14facSMarek Behún int btrfs_lookup_inode(const struct btrfs_root *root, 4921a14facSMarek Behún struct btrfs_key *location, 5021a14facSMarek Behún struct btrfs_inode_item *item, 5121a14facSMarek Behún struct btrfs_root *new_root) 5221a14facSMarek Behún { 5321a14facSMarek Behún struct btrfs_root tmp_root = *root; 5421a14facSMarek Behún struct btrfs_path path; 5521a14facSMarek Behún int res = -1; 5621a14facSMarek Behún 5721a14facSMarek Behún if (location->type == BTRFS_ROOT_ITEM_KEY) { 5821a14facSMarek Behún if (btrfs_find_root(location->objectid, &tmp_root, NULL)) 5921a14facSMarek Behún return -1; 6021a14facSMarek Behún 6121a14facSMarek Behún location->objectid = tmp_root.root_dirid; 6221a14facSMarek Behún location->type = BTRFS_INODE_ITEM_KEY; 6321a14facSMarek Behún location->offset = 0; 6421a14facSMarek Behún } 6521a14facSMarek Behún 6621a14facSMarek Behún if (btrfs_search_tree(&tmp_root, location, &path)) 6721a14facSMarek Behún return res; 6821a14facSMarek Behún 6921a14facSMarek Behún if (btrfs_comp_keys(location, btrfs_path_leaf_key(&path))) 7021a14facSMarek Behún goto out; 7121a14facSMarek Behún 7221a14facSMarek Behún if (item) { 7321a14facSMarek Behún *item = *btrfs_path_item_ptr(&path, struct btrfs_inode_item); 7421a14facSMarek Behún btrfs_inode_item_to_cpu(item); 7521a14facSMarek Behún } 7621a14facSMarek Behún 7721a14facSMarek Behún if (new_root) 7821a14facSMarek Behún *new_root = tmp_root; 7921a14facSMarek Behún 8021a14facSMarek Behún res = 0; 8121a14facSMarek Behún 8221a14facSMarek Behún out: 8321a14facSMarek Behún btrfs_free_path(&path); 8421a14facSMarek Behún return res; 8521a14facSMarek Behún } 8621a14facSMarek Behún 8721a14facSMarek Behún int btrfs_readlink(const struct btrfs_root *root, u64 inr, char *target) 8821a14facSMarek Behún { 8921a14facSMarek Behún struct btrfs_path path; 9021a14facSMarek Behún struct btrfs_key key; 9121a14facSMarek Behún struct btrfs_file_extent_item *extent; 9221a14facSMarek Behún const char *data_ptr; 9321a14facSMarek Behún int res = -1; 9421a14facSMarek Behún 9521a14facSMarek Behún key.objectid = inr; 9621a14facSMarek Behún key.type = BTRFS_EXTENT_DATA_KEY; 9721a14facSMarek Behún key.offset = 0; 9821a14facSMarek Behún 9921a14facSMarek Behún if (btrfs_search_tree(root, &key, &path)) 10021a14facSMarek Behún return -1; 10121a14facSMarek Behún 10221a14facSMarek Behún if (btrfs_comp_keys(&key, btrfs_path_leaf_key(&path))) 10321a14facSMarek Behún goto out; 10421a14facSMarek Behún 10521a14facSMarek Behún extent = btrfs_path_item_ptr(&path, struct btrfs_file_extent_item); 10621a14facSMarek Behún if (extent->type != BTRFS_FILE_EXTENT_INLINE) { 10721a14facSMarek Behún printf("%s: Extent for symlink %llu not of INLINE type\n", 10821a14facSMarek Behún __func__, inr); 10921a14facSMarek Behún goto out; 11021a14facSMarek Behún } 11121a14facSMarek Behún 11221a14facSMarek Behún btrfs_file_extent_item_to_cpu_inl(extent); 11321a14facSMarek Behún 11421a14facSMarek Behún if (extent->compression != BTRFS_COMPRESS_NONE) { 11521a14facSMarek Behún printf("%s: Symlink %llu extent data compressed!\n", __func__, 11621a14facSMarek Behún inr); 11721a14facSMarek Behún goto out; 11821a14facSMarek Behún } else if (extent->encryption != 0) { 11921a14facSMarek Behún printf("%s: Symlink %llu extent data encrypted!\n", __func__, 12021a14facSMarek Behún inr); 12121a14facSMarek Behún goto out; 12221a14facSMarek Behún } else if (extent->ram_bytes >= btrfs_info.sb.sectorsize) { 12321a14facSMarek Behún printf("%s: Symlink %llu extent data too long (%llu)!\n", 12421a14facSMarek Behún __func__, inr, extent->ram_bytes); 12521a14facSMarek Behún goto out; 12621a14facSMarek Behún } 12721a14facSMarek Behún 12821a14facSMarek Behún data_ptr = (const char *) extent 12921a14facSMarek Behún + offsetof(struct btrfs_file_extent_item, disk_bytenr); 13021a14facSMarek Behún 13121a14facSMarek Behún memcpy(target, data_ptr, extent->ram_bytes); 13221a14facSMarek Behún target[extent->ram_bytes] = '\0'; 13321a14facSMarek Behún res = 0; 13421a14facSMarek Behún out: 13521a14facSMarek Behún btrfs_free_path(&path); 13621a14facSMarek Behún return res; 13721a14facSMarek Behún } 13821a14facSMarek Behún 13921a14facSMarek Behún /* inr must be a directory (for regular files with multiple hard links this 14021a14facSMarek Behún function returns only one of the parents of the file) */ 14121a14facSMarek Behún static u64 get_parent_inode(struct btrfs_root *root, u64 inr, 14221a14facSMarek Behún struct btrfs_inode_item *inode_item) 14321a14facSMarek Behún { 14421a14facSMarek Behún struct btrfs_key key; 14521a14facSMarek Behún u64 res; 14621a14facSMarek Behún 14721a14facSMarek Behún if (inr == BTRFS_FIRST_FREE_OBJECTID) { 14821a14facSMarek Behún if (root->objectid != btrfs_info.fs_root.objectid) { 14921a14facSMarek Behún u64 parent; 15021a14facSMarek Behún struct btrfs_root_ref ref; 15121a14facSMarek Behún 15221a14facSMarek Behún parent = btrfs_lookup_root_ref(root->objectid, &ref, 15321a14facSMarek Behún NULL); 15421a14facSMarek Behún if (parent == -1ULL) 15521a14facSMarek Behún return -1ULL; 15621a14facSMarek Behún 15721a14facSMarek Behún if (btrfs_find_root(parent, root, NULL)) 15821a14facSMarek Behún return -1ULL; 15921a14facSMarek Behún 16021a14facSMarek Behún inr = ref.dirid; 16121a14facSMarek Behún } 16221a14facSMarek Behún 16321a14facSMarek Behún if (inode_item) { 16421a14facSMarek Behún key.objectid = inr; 16521a14facSMarek Behún key.type = BTRFS_INODE_ITEM_KEY; 16621a14facSMarek Behún key.offset = 0; 16721a14facSMarek Behún 16821a14facSMarek Behún if (btrfs_lookup_inode(root, &key, inode_item, NULL)) 16921a14facSMarek Behún return -1ULL; 17021a14facSMarek Behún } 17121a14facSMarek Behún 17221a14facSMarek Behún return inr; 17321a14facSMarek Behún } 17421a14facSMarek Behún 17521a14facSMarek Behún res = btrfs_lookup_inode_ref(root, inr, NULL, NULL); 17621a14facSMarek Behún if (res == -1ULL) 17721a14facSMarek Behún return -1ULL; 17821a14facSMarek Behún 17921a14facSMarek Behún if (inode_item) { 18021a14facSMarek Behún key.objectid = res; 18121a14facSMarek Behún key.type = BTRFS_INODE_ITEM_KEY; 18221a14facSMarek Behún key.offset = 0; 18321a14facSMarek Behún 18421a14facSMarek Behún if (btrfs_lookup_inode(root, &key, inode_item, NULL)) 18521a14facSMarek Behún return -1ULL; 18621a14facSMarek Behún } 18721a14facSMarek Behún 18821a14facSMarek Behún return res; 18921a14facSMarek Behún } 19021a14facSMarek Behún 19121a14facSMarek Behún static inline int next_length(const char *path) 19221a14facSMarek Behún { 19321a14facSMarek Behún int res = 0; 19421a14facSMarek Behún while (*path != '\0' && *path != '/' && res <= BTRFS_NAME_LEN) 19521a14facSMarek Behún ++res, ++path; 19621a14facSMarek Behún return res; 19721a14facSMarek Behún } 19821a14facSMarek Behún 19921a14facSMarek Behún static inline const char *skip_current_directories(const char *cur) 20021a14facSMarek Behún { 20121a14facSMarek Behún while (1) { 20221a14facSMarek Behún if (cur[0] == '/') 20321a14facSMarek Behún ++cur; 20421a14facSMarek Behún else if (cur[0] == '.' && cur[1] == '/') 20521a14facSMarek Behún cur += 2; 20621a14facSMarek Behún else 20721a14facSMarek Behún break; 20821a14facSMarek Behún } 20921a14facSMarek Behún 21021a14facSMarek Behún return cur; 21121a14facSMarek Behún } 21221a14facSMarek Behún 21321a14facSMarek Behún /* inode.c, musi vratit aj root stromu kde sa inoda najde */ 21421a14facSMarek Behún u64 btrfs_lookup_path(struct btrfs_root *root, u64 inr, const char *path, 21521a14facSMarek Behún u8 *type_p, struct btrfs_inode_item *inode_item_p, 21621a14facSMarek Behún int symlink_limit) 21721a14facSMarek Behún { 21821a14facSMarek Behún struct btrfs_dir_item item; 21921a14facSMarek Behún struct btrfs_inode_item inode_item; 22021a14facSMarek Behún u8 type = BTRFS_FT_DIR; 22121a14facSMarek Behún int len, have_inode = 0; 22221a14facSMarek Behún const char *cur = path; 22321a14facSMarek Behún 22421a14facSMarek Behún if (*cur == '/') { 22521a14facSMarek Behún ++cur; 22621a14facSMarek Behún inr = root->root_dirid; 22721a14facSMarek Behún } 22821a14facSMarek Behún 22921a14facSMarek Behún do { 23021a14facSMarek Behún cur = skip_current_directories(cur); 23121a14facSMarek Behún 23221a14facSMarek Behún len = next_length(cur); 23321a14facSMarek Behún if (len > BTRFS_NAME_LEN) { 23421a14facSMarek Behún printf("%s: Name too long at \"%.*s\"\n", __func__, 23521a14facSMarek Behún BTRFS_NAME_LEN, cur); 23621a14facSMarek Behún return -1ULL; 23721a14facSMarek Behún } 23821a14facSMarek Behún 23921a14facSMarek Behún if (len == 1 && cur[0] == '.') 24021a14facSMarek Behún break; 24121a14facSMarek Behún 24221a14facSMarek Behún if (len == 2 && cur[0] == '.' && cur[1] == '.') { 24321a14facSMarek Behún cur += 2; 24421a14facSMarek Behún inr = get_parent_inode(root, inr, &inode_item); 24521a14facSMarek Behún if (inr == -1ULL) 24621a14facSMarek Behún return -1ULL; 24721a14facSMarek Behún 24821a14facSMarek Behún type = BTRFS_FT_DIR; 24921a14facSMarek Behún continue; 25021a14facSMarek Behún } 25121a14facSMarek Behún 25221a14facSMarek Behún if (!*cur) 25321a14facSMarek Behún break; 25421a14facSMarek Behún 25521a14facSMarek Behún if (btrfs_lookup_dir_item(root, inr, cur, len, &item)) 25621a14facSMarek Behún return -1ULL; 25721a14facSMarek Behún 25821a14facSMarek Behún type = item.type; 25921a14facSMarek Behún have_inode = 1; 26021a14facSMarek Behún if (btrfs_lookup_inode(root, &item.location, &inode_item, root)) 26121a14facSMarek Behún return -1ULL; 26221a14facSMarek Behún 26321a14facSMarek Behún if (item.type == BTRFS_FT_SYMLINK && symlink_limit >= 0) { 26421a14facSMarek Behún char *target; 26521a14facSMarek Behún 26621a14facSMarek Behún if (!symlink_limit) { 26721a14facSMarek Behún printf("%s: Too much symlinks!\n", __func__); 26821a14facSMarek Behún return -1ULL; 26921a14facSMarek Behún } 27021a14facSMarek Behún 27121a14facSMarek Behún target = malloc(min(inode_item.size + 1, 27221a14facSMarek Behún (u64) btrfs_info.sb.sectorsize)); 27321a14facSMarek Behún if (!target) 27421a14facSMarek Behún return -1ULL; 27521a14facSMarek Behún 27621a14facSMarek Behún if (btrfs_readlink(root, item.location.objectid, 27721a14facSMarek Behún target)) { 27821a14facSMarek Behún free(target); 27921a14facSMarek Behún return -1ULL; 28021a14facSMarek Behún } 28121a14facSMarek Behún 28221a14facSMarek Behún inr = btrfs_lookup_path(root, inr, target, &type, 28321a14facSMarek Behún &inode_item, symlink_limit - 1); 28421a14facSMarek Behún 28521a14facSMarek Behún free(target); 28621a14facSMarek Behún 28721a14facSMarek Behún if (inr == -1ULL) 28821a14facSMarek Behún return -1ULL; 28921a14facSMarek Behún } else if (item.type != BTRFS_FT_DIR && cur[len]) { 29021a14facSMarek Behún printf("%s: \"%.*s\" not a directory\n", __func__, 29121a14facSMarek Behún (int) (cur - path + len), path); 29221a14facSMarek Behún return -1ULL; 29321a14facSMarek Behún } else { 29421a14facSMarek Behún inr = item.location.objectid; 29521a14facSMarek Behún } 29621a14facSMarek Behún 29721a14facSMarek Behún cur += len; 29821a14facSMarek Behún } while (*cur); 29921a14facSMarek Behún 30021a14facSMarek Behún if (type_p) 30121a14facSMarek Behún *type_p = type; 30221a14facSMarek Behún 30321a14facSMarek Behún if (inode_item_p) { 30421a14facSMarek Behún if (!have_inode) { 30521a14facSMarek Behún struct btrfs_key key; 30621a14facSMarek Behún 30721a14facSMarek Behún key.objectid = inr; 30821a14facSMarek Behún key.type = BTRFS_INODE_ITEM_KEY; 30921a14facSMarek Behún key.offset = 0; 31021a14facSMarek Behún 31121a14facSMarek Behún if (btrfs_lookup_inode(root, &key, &inode_item, NULL)) 31221a14facSMarek Behún return -1ULL; 31321a14facSMarek Behún } 31421a14facSMarek Behún 31521a14facSMarek Behún *inode_item_p = inode_item; 31621a14facSMarek Behún } 31721a14facSMarek Behún 31821a14facSMarek Behún return inr; 31921a14facSMarek Behún } 32021a14facSMarek Behún 32121a14facSMarek Behún u64 btrfs_file_read(const struct btrfs_root *root, u64 inr, u64 offset, 32221a14facSMarek Behún u64 size, char *buf) 32321a14facSMarek Behún { 32421a14facSMarek Behún struct btrfs_path path; 32521a14facSMarek Behún struct btrfs_key key; 32621a14facSMarek Behún struct btrfs_file_extent_item *extent; 327*ecab881cSMarek Behún int res = 0; 32821a14facSMarek Behún u64 rd, rd_all = -1ULL; 32921a14facSMarek Behún 33021a14facSMarek Behún key.objectid = inr; 33121a14facSMarek Behún key.type = BTRFS_EXTENT_DATA_KEY; 33221a14facSMarek Behún key.offset = offset; 33321a14facSMarek Behún 33421a14facSMarek Behún if (btrfs_search_tree(root, &key, &path)) 33521a14facSMarek Behún return -1ULL; 33621a14facSMarek Behún 33721a14facSMarek Behún if (btrfs_comp_keys(&key, btrfs_path_leaf_key(&path)) < 0) { 33821a14facSMarek Behún if (btrfs_prev_slot(&path)) 33921a14facSMarek Behún goto out; 34021a14facSMarek Behún 34121a14facSMarek Behún if (btrfs_comp_keys_type(&key, btrfs_path_leaf_key(&path))) 34221a14facSMarek Behún goto out; 34321a14facSMarek Behún } 34421a14facSMarek Behún 34521a14facSMarek Behún rd_all = 0; 34621a14facSMarek Behún 34721a14facSMarek Behún do { 34821a14facSMarek Behún if (btrfs_comp_keys_type(&key, btrfs_path_leaf_key(&path))) 34921a14facSMarek Behún break; 35021a14facSMarek Behún 35121a14facSMarek Behún extent = btrfs_path_item_ptr(&path, 35221a14facSMarek Behún struct btrfs_file_extent_item); 35321a14facSMarek Behún 35421a14facSMarek Behún if (extent->type == BTRFS_FILE_EXTENT_INLINE) { 35521a14facSMarek Behún btrfs_file_extent_item_to_cpu_inl(extent); 35621a14facSMarek Behún rd = btrfs_read_extent_inline(&path, extent, offset, 35721a14facSMarek Behún size, buf); 35821a14facSMarek Behún } else { 35921a14facSMarek Behún btrfs_file_extent_item_to_cpu(extent); 36021a14facSMarek Behún rd = btrfs_read_extent_reg(&path, extent, offset, size, 36121a14facSMarek Behún buf); 36221a14facSMarek Behún } 36321a14facSMarek Behún 36421a14facSMarek Behún if (rd == -1ULL) { 36521a14facSMarek Behún printf("%s: Error reading extent\n", __func__); 36621a14facSMarek Behún rd_all = -1; 36721a14facSMarek Behún goto out; 36821a14facSMarek Behún } 36921a14facSMarek Behún 37021a14facSMarek Behún offset = 0; 37121a14facSMarek Behún buf += rd; 37221a14facSMarek Behún rd_all += rd; 37321a14facSMarek Behún size -= rd; 37421a14facSMarek Behún 37521a14facSMarek Behún if (!size) 37621a14facSMarek Behún break; 37721a14facSMarek Behún } while (!(res = btrfs_next_slot(&path))); 37821a14facSMarek Behún 37921a14facSMarek Behún if (res) 38021a14facSMarek Behún return -1ULL; 38121a14facSMarek Behún 38221a14facSMarek Behún out: 38321a14facSMarek Behún btrfs_free_path(&path); 38421a14facSMarek Behún return rd_all; 38521a14facSMarek Behún } 386