18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2007 Oracle. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include "ctree.h" 78c2ecf20Sopenharmony_ci#include "disk-io.h" 88c2ecf20Sopenharmony_ci#include "transaction.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* 118c2ecf20Sopenharmony_ci * insert a name into a directory, doing overflow properly if there is a hash 128c2ecf20Sopenharmony_ci * collision. data_size indicates how big the item inserted should be. On 138c2ecf20Sopenharmony_ci * success a struct btrfs_dir_item pointer is returned, otherwise it is 148c2ecf20Sopenharmony_ci * an ERR_PTR. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * The name is not copied into the dir item, you have to do that yourself. 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_cistatic struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle 198c2ecf20Sopenharmony_ci *trans, 208c2ecf20Sopenharmony_ci struct btrfs_root *root, 218c2ecf20Sopenharmony_ci struct btrfs_path *path, 228c2ecf20Sopenharmony_ci struct btrfs_key *cpu_key, 238c2ecf20Sopenharmony_ci u32 data_size, 248c2ecf20Sopenharmony_ci const char *name, 258c2ecf20Sopenharmony_ci int name_len) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = root->fs_info; 288c2ecf20Sopenharmony_ci int ret; 298c2ecf20Sopenharmony_ci char *ptr; 308c2ecf20Sopenharmony_ci struct btrfs_item *item; 318c2ecf20Sopenharmony_ci struct extent_buffer *leaf; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size); 348c2ecf20Sopenharmony_ci if (ret == -EEXIST) { 358c2ecf20Sopenharmony_ci struct btrfs_dir_item *di; 368c2ecf20Sopenharmony_ci di = btrfs_match_dir_item_name(fs_info, path, name, name_len); 378c2ecf20Sopenharmony_ci if (di) 388c2ecf20Sopenharmony_ci return ERR_PTR(-EEXIST); 398c2ecf20Sopenharmony_ci btrfs_extend_item(path, data_size); 408c2ecf20Sopenharmony_ci } else if (ret < 0) 418c2ecf20Sopenharmony_ci return ERR_PTR(ret); 428c2ecf20Sopenharmony_ci WARN_ON(ret > 0); 438c2ecf20Sopenharmony_ci leaf = path->nodes[0]; 448c2ecf20Sopenharmony_ci item = btrfs_item_nr(path->slots[0]); 458c2ecf20Sopenharmony_ci ptr = btrfs_item_ptr(leaf, path->slots[0], char); 468c2ecf20Sopenharmony_ci BUG_ON(data_size > btrfs_item_size(leaf, item)); 478c2ecf20Sopenharmony_ci ptr += btrfs_item_size(leaf, item) - data_size; 488c2ecf20Sopenharmony_ci return (struct btrfs_dir_item *)ptr; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* 528c2ecf20Sopenharmony_ci * xattrs work a lot like directories, this inserts an xattr item 538c2ecf20Sopenharmony_ci * into the tree 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ciint btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, 568c2ecf20Sopenharmony_ci struct btrfs_root *root, 578c2ecf20Sopenharmony_ci struct btrfs_path *path, u64 objectid, 588c2ecf20Sopenharmony_ci const char *name, u16 name_len, 598c2ecf20Sopenharmony_ci const void *data, u16 data_len) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci int ret = 0; 628c2ecf20Sopenharmony_ci struct btrfs_dir_item *dir_item; 638c2ecf20Sopenharmony_ci unsigned long name_ptr, data_ptr; 648c2ecf20Sopenharmony_ci struct btrfs_key key, location; 658c2ecf20Sopenharmony_ci struct btrfs_disk_key disk_key; 668c2ecf20Sopenharmony_ci struct extent_buffer *leaf; 678c2ecf20Sopenharmony_ci u32 data_size; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root->fs_info)) 708c2ecf20Sopenharmony_ci return -ENOSPC; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci key.objectid = objectid; 738c2ecf20Sopenharmony_ci key.type = BTRFS_XATTR_ITEM_KEY; 748c2ecf20Sopenharmony_ci key.offset = btrfs_name_hash(name, name_len); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci data_size = sizeof(*dir_item) + name_len + data_len; 778c2ecf20Sopenharmony_ci dir_item = insert_with_overflow(trans, root, path, &key, data_size, 788c2ecf20Sopenharmony_ci name, name_len); 798c2ecf20Sopenharmony_ci if (IS_ERR(dir_item)) 808c2ecf20Sopenharmony_ci return PTR_ERR(dir_item); 818c2ecf20Sopenharmony_ci memset(&location, 0, sizeof(location)); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci leaf = path->nodes[0]; 848c2ecf20Sopenharmony_ci btrfs_cpu_key_to_disk(&disk_key, &location); 858c2ecf20Sopenharmony_ci btrfs_set_dir_item_key(leaf, dir_item, &disk_key); 868c2ecf20Sopenharmony_ci btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR); 878c2ecf20Sopenharmony_ci btrfs_set_dir_name_len(leaf, dir_item, name_len); 888c2ecf20Sopenharmony_ci btrfs_set_dir_transid(leaf, dir_item, trans->transid); 898c2ecf20Sopenharmony_ci btrfs_set_dir_data_len(leaf, dir_item, data_len); 908c2ecf20Sopenharmony_ci name_ptr = (unsigned long)(dir_item + 1); 918c2ecf20Sopenharmony_ci data_ptr = (unsigned long)((char *)name_ptr + name_len); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci write_extent_buffer(leaf, name, name_ptr, name_len); 948c2ecf20Sopenharmony_ci write_extent_buffer(leaf, data, data_ptr, data_len); 958c2ecf20Sopenharmony_ci btrfs_mark_buffer_dirty(path->nodes[0]); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci return ret; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* 1018c2ecf20Sopenharmony_ci * insert a directory item in the tree, doing all the magic for 1028c2ecf20Sopenharmony_ci * both indexes. 'dir' indicates which objectid to insert it into, 1038c2ecf20Sopenharmony_ci * 'location' is the key to stuff into the directory item, 'type' is the 1048c2ecf20Sopenharmony_ci * type of the inode we're pointing to, and 'index' is the sequence number 1058c2ecf20Sopenharmony_ci * to use for the second index (if one is created). 1068c2ecf20Sopenharmony_ci * Will return 0 or -ENOMEM 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ciint btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name, 1098c2ecf20Sopenharmony_ci int name_len, struct btrfs_inode *dir, 1108c2ecf20Sopenharmony_ci struct btrfs_key *location, u8 type, u64 index) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci int ret = 0; 1138c2ecf20Sopenharmony_ci int ret2 = 0; 1148c2ecf20Sopenharmony_ci struct btrfs_root *root = dir->root; 1158c2ecf20Sopenharmony_ci struct btrfs_path *path; 1168c2ecf20Sopenharmony_ci struct btrfs_dir_item *dir_item; 1178c2ecf20Sopenharmony_ci struct extent_buffer *leaf; 1188c2ecf20Sopenharmony_ci unsigned long name_ptr; 1198c2ecf20Sopenharmony_ci struct btrfs_key key; 1208c2ecf20Sopenharmony_ci struct btrfs_disk_key disk_key; 1218c2ecf20Sopenharmony_ci u32 data_size; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci key.objectid = btrfs_ino(dir); 1248c2ecf20Sopenharmony_ci key.type = BTRFS_DIR_ITEM_KEY; 1258c2ecf20Sopenharmony_ci key.offset = btrfs_name_hash(name, name_len); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 1288c2ecf20Sopenharmony_ci if (!path) 1298c2ecf20Sopenharmony_ci return -ENOMEM; 1308c2ecf20Sopenharmony_ci path->leave_spinning = 1; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci btrfs_cpu_key_to_disk(&disk_key, location); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci data_size = sizeof(*dir_item) + name_len; 1358c2ecf20Sopenharmony_ci dir_item = insert_with_overflow(trans, root, path, &key, data_size, 1368c2ecf20Sopenharmony_ci name, name_len); 1378c2ecf20Sopenharmony_ci if (IS_ERR(dir_item)) { 1388c2ecf20Sopenharmony_ci ret = PTR_ERR(dir_item); 1398c2ecf20Sopenharmony_ci if (ret == -EEXIST) 1408c2ecf20Sopenharmony_ci goto second_insert; 1418c2ecf20Sopenharmony_ci goto out_free; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci leaf = path->nodes[0]; 1458c2ecf20Sopenharmony_ci btrfs_set_dir_item_key(leaf, dir_item, &disk_key); 1468c2ecf20Sopenharmony_ci btrfs_set_dir_type(leaf, dir_item, type); 1478c2ecf20Sopenharmony_ci btrfs_set_dir_data_len(leaf, dir_item, 0); 1488c2ecf20Sopenharmony_ci btrfs_set_dir_name_len(leaf, dir_item, name_len); 1498c2ecf20Sopenharmony_ci btrfs_set_dir_transid(leaf, dir_item, trans->transid); 1508c2ecf20Sopenharmony_ci name_ptr = (unsigned long)(dir_item + 1); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci write_extent_buffer(leaf, name, name_ptr, name_len); 1538c2ecf20Sopenharmony_ci btrfs_mark_buffer_dirty(leaf); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cisecond_insert: 1568c2ecf20Sopenharmony_ci /* FIXME, use some real flag for selecting the extra index */ 1578c2ecf20Sopenharmony_ci if (root == root->fs_info->tree_root) { 1588c2ecf20Sopenharmony_ci ret = 0; 1598c2ecf20Sopenharmony_ci goto out_free; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci btrfs_release_path(path); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci ret2 = btrfs_insert_delayed_dir_index(trans, name, name_len, dir, 1648c2ecf20Sopenharmony_ci &disk_key, type, index); 1658c2ecf20Sopenharmony_ciout_free: 1668c2ecf20Sopenharmony_ci btrfs_free_path(path); 1678c2ecf20Sopenharmony_ci if (ret) 1688c2ecf20Sopenharmony_ci return ret; 1698c2ecf20Sopenharmony_ci if (ret2) 1708c2ecf20Sopenharmony_ci return ret2; 1718c2ecf20Sopenharmony_ci return 0; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci/* 1758c2ecf20Sopenharmony_ci * lookup a directory item based on name. 'dir' is the objectid 1768c2ecf20Sopenharmony_ci * we're searching in, and 'mod' tells us if you plan on deleting the 1778c2ecf20Sopenharmony_ci * item (use mod < 0) or changing the options (use mod > 0) 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_cistruct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, 1808c2ecf20Sopenharmony_ci struct btrfs_root *root, 1818c2ecf20Sopenharmony_ci struct btrfs_path *path, u64 dir, 1828c2ecf20Sopenharmony_ci const char *name, int name_len, 1838c2ecf20Sopenharmony_ci int mod) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci int ret; 1868c2ecf20Sopenharmony_ci struct btrfs_key key; 1878c2ecf20Sopenharmony_ci int ins_len = mod < 0 ? -1 : 0; 1888c2ecf20Sopenharmony_ci int cow = mod != 0; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci key.objectid = dir; 1918c2ecf20Sopenharmony_ci key.type = BTRFS_DIR_ITEM_KEY; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci key.offset = btrfs_name_hash(name, name_len); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); 1968c2ecf20Sopenharmony_ci if (ret < 0) 1978c2ecf20Sopenharmony_ci return ERR_PTR(ret); 1988c2ecf20Sopenharmony_ci if (ret > 0) 1998c2ecf20Sopenharmony_ci return NULL; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci return btrfs_match_dir_item_name(root->fs_info, path, name, name_len); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ciint btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir, 2058c2ecf20Sopenharmony_ci const char *name, int name_len) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci int ret; 2088c2ecf20Sopenharmony_ci struct btrfs_key key; 2098c2ecf20Sopenharmony_ci struct btrfs_dir_item *di; 2108c2ecf20Sopenharmony_ci int data_size; 2118c2ecf20Sopenharmony_ci struct extent_buffer *leaf; 2128c2ecf20Sopenharmony_ci int slot; 2138c2ecf20Sopenharmony_ci struct btrfs_path *path; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 2178c2ecf20Sopenharmony_ci if (!path) 2188c2ecf20Sopenharmony_ci return -ENOMEM; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci key.objectid = dir; 2218c2ecf20Sopenharmony_ci key.type = BTRFS_DIR_ITEM_KEY; 2228c2ecf20Sopenharmony_ci key.offset = btrfs_name_hash(name, name_len); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* return back any errors */ 2278c2ecf20Sopenharmony_ci if (ret < 0) 2288c2ecf20Sopenharmony_ci goto out; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* nothing found, we're safe */ 2318c2ecf20Sopenharmony_ci if (ret > 0) { 2328c2ecf20Sopenharmony_ci ret = 0; 2338c2ecf20Sopenharmony_ci goto out; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* we found an item, look for our name in the item */ 2378c2ecf20Sopenharmony_ci di = btrfs_match_dir_item_name(root->fs_info, path, name, name_len); 2388c2ecf20Sopenharmony_ci if (di) { 2398c2ecf20Sopenharmony_ci /* our exact name was found */ 2408c2ecf20Sopenharmony_ci ret = -EEXIST; 2418c2ecf20Sopenharmony_ci goto out; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* 2458c2ecf20Sopenharmony_ci * see if there is room in the item to insert this 2468c2ecf20Sopenharmony_ci * name 2478c2ecf20Sopenharmony_ci */ 2488c2ecf20Sopenharmony_ci data_size = sizeof(*di) + name_len; 2498c2ecf20Sopenharmony_ci leaf = path->nodes[0]; 2508c2ecf20Sopenharmony_ci slot = path->slots[0]; 2518c2ecf20Sopenharmony_ci if (data_size + btrfs_item_size_nr(leaf, slot) + 2528c2ecf20Sopenharmony_ci sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root->fs_info)) { 2538c2ecf20Sopenharmony_ci ret = -EOVERFLOW; 2548c2ecf20Sopenharmony_ci } else { 2558c2ecf20Sopenharmony_ci /* plenty of insertion room */ 2568c2ecf20Sopenharmony_ci ret = 0; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ciout: 2598c2ecf20Sopenharmony_ci btrfs_free_path(path); 2608c2ecf20Sopenharmony_ci return ret; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci/* 2648c2ecf20Sopenharmony_ci * lookup a directory item based on index. 'dir' is the objectid 2658c2ecf20Sopenharmony_ci * we're searching in, and 'mod' tells us if you plan on deleting the 2668c2ecf20Sopenharmony_ci * item (use mod < 0) or changing the options (use mod > 0) 2678c2ecf20Sopenharmony_ci * 2688c2ecf20Sopenharmony_ci * The name is used to make sure the index really points to the name you were 2698c2ecf20Sopenharmony_ci * looking for. 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_cistruct btrfs_dir_item * 2728c2ecf20Sopenharmony_cibtrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans, 2738c2ecf20Sopenharmony_ci struct btrfs_root *root, 2748c2ecf20Sopenharmony_ci struct btrfs_path *path, u64 dir, 2758c2ecf20Sopenharmony_ci u64 objectid, const char *name, int name_len, 2768c2ecf20Sopenharmony_ci int mod) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci int ret; 2798c2ecf20Sopenharmony_ci struct btrfs_key key; 2808c2ecf20Sopenharmony_ci int ins_len = mod < 0 ? -1 : 0; 2818c2ecf20Sopenharmony_ci int cow = mod != 0; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci key.objectid = dir; 2848c2ecf20Sopenharmony_ci key.type = BTRFS_DIR_INDEX_KEY; 2858c2ecf20Sopenharmony_ci key.offset = objectid; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); 2888c2ecf20Sopenharmony_ci if (ret < 0) 2898c2ecf20Sopenharmony_ci return ERR_PTR(ret); 2908c2ecf20Sopenharmony_ci if (ret > 0) 2918c2ecf20Sopenharmony_ci return ERR_PTR(-ENOENT); 2928c2ecf20Sopenharmony_ci return btrfs_match_dir_item_name(root->fs_info, path, name, name_len); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistruct btrfs_dir_item * 2968c2ecf20Sopenharmony_cibtrfs_search_dir_index_item(struct btrfs_root *root, 2978c2ecf20Sopenharmony_ci struct btrfs_path *path, u64 dirid, 2988c2ecf20Sopenharmony_ci const char *name, int name_len) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct extent_buffer *leaf; 3018c2ecf20Sopenharmony_ci struct btrfs_dir_item *di; 3028c2ecf20Sopenharmony_ci struct btrfs_key key; 3038c2ecf20Sopenharmony_ci u32 nritems; 3048c2ecf20Sopenharmony_ci int ret; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci key.objectid = dirid; 3078c2ecf20Sopenharmony_ci key.type = BTRFS_DIR_INDEX_KEY; 3088c2ecf20Sopenharmony_ci key.offset = 0; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); 3118c2ecf20Sopenharmony_ci if (ret < 0) 3128c2ecf20Sopenharmony_ci return ERR_PTR(ret); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci leaf = path->nodes[0]; 3158c2ecf20Sopenharmony_ci nritems = btrfs_header_nritems(leaf); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci while (1) { 3188c2ecf20Sopenharmony_ci if (path->slots[0] >= nritems) { 3198c2ecf20Sopenharmony_ci ret = btrfs_next_leaf(root, path); 3208c2ecf20Sopenharmony_ci if (ret < 0) 3218c2ecf20Sopenharmony_ci return ERR_PTR(ret); 3228c2ecf20Sopenharmony_ci if (ret > 0) 3238c2ecf20Sopenharmony_ci break; 3248c2ecf20Sopenharmony_ci leaf = path->nodes[0]; 3258c2ecf20Sopenharmony_ci nritems = btrfs_header_nritems(leaf); 3268c2ecf20Sopenharmony_ci continue; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); 3308c2ecf20Sopenharmony_ci if (key.objectid != dirid || key.type != BTRFS_DIR_INDEX_KEY) 3318c2ecf20Sopenharmony_ci break; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci di = btrfs_match_dir_item_name(root->fs_info, path, 3348c2ecf20Sopenharmony_ci name, name_len); 3358c2ecf20Sopenharmony_ci if (di) 3368c2ecf20Sopenharmony_ci return di; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci path->slots[0]++; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci return NULL; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistruct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, 3448c2ecf20Sopenharmony_ci struct btrfs_root *root, 3458c2ecf20Sopenharmony_ci struct btrfs_path *path, u64 dir, 3468c2ecf20Sopenharmony_ci const char *name, u16 name_len, 3478c2ecf20Sopenharmony_ci int mod) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci int ret; 3508c2ecf20Sopenharmony_ci struct btrfs_key key; 3518c2ecf20Sopenharmony_ci int ins_len = mod < 0 ? -1 : 0; 3528c2ecf20Sopenharmony_ci int cow = mod != 0; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci key.objectid = dir; 3558c2ecf20Sopenharmony_ci key.type = BTRFS_XATTR_ITEM_KEY; 3568c2ecf20Sopenharmony_ci key.offset = btrfs_name_hash(name, name_len); 3578c2ecf20Sopenharmony_ci ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); 3588c2ecf20Sopenharmony_ci if (ret < 0) 3598c2ecf20Sopenharmony_ci return ERR_PTR(ret); 3608c2ecf20Sopenharmony_ci if (ret > 0) 3618c2ecf20Sopenharmony_ci return NULL; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci return btrfs_match_dir_item_name(root->fs_info, path, name, name_len); 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci/* 3678c2ecf20Sopenharmony_ci * helper function to look at the directory item pointed to by 'path' 3688c2ecf20Sopenharmony_ci * this walks through all the entries in a dir item and finds one 3698c2ecf20Sopenharmony_ci * for a specific name. 3708c2ecf20Sopenharmony_ci */ 3718c2ecf20Sopenharmony_cistruct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info, 3728c2ecf20Sopenharmony_ci struct btrfs_path *path, 3738c2ecf20Sopenharmony_ci const char *name, int name_len) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci struct btrfs_dir_item *dir_item; 3768c2ecf20Sopenharmony_ci unsigned long name_ptr; 3778c2ecf20Sopenharmony_ci u32 total_len; 3788c2ecf20Sopenharmony_ci u32 cur = 0; 3798c2ecf20Sopenharmony_ci u32 this_len; 3808c2ecf20Sopenharmony_ci struct extent_buffer *leaf; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci leaf = path->nodes[0]; 3838c2ecf20Sopenharmony_ci dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci total_len = btrfs_item_size_nr(leaf, path->slots[0]); 3868c2ecf20Sopenharmony_ci while (cur < total_len) { 3878c2ecf20Sopenharmony_ci this_len = sizeof(*dir_item) + 3888c2ecf20Sopenharmony_ci btrfs_dir_name_len(leaf, dir_item) + 3898c2ecf20Sopenharmony_ci btrfs_dir_data_len(leaf, dir_item); 3908c2ecf20Sopenharmony_ci name_ptr = (unsigned long)(dir_item + 1); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (btrfs_dir_name_len(leaf, dir_item) == name_len && 3938c2ecf20Sopenharmony_ci memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) 3948c2ecf20Sopenharmony_ci return dir_item; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci cur += this_len; 3978c2ecf20Sopenharmony_ci dir_item = (struct btrfs_dir_item *)((char *)dir_item + 3988c2ecf20Sopenharmony_ci this_len); 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci return NULL; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci/* 4048c2ecf20Sopenharmony_ci * given a pointer into a directory item, delete it. This 4058c2ecf20Sopenharmony_ci * handles items that have more than one entry in them. 4068c2ecf20Sopenharmony_ci */ 4078c2ecf20Sopenharmony_ciint btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, 4088c2ecf20Sopenharmony_ci struct btrfs_root *root, 4098c2ecf20Sopenharmony_ci struct btrfs_path *path, 4108c2ecf20Sopenharmony_ci struct btrfs_dir_item *di) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci struct extent_buffer *leaf; 4148c2ecf20Sopenharmony_ci u32 sub_item_len; 4158c2ecf20Sopenharmony_ci u32 item_len; 4168c2ecf20Sopenharmony_ci int ret = 0; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci leaf = path->nodes[0]; 4198c2ecf20Sopenharmony_ci sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) + 4208c2ecf20Sopenharmony_ci btrfs_dir_data_len(leaf, di); 4218c2ecf20Sopenharmony_ci item_len = btrfs_item_size_nr(leaf, path->slots[0]); 4228c2ecf20Sopenharmony_ci if (sub_item_len == item_len) { 4238c2ecf20Sopenharmony_ci ret = btrfs_del_item(trans, root, path); 4248c2ecf20Sopenharmony_ci } else { 4258c2ecf20Sopenharmony_ci /* MARKER */ 4268c2ecf20Sopenharmony_ci unsigned long ptr = (unsigned long)di; 4278c2ecf20Sopenharmony_ci unsigned long start; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci start = btrfs_item_ptr_offset(leaf, path->slots[0]); 4308c2ecf20Sopenharmony_ci memmove_extent_buffer(leaf, ptr, ptr + sub_item_len, 4318c2ecf20Sopenharmony_ci item_len - (ptr + sub_item_len - start)); 4328c2ecf20Sopenharmony_ci btrfs_truncate_item(path, item_len - sub_item_len, 1); 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci return ret; 4358c2ecf20Sopenharmony_ci} 436