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