1*21a14facSMarek Behún /* 2*21a14facSMarek Behún * BTRFS filesystem implementation for U-Boot 3*21a14facSMarek Behún * 4*21a14facSMarek Behún * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz 5*21a14facSMarek Behún * 6*21a14facSMarek Behún * SPDX-License-Identifier: GPL-2.0+ 7*21a14facSMarek Behún */ 8*21a14facSMarek Behún 9*21a14facSMarek Behún #include "btrfs.h" 10*21a14facSMarek Behún #include <malloc.h> 11*21a14facSMarek Behún 12*21a14facSMarek Behún u64 btrfs_lookup_inode_ref(struct btrfs_root *root, u64 inr, 13*21a14facSMarek Behún struct btrfs_inode_ref *refp, char *name) 14*21a14facSMarek Behún { 15*21a14facSMarek Behún struct btrfs_path path; 16*21a14facSMarek Behún struct btrfs_key *key; 17*21a14facSMarek Behún struct btrfs_inode_ref *ref; 18*21a14facSMarek Behún u64 res = -1ULL; 19*21a14facSMarek Behún 20*21a14facSMarek Behún key = btrfs_search_tree_key_type(root, inr, BTRFS_INODE_REF_KEY, 21*21a14facSMarek Behún &path); 22*21a14facSMarek Behún 23*21a14facSMarek Behún if (!key) 24*21a14facSMarek Behún return -1ULL; 25*21a14facSMarek Behún 26*21a14facSMarek Behún ref = btrfs_path_item_ptr(&path, struct btrfs_inode_ref); 27*21a14facSMarek Behún btrfs_inode_ref_to_cpu(ref); 28*21a14facSMarek Behún 29*21a14facSMarek Behún if (refp) 30*21a14facSMarek Behún *refp = *ref; 31*21a14facSMarek Behún 32*21a14facSMarek Behún if (name) { 33*21a14facSMarek Behún if (ref->name_len > BTRFS_NAME_MAX) { 34*21a14facSMarek Behún printf("%s: inode name too long: %u\n", __func__, 35*21a14facSMarek Behún ref->name_len); 36*21a14facSMarek Behún goto out; 37*21a14facSMarek Behún } 38*21a14facSMarek Behún 39*21a14facSMarek Behún memcpy(name, ref + 1, ref->name_len); 40*21a14facSMarek Behún } 41*21a14facSMarek Behún 42*21a14facSMarek Behún res = key->offset; 43*21a14facSMarek Behún out: 44*21a14facSMarek Behún btrfs_free_path(&path); 45*21a14facSMarek Behún return res; 46*21a14facSMarek Behún } 47*21a14facSMarek Behún 48*21a14facSMarek Behún int btrfs_lookup_inode(const struct btrfs_root *root, 49*21a14facSMarek Behún struct btrfs_key *location, 50*21a14facSMarek Behún struct btrfs_inode_item *item, 51*21a14facSMarek Behún struct btrfs_root *new_root) 52*21a14facSMarek Behún { 53*21a14facSMarek Behún struct btrfs_root tmp_root = *root; 54*21a14facSMarek Behún struct btrfs_path path; 55*21a14facSMarek Behún int res = -1; 56*21a14facSMarek Behún 57*21a14facSMarek Behún if (location->type == BTRFS_ROOT_ITEM_KEY) { 58*21a14facSMarek Behún if (btrfs_find_root(location->objectid, &tmp_root, NULL)) 59*21a14facSMarek Behún return -1; 60*21a14facSMarek Behún 61*21a14facSMarek Behún location->objectid = tmp_root.root_dirid; 62*21a14facSMarek Behún location->type = BTRFS_INODE_ITEM_KEY; 63*21a14facSMarek Behún location->offset = 0; 64*21a14facSMarek Behún } 65*21a14facSMarek Behún 66*21a14facSMarek Behún if (btrfs_search_tree(&tmp_root, location, &path)) 67*21a14facSMarek Behún return res; 68*21a14facSMarek Behún 69*21a14facSMarek Behún if (btrfs_comp_keys(location, btrfs_path_leaf_key(&path))) 70*21a14facSMarek Behún goto out; 71*21a14facSMarek Behún 72*21a14facSMarek Behún if (item) { 73*21a14facSMarek Behún *item = *btrfs_path_item_ptr(&path, struct btrfs_inode_item); 74*21a14facSMarek Behún btrfs_inode_item_to_cpu(item); 75*21a14facSMarek Behún } 76*21a14facSMarek Behún 77*21a14facSMarek Behún if (new_root) 78*21a14facSMarek Behún *new_root = tmp_root; 79*21a14facSMarek Behún 80*21a14facSMarek Behún res = 0; 81*21a14facSMarek Behún 82*21a14facSMarek Behún out: 83*21a14facSMarek Behún btrfs_free_path(&path); 84*21a14facSMarek Behún return res; 85*21a14facSMarek Behún } 86*21a14facSMarek Behún 87*21a14facSMarek Behún int btrfs_readlink(const struct btrfs_root *root, u64 inr, char *target) 88*21a14facSMarek Behún { 89*21a14facSMarek Behún struct btrfs_path path; 90*21a14facSMarek Behún struct btrfs_key key; 91*21a14facSMarek Behún struct btrfs_file_extent_item *extent; 92*21a14facSMarek Behún const char *data_ptr; 93*21a14facSMarek Behún int res = -1; 94*21a14facSMarek Behún 95*21a14facSMarek Behún key.objectid = inr; 96*21a14facSMarek Behún key.type = BTRFS_EXTENT_DATA_KEY; 97*21a14facSMarek Behún key.offset = 0; 98*21a14facSMarek Behún 99*21a14facSMarek Behún if (btrfs_search_tree(root, &key, &path)) 100*21a14facSMarek Behún return -1; 101*21a14facSMarek Behún 102*21a14facSMarek Behún if (btrfs_comp_keys(&key, btrfs_path_leaf_key(&path))) 103*21a14facSMarek Behún goto out; 104*21a14facSMarek Behún 105*21a14facSMarek Behún extent = btrfs_path_item_ptr(&path, struct btrfs_file_extent_item); 106*21a14facSMarek Behún if (extent->type != BTRFS_FILE_EXTENT_INLINE) { 107*21a14facSMarek Behún printf("%s: Extent for symlink %llu not of INLINE type\n", 108*21a14facSMarek Behún __func__, inr); 109*21a14facSMarek Behún goto out; 110*21a14facSMarek Behún } 111*21a14facSMarek Behún 112*21a14facSMarek Behún btrfs_file_extent_item_to_cpu_inl(extent); 113*21a14facSMarek Behún 114*21a14facSMarek Behún if (extent->compression != BTRFS_COMPRESS_NONE) { 115*21a14facSMarek Behún printf("%s: Symlink %llu extent data compressed!\n", __func__, 116*21a14facSMarek Behún inr); 117*21a14facSMarek Behún goto out; 118*21a14facSMarek Behún } else if (extent->encryption != 0) { 119*21a14facSMarek Behún printf("%s: Symlink %llu extent data encrypted!\n", __func__, 120*21a14facSMarek Behún inr); 121*21a14facSMarek Behún goto out; 122*21a14facSMarek Behún } else if (extent->ram_bytes >= btrfs_info.sb.sectorsize) { 123*21a14facSMarek Behún printf("%s: Symlink %llu extent data too long (%llu)!\n", 124*21a14facSMarek Behún __func__, inr, extent->ram_bytes); 125*21a14facSMarek Behún goto out; 126*21a14facSMarek Behún } 127*21a14facSMarek Behún 128*21a14facSMarek Behún data_ptr = (const char *) extent 129*21a14facSMarek Behún + offsetof(struct btrfs_file_extent_item, disk_bytenr); 130*21a14facSMarek Behún 131*21a14facSMarek Behún memcpy(target, data_ptr, extent->ram_bytes); 132*21a14facSMarek Behún target[extent->ram_bytes] = '\0'; 133*21a14facSMarek Behún res = 0; 134*21a14facSMarek Behún out: 135*21a14facSMarek Behún btrfs_free_path(&path); 136*21a14facSMarek Behún return res; 137*21a14facSMarek Behún } 138*21a14facSMarek Behún 139*21a14facSMarek Behún /* inr must be a directory (for regular files with multiple hard links this 140*21a14facSMarek Behún function returns only one of the parents of the file) */ 141*21a14facSMarek Behún static u64 get_parent_inode(struct btrfs_root *root, u64 inr, 142*21a14facSMarek Behún struct btrfs_inode_item *inode_item) 143*21a14facSMarek Behún { 144*21a14facSMarek Behún struct btrfs_key key; 145*21a14facSMarek Behún u64 res; 146*21a14facSMarek Behún 147*21a14facSMarek Behún if (inr == BTRFS_FIRST_FREE_OBJECTID) { 148*21a14facSMarek Behún if (root->objectid != btrfs_info.fs_root.objectid) { 149*21a14facSMarek Behún u64 parent; 150*21a14facSMarek Behún struct btrfs_root_ref ref; 151*21a14facSMarek Behún 152*21a14facSMarek Behún parent = btrfs_lookup_root_ref(root->objectid, &ref, 153*21a14facSMarek Behún NULL); 154*21a14facSMarek Behún if (parent == -1ULL) 155*21a14facSMarek Behún return -1ULL; 156*21a14facSMarek Behún 157*21a14facSMarek Behún if (btrfs_find_root(parent, root, NULL)) 158*21a14facSMarek Behún return -1ULL; 159*21a14facSMarek Behún 160*21a14facSMarek Behún inr = ref.dirid; 161*21a14facSMarek Behún } 162*21a14facSMarek Behún 163*21a14facSMarek Behún if (inode_item) { 164*21a14facSMarek Behún key.objectid = inr; 165*21a14facSMarek Behún key.type = BTRFS_INODE_ITEM_KEY; 166*21a14facSMarek Behún key.offset = 0; 167*21a14facSMarek Behún 168*21a14facSMarek Behún if (btrfs_lookup_inode(root, &key, inode_item, NULL)) 169*21a14facSMarek Behún return -1ULL; 170*21a14facSMarek Behún } 171*21a14facSMarek Behún 172*21a14facSMarek Behún return inr; 173*21a14facSMarek Behún } 174*21a14facSMarek Behún 175*21a14facSMarek Behún res = btrfs_lookup_inode_ref(root, inr, NULL, NULL); 176*21a14facSMarek Behún if (res == -1ULL) 177*21a14facSMarek Behún return -1ULL; 178*21a14facSMarek Behún 179*21a14facSMarek Behún if (inode_item) { 180*21a14facSMarek Behún key.objectid = res; 181*21a14facSMarek Behún key.type = BTRFS_INODE_ITEM_KEY; 182*21a14facSMarek Behún key.offset = 0; 183*21a14facSMarek Behún 184*21a14facSMarek Behún if (btrfs_lookup_inode(root, &key, inode_item, NULL)) 185*21a14facSMarek Behún return -1ULL; 186*21a14facSMarek Behún } 187*21a14facSMarek Behún 188*21a14facSMarek Behún return res; 189*21a14facSMarek Behún } 190*21a14facSMarek Behún 191*21a14facSMarek Behún static inline int next_length(const char *path) 192*21a14facSMarek Behún { 193*21a14facSMarek Behún int res = 0; 194*21a14facSMarek Behún while (*path != '\0' && *path != '/' && res <= BTRFS_NAME_LEN) 195*21a14facSMarek Behún ++res, ++path; 196*21a14facSMarek Behún return res; 197*21a14facSMarek Behún } 198*21a14facSMarek Behún 199*21a14facSMarek Behún static inline const char *skip_current_directories(const char *cur) 200*21a14facSMarek Behún { 201*21a14facSMarek Behún while (1) { 202*21a14facSMarek Behún if (cur[0] == '/') 203*21a14facSMarek Behún ++cur; 204*21a14facSMarek Behún else if (cur[0] == '.' && cur[1] == '/') 205*21a14facSMarek Behún cur += 2; 206*21a14facSMarek Behún else 207*21a14facSMarek Behún break; 208*21a14facSMarek Behún } 209*21a14facSMarek Behún 210*21a14facSMarek Behún return cur; 211*21a14facSMarek Behún } 212*21a14facSMarek Behún 213*21a14facSMarek Behún /* inode.c, musi vratit aj root stromu kde sa inoda najde */ 214*21a14facSMarek Behún u64 btrfs_lookup_path(struct btrfs_root *root, u64 inr, const char *path, 215*21a14facSMarek Behún u8 *type_p, struct btrfs_inode_item *inode_item_p, 216*21a14facSMarek Behún int symlink_limit) 217*21a14facSMarek Behún { 218*21a14facSMarek Behún struct btrfs_dir_item item; 219*21a14facSMarek Behún struct btrfs_inode_item inode_item; 220*21a14facSMarek Behún u8 type = BTRFS_FT_DIR; 221*21a14facSMarek Behún int len, have_inode = 0; 222*21a14facSMarek Behún const char *cur = path; 223*21a14facSMarek Behún 224*21a14facSMarek Behún if (*cur == '/') { 225*21a14facSMarek Behún ++cur; 226*21a14facSMarek Behún inr = root->root_dirid; 227*21a14facSMarek Behún } 228*21a14facSMarek Behún 229*21a14facSMarek Behún do { 230*21a14facSMarek Behún cur = skip_current_directories(cur); 231*21a14facSMarek Behún 232*21a14facSMarek Behún len = next_length(cur); 233*21a14facSMarek Behún if (len > BTRFS_NAME_LEN) { 234*21a14facSMarek Behún printf("%s: Name too long at \"%.*s\"\n", __func__, 235*21a14facSMarek Behún BTRFS_NAME_LEN, cur); 236*21a14facSMarek Behún return -1ULL; 237*21a14facSMarek Behún } 238*21a14facSMarek Behún 239*21a14facSMarek Behún if (len == 1 && cur[0] == '.') 240*21a14facSMarek Behún break; 241*21a14facSMarek Behún 242*21a14facSMarek Behún if (len == 2 && cur[0] == '.' && cur[1] == '.') { 243*21a14facSMarek Behún cur += 2; 244*21a14facSMarek Behún inr = get_parent_inode(root, inr, &inode_item); 245*21a14facSMarek Behún if (inr == -1ULL) 246*21a14facSMarek Behún return -1ULL; 247*21a14facSMarek Behún 248*21a14facSMarek Behún type = BTRFS_FT_DIR; 249*21a14facSMarek Behún continue; 250*21a14facSMarek Behún } 251*21a14facSMarek Behún 252*21a14facSMarek Behún if (!*cur) 253*21a14facSMarek Behún break; 254*21a14facSMarek Behún 255*21a14facSMarek Behún if (btrfs_lookup_dir_item(root, inr, cur, len, &item)) 256*21a14facSMarek Behún return -1ULL; 257*21a14facSMarek Behún 258*21a14facSMarek Behún type = item.type; 259*21a14facSMarek Behún have_inode = 1; 260*21a14facSMarek Behún if (btrfs_lookup_inode(root, &item.location, &inode_item, root)) 261*21a14facSMarek Behún return -1ULL; 262*21a14facSMarek Behún 263*21a14facSMarek Behún if (item.type == BTRFS_FT_SYMLINK && symlink_limit >= 0) { 264*21a14facSMarek Behún char *target; 265*21a14facSMarek Behún 266*21a14facSMarek Behún if (!symlink_limit) { 267*21a14facSMarek Behún printf("%s: Too much symlinks!\n", __func__); 268*21a14facSMarek Behún return -1ULL; 269*21a14facSMarek Behún } 270*21a14facSMarek Behún 271*21a14facSMarek Behún target = malloc(min(inode_item.size + 1, 272*21a14facSMarek Behún (u64) btrfs_info.sb.sectorsize)); 273*21a14facSMarek Behún if (!target) 274*21a14facSMarek Behún return -1ULL; 275*21a14facSMarek Behún 276*21a14facSMarek Behún if (btrfs_readlink(root, item.location.objectid, 277*21a14facSMarek Behún target)) { 278*21a14facSMarek Behún free(target); 279*21a14facSMarek Behún return -1ULL; 280*21a14facSMarek Behún } 281*21a14facSMarek Behún 282*21a14facSMarek Behún inr = btrfs_lookup_path(root, inr, target, &type, 283*21a14facSMarek Behún &inode_item, symlink_limit - 1); 284*21a14facSMarek Behún 285*21a14facSMarek Behún free(target); 286*21a14facSMarek Behún 287*21a14facSMarek Behún if (inr == -1ULL) 288*21a14facSMarek Behún return -1ULL; 289*21a14facSMarek Behún } else if (item.type != BTRFS_FT_DIR && cur[len]) { 290*21a14facSMarek Behún printf("%s: \"%.*s\" not a directory\n", __func__, 291*21a14facSMarek Behún (int) (cur - path + len), path); 292*21a14facSMarek Behún return -1ULL; 293*21a14facSMarek Behún } else { 294*21a14facSMarek Behún inr = item.location.objectid; 295*21a14facSMarek Behún } 296*21a14facSMarek Behún 297*21a14facSMarek Behún cur += len; 298*21a14facSMarek Behún } while (*cur); 299*21a14facSMarek Behún 300*21a14facSMarek Behún if (type_p) 301*21a14facSMarek Behún *type_p = type; 302*21a14facSMarek Behún 303*21a14facSMarek Behún if (inode_item_p) { 304*21a14facSMarek Behún if (!have_inode) { 305*21a14facSMarek Behún struct btrfs_key key; 306*21a14facSMarek Behún 307*21a14facSMarek Behún key.objectid = inr; 308*21a14facSMarek Behún key.type = BTRFS_INODE_ITEM_KEY; 309*21a14facSMarek Behún key.offset = 0; 310*21a14facSMarek Behún 311*21a14facSMarek Behún if (btrfs_lookup_inode(root, &key, &inode_item, NULL)) 312*21a14facSMarek Behún return -1ULL; 313*21a14facSMarek Behún } 314*21a14facSMarek Behún 315*21a14facSMarek Behún *inode_item_p = inode_item; 316*21a14facSMarek Behún } 317*21a14facSMarek Behún 318*21a14facSMarek Behún return inr; 319*21a14facSMarek Behún } 320*21a14facSMarek Behún 321*21a14facSMarek Behún u64 btrfs_file_read(const struct btrfs_root *root, u64 inr, u64 offset, 322*21a14facSMarek Behún u64 size, char *buf) 323*21a14facSMarek Behún { 324*21a14facSMarek Behún struct btrfs_path path; 325*21a14facSMarek Behún struct btrfs_key key; 326*21a14facSMarek Behún struct btrfs_file_extent_item *extent; 327*21a14facSMarek Behún int res; 328*21a14facSMarek Behún u64 rd, rd_all = -1ULL; 329*21a14facSMarek Behún 330*21a14facSMarek Behún key.objectid = inr; 331*21a14facSMarek Behún key.type = BTRFS_EXTENT_DATA_KEY; 332*21a14facSMarek Behún key.offset = offset; 333*21a14facSMarek Behún 334*21a14facSMarek Behún if (btrfs_search_tree(root, &key, &path)) 335*21a14facSMarek Behún return -1ULL; 336*21a14facSMarek Behún 337*21a14facSMarek Behún if (btrfs_comp_keys(&key, btrfs_path_leaf_key(&path)) < 0) { 338*21a14facSMarek Behún if (btrfs_prev_slot(&path)) 339*21a14facSMarek Behún goto out; 340*21a14facSMarek Behún 341*21a14facSMarek Behún if (btrfs_comp_keys_type(&key, btrfs_path_leaf_key(&path))) 342*21a14facSMarek Behún goto out; 343*21a14facSMarek Behún } 344*21a14facSMarek Behún 345*21a14facSMarek Behún rd_all = 0; 346*21a14facSMarek Behún 347*21a14facSMarek Behún do { 348*21a14facSMarek Behún if (btrfs_comp_keys_type(&key, btrfs_path_leaf_key(&path))) 349*21a14facSMarek Behún break; 350*21a14facSMarek Behún 351*21a14facSMarek Behún extent = btrfs_path_item_ptr(&path, 352*21a14facSMarek Behún struct btrfs_file_extent_item); 353*21a14facSMarek Behún 354*21a14facSMarek Behún if (extent->type == BTRFS_FILE_EXTENT_INLINE) { 355*21a14facSMarek Behún btrfs_file_extent_item_to_cpu_inl(extent); 356*21a14facSMarek Behún rd = btrfs_read_extent_inline(&path, extent, offset, 357*21a14facSMarek Behún size, buf); 358*21a14facSMarek Behún } else { 359*21a14facSMarek Behún btrfs_file_extent_item_to_cpu(extent); 360*21a14facSMarek Behún rd = btrfs_read_extent_reg(&path, extent, offset, size, 361*21a14facSMarek Behún buf); 362*21a14facSMarek Behún } 363*21a14facSMarek Behún 364*21a14facSMarek Behún if (rd == -1ULL) { 365*21a14facSMarek Behún printf("%s: Error reading extent\n", __func__); 366*21a14facSMarek Behún rd_all = -1; 367*21a14facSMarek Behún goto out; 368*21a14facSMarek Behún } 369*21a14facSMarek Behún 370*21a14facSMarek Behún offset = 0; 371*21a14facSMarek Behún buf += rd; 372*21a14facSMarek Behún rd_all += rd; 373*21a14facSMarek Behún size -= rd; 374*21a14facSMarek Behún 375*21a14facSMarek Behún if (!size) 376*21a14facSMarek Behún break; 377*21a14facSMarek Behún } while (!(res = btrfs_next_slot(&path))); 378*21a14facSMarek Behún 379*21a14facSMarek Behún if (res) 380*21a14facSMarek Behún return -1ULL; 381*21a14facSMarek Behún 382*21a14facSMarek Behún out: 383*21a14facSMarek Behún btrfs_free_path(&path); 384*21a14facSMarek Behún return rd_all; 385*21a14facSMarek Behún } 386