1c1d7c514SDavid Sterba // SPDX-License-Identifier: GPL-2.0
26cbd5570SChris Mason /*
36cbd5570SChris Mason * Copyright (C) 2007 Oracle. All rights reserved.
46cbd5570SChris Mason */
56cbd5570SChris Mason
69b569ea0SJosef Bacik #include "messages.h"
762e2749eSChris Mason #include "ctree.h"
862e2749eSChris Mason #include "disk-io.h"
9e089f05cSChris Mason #include "transaction.h"
1007e81dc9SJosef Bacik #include "accessors.h"
11f2b39277SJosef Bacik #include "dir-item.h"
1262e2749eSChris Mason
13d352ac68SChris Mason /*
14d352ac68SChris Mason * insert a name into a directory, doing overflow properly if there is a hash
15d352ac68SChris Mason * collision. data_size indicates how big the item inserted should be. On
16d352ac68SChris Mason * success a struct btrfs_dir_item pointer is returned, otherwise it is
17d352ac68SChris Mason * an ERR_PTR.
18d352ac68SChris Mason *
19d352ac68SChris Mason * The name is not copied into the dir item, you have to do that yourself.
20d352ac68SChris Mason */
insert_with_overflow(struct btrfs_trans_handle * trans,struct btrfs_root * root,struct btrfs_path * path,struct btrfs_key * cpu_key,u32 data_size,const char * name,int name_len)2135b7e476SChris Mason static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
2235b7e476SChris Mason *trans,
237e38180eSChris Mason struct btrfs_root *root,
247e38180eSChris Mason struct btrfs_path *path,
257e38180eSChris Mason struct btrfs_key *cpu_key,
26e06afa83SChris Mason u32 data_size,
27e06afa83SChris Mason const char *name,
28e06afa83SChris Mason int name_len)
297fcde0e3SChris Mason {
302ff7e61eSJeff Mahoney struct btrfs_fs_info *fs_info = root->fs_info;
317fcde0e3SChris Mason int ret;
327e38180eSChris Mason char *ptr;
335f39d397SChris Mason struct extent_buffer *leaf;
347fcde0e3SChris Mason
357fcde0e3SChris Mason ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
367e38180eSChris Mason if (ret == -EEXIST) {
37e06afa83SChris Mason struct btrfs_dir_item *di;
382ff7e61eSJeff Mahoney di = btrfs_match_dir_item_name(fs_info, path, name, name_len);
39e06afa83SChris Mason if (di)
40e06afa83SChris Mason return ERR_PTR(-EEXIST);
41d5e09e38SFilipe Manana btrfs_extend_item(trans, path, data_size);
42143bede5SJeff Mahoney } else if (ret < 0)
4354aa1f4dSChris Mason return ERR_PTR(ret);
447e38180eSChris Mason WARN_ON(ret > 0);
455f39d397SChris Mason leaf = path->nodes[0];
467e38180eSChris Mason ptr = btrfs_item_ptr(leaf, path->slots[0], char);
473212fa14SJosef Bacik ASSERT(data_size <= btrfs_item_size(leaf, path->slots[0]));
483212fa14SJosef Bacik ptr += btrfs_item_size(leaf, path->slots[0]) - data_size;
497e38180eSChris Mason return (struct btrfs_dir_item *)ptr;
507fcde0e3SChris Mason }
517fcde0e3SChris Mason
52d352ac68SChris Mason /*
53d352ac68SChris Mason * xattrs work a lot like directories, this inserts an xattr item
54d352ac68SChris Mason * into the tree
55d352ac68SChris Mason */
btrfs_insert_xattr_item(struct btrfs_trans_handle * trans,struct btrfs_root * root,struct btrfs_path * path,u64 objectid,const char * name,u16 name_len,const void * data,u16 data_len)565103e947SJosef Bacik int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
57f34f57a3SYan, Zheng struct btrfs_root *root,
58f34f57a3SYan, Zheng struct btrfs_path *path, u64 objectid,
59f34f57a3SYan, Zheng const char *name, u16 name_len,
60f34f57a3SYan, Zheng const void *data, u16 data_len)
615103e947SJosef Bacik {
625103e947SJosef Bacik int ret = 0;
635103e947SJosef Bacik struct btrfs_dir_item *dir_item;
645103e947SJosef Bacik unsigned long name_ptr, data_ptr;
655103e947SJosef Bacik struct btrfs_key key, location;
665103e947SJosef Bacik struct btrfs_disk_key disk_key;
675103e947SJosef Bacik struct extent_buffer *leaf;
685103e947SJosef Bacik u32 data_size;
695103e947SJosef Bacik
70b9d04c60SDavid Sterba if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root->fs_info))
71b9d04c60SDavid Sterba return -ENOSPC;
72f34f57a3SYan, Zheng
73f34f57a3SYan, Zheng key.objectid = objectid;
74962a298fSDavid Sterba key.type = BTRFS_XATTR_ITEM_KEY;
75df68b8a7SDavid Miller key.offset = btrfs_name_hash(name, name_len);
765103e947SJosef Bacik
775103e947SJosef Bacik data_size = sizeof(*dir_item) + name_len + data_len;
785103e947SJosef Bacik dir_item = insert_with_overflow(trans, root, path, &key, data_size,
795103e947SJosef Bacik name, name_len);
80fa09200bSJosef Bacik if (IS_ERR(dir_item))
81fa09200bSJosef Bacik return PTR_ERR(dir_item);
825103e947SJosef Bacik memset(&location, 0, sizeof(location));
835103e947SJosef Bacik
845103e947SJosef Bacik leaf = path->nodes[0];
855103e947SJosef Bacik btrfs_cpu_key_to_disk(&disk_key, &location);
865103e947SJosef Bacik btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
8794a48aefSOmar Sandoval btrfs_set_dir_flags(leaf, dir_item, BTRFS_FT_XATTR);
885103e947SJosef Bacik btrfs_set_dir_name_len(leaf, dir_item, name_len);
89e02119d5SChris Mason btrfs_set_dir_transid(leaf, dir_item, trans->transid);
905103e947SJosef Bacik btrfs_set_dir_data_len(leaf, dir_item, data_len);
915103e947SJosef Bacik name_ptr = (unsigned long)(dir_item + 1);
925103e947SJosef Bacik data_ptr = (unsigned long)((char *)name_ptr + name_len);
935103e947SJosef Bacik
945103e947SJosef Bacik write_extent_buffer(leaf, name, name_ptr, name_len);
955103e947SJosef Bacik write_extent_buffer(leaf, data, data_ptr, data_len);
96d5e09e38SFilipe Manana btrfs_mark_buffer_dirty(trans, path->nodes[0]);
975103e947SJosef Bacik
985103e947SJosef Bacik return ret;
995103e947SJosef Bacik }
1005103e947SJosef Bacik
101d352ac68SChris Mason /*
102d352ac68SChris Mason * insert a directory item in the tree, doing all the magic for
103d352ac68SChris Mason * both indexes. 'dir' indicates which objectid to insert it into,
104d352ac68SChris Mason * 'location' is the key to stuff into the directory item, 'type' is the
105d352ac68SChris Mason * type of the inode we're pointing to, and 'index' is the sequence number
106d352ac68SChris Mason * to use for the second index (if one is created).
10779787eaaSJeff Mahoney * Will return 0 or -ENOMEM
108d352ac68SChris Mason */
btrfs_insert_dir_item(struct btrfs_trans_handle * trans,const struct fscrypt_str * name,struct btrfs_inode * dir,struct btrfs_key * location,u8 type,u64 index)109e43eec81SSweet Tea Dorminy int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
1106db75318SSweet Tea Dorminy const struct fscrypt_str *name, struct btrfs_inode *dir,
111684572dfSLu Fengqi struct btrfs_key *location, u8 type, u64 index)
11262e2749eSChris Mason {
11362e2749eSChris Mason int ret = 0;
114e06afa83SChris Mason int ret2 = 0;
115684572dfSLu Fengqi struct btrfs_root *root = dir->root;
1165caf2a00SChris Mason struct btrfs_path *path;
11762e2749eSChris Mason struct btrfs_dir_item *dir_item;
1185f39d397SChris Mason struct extent_buffer *leaf;
1195f39d397SChris Mason unsigned long name_ptr;
12062e2749eSChris Mason struct btrfs_key key;
1215f39d397SChris Mason struct btrfs_disk_key disk_key;
12262e2749eSChris Mason u32 data_size;
12362e2749eSChris Mason
1248e7611cfSNikolay Borisov key.objectid = btrfs_ino(dir);
125962a298fSDavid Sterba key.type = BTRFS_DIR_ITEM_KEY;
126e43eec81SSweet Tea Dorminy key.offset = btrfs_name_hash(name->name, name->len);
127b9473439SChris Mason
1285caf2a00SChris Mason path = btrfs_alloc_path();
12916cdcec7SMiao Xie if (!path)
13016cdcec7SMiao Xie return -ENOMEM;
131b9473439SChris Mason
13216cdcec7SMiao Xie btrfs_cpu_key_to_disk(&disk_key, location);
13316cdcec7SMiao Xie
134e43eec81SSweet Tea Dorminy data_size = sizeof(*dir_item) + name->len;
135e06afa83SChris Mason dir_item = insert_with_overflow(trans, root, path, &key, data_size,
136e43eec81SSweet Tea Dorminy name->name, name->len);
1377e38180eSChris Mason if (IS_ERR(dir_item)) {
1387e38180eSChris Mason ret = PTR_ERR(dir_item);
139e06afa83SChris Mason if (ret == -EEXIST)
140e06afa83SChris Mason goto second_insert;
141c2db1073STsutomu Itoh goto out_free;
1427e38180eSChris Mason }
14362e2749eSChris Mason
14494a48aefSOmar Sandoval if (IS_ENCRYPTED(&dir->vfs_inode))
14594a48aefSOmar Sandoval type |= BTRFS_FT_ENCRYPTED;
14694a48aefSOmar Sandoval
1475f39d397SChris Mason leaf = path->nodes[0];
1485f39d397SChris Mason btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
14994a48aefSOmar Sandoval btrfs_set_dir_flags(leaf, dir_item, type);
1505103e947SJosef Bacik btrfs_set_dir_data_len(leaf, dir_item, 0);
151e43eec81SSweet Tea Dorminy btrfs_set_dir_name_len(leaf, dir_item, name->len);
152e02119d5SChris Mason btrfs_set_dir_transid(leaf, dir_item, trans->transid);
1535f39d397SChris Mason name_ptr = (unsigned long)(dir_item + 1);
154c5739bbaSChris Mason
155e43eec81SSweet Tea Dorminy write_extent_buffer(leaf, name->name, name_ptr, name->len);
156d5e09e38SFilipe Manana btrfs_mark_buffer_dirty(trans, leaf);
1577e38180eSChris Mason
158e06afa83SChris Mason second_insert:
1597e38180eSChris Mason /* FIXME, use some real flag for selecting the extra index */
1607e38180eSChris Mason if (root == root->fs_info->tree_root) {
1617e38180eSChris Mason ret = 0;
162c2db1073STsutomu Itoh goto out_free;
1637e38180eSChris Mason }
164b3b4aa74SDavid Sterba btrfs_release_path(path);
1657e38180eSChris Mason
166e43eec81SSweet Tea Dorminy ret2 = btrfs_insert_delayed_dir_index(trans, name->name, name->len, dir,
1674465c8b4SLu Fengqi &disk_key, type, index);
168c2db1073STsutomu Itoh out_free:
1695caf2a00SChris Mason btrfs_free_path(path);
170e06afa83SChris Mason if (ret)
17162e2749eSChris Mason return ret;
172e06afa83SChris Mason if (ret2)
173e06afa83SChris Mason return ret2;
174e06afa83SChris Mason return 0;
17562e2749eSChris Mason }
17662e2749eSChris Mason
btrfs_lookup_match_dir(struct btrfs_trans_handle * trans,struct btrfs_root * root,struct btrfs_path * path,struct btrfs_key * key,const char * name,int name_len,int mod)177a7d1c5dcSMarcos Paulo de Souza static struct btrfs_dir_item *btrfs_lookup_match_dir(
178a7d1c5dcSMarcos Paulo de Souza struct btrfs_trans_handle *trans,
179a7d1c5dcSMarcos Paulo de Souza struct btrfs_root *root, struct btrfs_path *path,
180a7d1c5dcSMarcos Paulo de Souza struct btrfs_key *key, const char *name,
181a7d1c5dcSMarcos Paulo de Souza int name_len, int mod)
182a7d1c5dcSMarcos Paulo de Souza {
183a7d1c5dcSMarcos Paulo de Souza const int ins_len = (mod < 0 ? -1 : 0);
184a7d1c5dcSMarcos Paulo de Souza const int cow = (mod != 0);
185a7d1c5dcSMarcos Paulo de Souza int ret;
186a7d1c5dcSMarcos Paulo de Souza
187a7d1c5dcSMarcos Paulo de Souza ret = btrfs_search_slot(trans, root, key, path, ins_len, cow);
188a7d1c5dcSMarcos Paulo de Souza if (ret < 0)
189a7d1c5dcSMarcos Paulo de Souza return ERR_PTR(ret);
190a7d1c5dcSMarcos Paulo de Souza if (ret > 0)
191a7d1c5dcSMarcos Paulo de Souza return ERR_PTR(-ENOENT);
192a7d1c5dcSMarcos Paulo de Souza
193a7d1c5dcSMarcos Paulo de Souza return btrfs_match_dir_item_name(root->fs_info, path, name, name_len);
194a7d1c5dcSMarcos Paulo de Souza }
195a7d1c5dcSMarcos Paulo de Souza
196d352ac68SChris Mason /*
1978dcbc261SFilipe Manana * Lookup for a directory item by name.
1988dcbc261SFilipe Manana *
1998dcbc261SFilipe Manana * @trans: The transaction handle to use. Can be NULL if @mod is 0.
2008dcbc261SFilipe Manana * @root: The root of the target tree.
2018dcbc261SFilipe Manana * @path: Path to use for the search.
2028dcbc261SFilipe Manana * @dir: The inode number (objectid) of the directory.
2038dcbc261SFilipe Manana * @name: The name associated to the directory entry we are looking for.
2048dcbc261SFilipe Manana * @name_len: The length of the name.
2058dcbc261SFilipe Manana * @mod: Used to indicate if the tree search is meant for a read only
2068dcbc261SFilipe Manana * lookup, for a modification lookup or for a deletion lookup, so
2078dcbc261SFilipe Manana * its value should be 0, 1 or -1, respectively.
2088dcbc261SFilipe Manana *
2098dcbc261SFilipe Manana * Returns: NULL if the dir item does not exists, an error pointer if an error
2108dcbc261SFilipe Manana * happened, or a pointer to a dir item if a dir item exists for the given name.
211d352ac68SChris Mason */
btrfs_lookup_dir_item(struct btrfs_trans_handle * trans,struct btrfs_root * root,struct btrfs_path * path,u64 dir,const struct fscrypt_str * name,int mod)2127e38180eSChris Mason struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
2137e38180eSChris Mason struct btrfs_root *root,
2147e38180eSChris Mason struct btrfs_path *path, u64 dir,
2156db75318SSweet Tea Dorminy const struct fscrypt_str *name,
2167e38180eSChris Mason int mod)
21762e2749eSChris Mason {
21862e2749eSChris Mason struct btrfs_key key;
219a7d1c5dcSMarcos Paulo de Souza struct btrfs_dir_item *di;
22062e2749eSChris Mason
22162e2749eSChris Mason key.objectid = dir;
222962a298fSDavid Sterba key.type = BTRFS_DIR_ITEM_KEY;
223e43eec81SSweet Tea Dorminy key.offset = btrfs_name_hash(name->name, name->len);
2245f39d397SChris Mason
225e43eec81SSweet Tea Dorminy di = btrfs_lookup_match_dir(trans, root, path, &key, name->name,
226e43eec81SSweet Tea Dorminy name->len, mod);
227a7d1c5dcSMarcos Paulo de Souza if (IS_ERR(di) && PTR_ERR(di) == -ENOENT)
2287e38180eSChris Mason return NULL;
2297fcde0e3SChris Mason
230a7d1c5dcSMarcos Paulo de Souza return di;
23162e2749eSChris Mason }
23262e2749eSChris Mason
btrfs_check_dir_item_collision(struct btrfs_root * root,u64 dir,const struct fscrypt_str * name)2339c52057cSChris Mason int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
2346db75318SSweet Tea Dorminy const struct fscrypt_str *name)
2359c52057cSChris Mason {
2369c52057cSChris Mason int ret;
2379c52057cSChris Mason struct btrfs_key key;
2389c52057cSChris Mason struct btrfs_dir_item *di;
2399c52057cSChris Mason int data_size;
2409c52057cSChris Mason struct extent_buffer *leaf;
2419c52057cSChris Mason int slot;
2429c52057cSChris Mason struct btrfs_path *path;
2439c52057cSChris Mason
2449c52057cSChris Mason path = btrfs_alloc_path();
2459c52057cSChris Mason if (!path)
2469c52057cSChris Mason return -ENOMEM;
2479c52057cSChris Mason
2489c52057cSChris Mason key.objectid = dir;
249962a298fSDavid Sterba key.type = BTRFS_DIR_ITEM_KEY;
250e43eec81SSweet Tea Dorminy key.offset = btrfs_name_hash(name->name, name->len);
2519c52057cSChris Mason
252e43eec81SSweet Tea Dorminy di = btrfs_lookup_match_dir(NULL, root, path, &key, name->name,
253e43eec81SSweet Tea Dorminy name->len, 0);
254a7d1c5dcSMarcos Paulo de Souza if (IS_ERR(di)) {
255a7d1c5dcSMarcos Paulo de Souza ret = PTR_ERR(di);
256a7d1c5dcSMarcos Paulo de Souza /* Nothing found, we're safe */
257a7d1c5dcSMarcos Paulo de Souza if (ret == -ENOENT) {
2589c52057cSChris Mason ret = 0;
2599c52057cSChris Mason goto out;
2609c52057cSChris Mason }
2619c52057cSChris Mason
262a7d1c5dcSMarcos Paulo de Souza if (ret < 0)
263a7d1c5dcSMarcos Paulo de Souza goto out;
264a7d1c5dcSMarcos Paulo de Souza }
265a7d1c5dcSMarcos Paulo de Souza
2669c52057cSChris Mason /* we found an item, look for our name in the item */
2679c52057cSChris Mason if (di) {
2689c52057cSChris Mason /* our exact name was found */
2699c52057cSChris Mason ret = -EEXIST;
2709c52057cSChris Mason goto out;
2719c52057cSChris Mason }
2729c52057cSChris Mason
273e43eec81SSweet Tea Dorminy /* See if there is room in the item to insert this name. */
274e43eec81SSweet Tea Dorminy data_size = sizeof(*di) + name->len;
2759c52057cSChris Mason leaf = path->nodes[0];
2769c52057cSChris Mason slot = path->slots[0];
2773212fa14SJosef Bacik if (data_size + btrfs_item_size(leaf, slot) +
278da17066cSJeff Mahoney sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root->fs_info)) {
2799c52057cSChris Mason ret = -EOVERFLOW;
2809c52057cSChris Mason } else {
2819c52057cSChris Mason /* plenty of insertion room */
2829c52057cSChris Mason ret = 0;
2839c52057cSChris Mason }
2849c52057cSChris Mason out:
2859c52057cSChris Mason btrfs_free_path(path);
2869c52057cSChris Mason return ret;
2879c52057cSChris Mason }
2889c52057cSChris Mason
289d352ac68SChris Mason /*
2908dcbc261SFilipe Manana * Lookup for a directory index item by name and index number.
291d352ac68SChris Mason *
2928dcbc261SFilipe Manana * @trans: The transaction handle to use. Can be NULL if @mod is 0.
2938dcbc261SFilipe Manana * @root: The root of the target tree.
2948dcbc261SFilipe Manana * @path: Path to use for the search.
2958dcbc261SFilipe Manana * @dir: The inode number (objectid) of the directory.
2968dcbc261SFilipe Manana * @index: The index number.
2978dcbc261SFilipe Manana * @name: The name associated to the directory entry we are looking for.
2988dcbc261SFilipe Manana * @name_len: The length of the name.
2998dcbc261SFilipe Manana * @mod: Used to indicate if the tree search is meant for a read only
3008dcbc261SFilipe Manana * lookup, for a modification lookup or for a deletion lookup, so
3018dcbc261SFilipe Manana * its value should be 0, 1 or -1, respectively.
3028dcbc261SFilipe Manana *
3038dcbc261SFilipe Manana * Returns: NULL if the dir index item does not exists, an error pointer if an
3048dcbc261SFilipe Manana * error happened, or a pointer to a dir item if the dir index item exists and
3058dcbc261SFilipe Manana * matches the criteria (name and index number).
306d352ac68SChris Mason */
3077e38180eSChris Mason struct btrfs_dir_item *
btrfs_lookup_dir_index_item(struct btrfs_trans_handle * trans,struct btrfs_root * root,struct btrfs_path * path,u64 dir,u64 index,const struct fscrypt_str * name,int mod)3087e38180eSChris Mason btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
3097e38180eSChris Mason struct btrfs_root *root,
3107e38180eSChris Mason struct btrfs_path *path, u64 dir,
3116db75318SSweet Tea Dorminy u64 index, const struct fscrypt_str *name, int mod)
3127e38180eSChris Mason {
3138dcbc261SFilipe Manana struct btrfs_dir_item *di;
3147e38180eSChris Mason struct btrfs_key key;
3157e38180eSChris Mason
3167e38180eSChris Mason key.objectid = dir;
317962a298fSDavid Sterba key.type = BTRFS_DIR_INDEX_KEY;
3188dcbc261SFilipe Manana key.offset = index;
3197e38180eSChris Mason
320e43eec81SSweet Tea Dorminy di = btrfs_lookup_match_dir(trans, root, path, &key, name->name,
321e43eec81SSweet Tea Dorminy name->len, mod);
3228dcbc261SFilipe Manana if (di == ERR_PTR(-ENOENT))
3238dcbc261SFilipe Manana return NULL;
3248dcbc261SFilipe Manana
3258dcbc261SFilipe Manana return di;
3267e38180eSChris Mason }
3277e38180eSChris Mason
3284df27c4dSYan, Zheng struct btrfs_dir_item *
btrfs_search_dir_index_item(struct btrfs_root * root,struct btrfs_path * path,u64 dirid,const struct fscrypt_str * name)329e43eec81SSweet Tea Dorminy btrfs_search_dir_index_item(struct btrfs_root *root, struct btrfs_path *path,
3306db75318SSweet Tea Dorminy u64 dirid, const struct fscrypt_str *name)
3314df27c4dSYan, Zheng {
3324df27c4dSYan, Zheng struct btrfs_dir_item *di;
3334df27c4dSYan, Zheng struct btrfs_key key;
3344df27c4dSYan, Zheng int ret;
3354df27c4dSYan, Zheng
3364df27c4dSYan, Zheng key.objectid = dirid;
3374df27c4dSYan, Zheng key.type = BTRFS_DIR_INDEX_KEY;
3384df27c4dSYan, Zheng key.offset = 0;
3394df27c4dSYan, Zheng
3409dcbe16fSGabriel Niebler btrfs_for_each_slot(root, &key, &key, path, ret) {
3414df27c4dSYan, Zheng if (key.objectid != dirid || key.type != BTRFS_DIR_INDEX_KEY)
3424df27c4dSYan, Zheng break;
3434df27c4dSYan, Zheng
3442ff7e61eSJeff Mahoney di = btrfs_match_dir_item_name(root->fs_info, path,
345e43eec81SSweet Tea Dorminy name->name, name->len);
3464df27c4dSYan, Zheng if (di)
3474df27c4dSYan, Zheng return di;
3484df27c4dSYan, Zheng }
3499dcbe16fSGabriel Niebler /* Adjust return code if the key was not found in the next leaf. */
350*35217546SYue Haibing if (ret >= 0)
351*35217546SYue Haibing ret = -ENOENT;
3529dcbe16fSGabriel Niebler
3539dcbe16fSGabriel Niebler return ERR_PTR(ret);
3544df27c4dSYan, Zheng }
3554df27c4dSYan, Zheng
btrfs_lookup_xattr(struct btrfs_trans_handle * trans,struct btrfs_root * root,struct btrfs_path * path,u64 dir,const char * name,u16 name_len,int mod)3565103e947SJosef Bacik struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
3575103e947SJosef Bacik struct btrfs_root *root,
3585103e947SJosef Bacik struct btrfs_path *path, u64 dir,
3595103e947SJosef Bacik const char *name, u16 name_len,
3605103e947SJosef Bacik int mod)
3615103e947SJosef Bacik {
3625103e947SJosef Bacik struct btrfs_key key;
363a7d1c5dcSMarcos Paulo de Souza struct btrfs_dir_item *di;
3645103e947SJosef Bacik
3655103e947SJosef Bacik key.objectid = dir;
366962a298fSDavid Sterba key.type = BTRFS_XATTR_ITEM_KEY;
367df68b8a7SDavid Miller key.offset = btrfs_name_hash(name, name_len);
368a7d1c5dcSMarcos Paulo de Souza
369a7d1c5dcSMarcos Paulo de Souza di = btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod);
370a7d1c5dcSMarcos Paulo de Souza if (IS_ERR(di) && PTR_ERR(di) == -ENOENT)
3715103e947SJosef Bacik return NULL;
3725103e947SJosef Bacik
373a7d1c5dcSMarcos Paulo de Souza return di;
3745103e947SJosef Bacik }
3755103e947SJosef Bacik
376d352ac68SChris Mason /*
377d352ac68SChris Mason * helper function to look at the directory item pointed to by 'path'
378d352ac68SChris Mason * this walks through all the entries in a dir item and finds one
379d352ac68SChris Mason * for a specific name.
380d352ac68SChris Mason */
btrfs_match_dir_item_name(struct btrfs_fs_info * fs_info,struct btrfs_path * path,const char * name,int name_len)3812ff7e61eSJeff Mahoney struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info,
3827f5c1516SChris Mason struct btrfs_path *path,
3837f5c1516SChris Mason const char *name, int name_len)
38462e2749eSChris Mason {
38562e2749eSChris Mason struct btrfs_dir_item *dir_item;
3865f39d397SChris Mason unsigned long name_ptr;
3877e38180eSChris Mason u32 total_len;
3887e38180eSChris Mason u32 cur = 0;
3897e38180eSChris Mason u32 this_len;
3905f39d397SChris Mason struct extent_buffer *leaf;
391a8a2ee0cSChris Mason
3925f39d397SChris Mason leaf = path->nodes[0];
3937e38180eSChris Mason dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
39422a94d44SJosef Bacik
3953212fa14SJosef Bacik total_len = btrfs_item_size(leaf, path->slots[0]);
3967e38180eSChris Mason while (cur < total_len) {
3975f39d397SChris Mason this_len = sizeof(*dir_item) +
3985103e947SJosef Bacik btrfs_dir_name_len(leaf, dir_item) +
3995103e947SJosef Bacik btrfs_dir_data_len(leaf, dir_item);
4005f39d397SChris Mason name_ptr = (unsigned long)(dir_item + 1);
4017e38180eSChris Mason
4025f39d397SChris Mason if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
4035f39d397SChris Mason memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
4047e38180eSChris Mason return dir_item;
4057e38180eSChris Mason
4067e38180eSChris Mason cur += this_len;
4077e38180eSChris Mason dir_item = (struct btrfs_dir_item *)((char *)dir_item +
4087e38180eSChris Mason this_len);
40962e2749eSChris Mason }
4107e38180eSChris Mason return NULL;
4117e38180eSChris Mason }
4127e38180eSChris Mason
413d352ac68SChris Mason /*
414d352ac68SChris Mason * given a pointer into a directory item, delete it. This
415d352ac68SChris Mason * handles items that have more than one entry in them.
416d352ac68SChris Mason */
btrfs_delete_one_dir_name(struct btrfs_trans_handle * trans,struct btrfs_root * root,struct btrfs_path * path,struct btrfs_dir_item * di)4177e38180eSChris Mason int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
4187e38180eSChris Mason struct btrfs_root *root,
4197e38180eSChris Mason struct btrfs_path *path,
4207e38180eSChris Mason struct btrfs_dir_item *di)
4217e38180eSChris Mason {
4227e38180eSChris Mason
4235f39d397SChris Mason struct extent_buffer *leaf;
4247e38180eSChris Mason u32 sub_item_len;
4257e38180eSChris Mason u32 item_len;
42654aa1f4dSChris Mason int ret = 0;
4277e38180eSChris Mason
4285f39d397SChris Mason leaf = path->nodes[0];
4295103e947SJosef Bacik sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) +
4305103e947SJosef Bacik btrfs_dir_data_len(leaf, di);
4313212fa14SJosef Bacik item_len = btrfs_item_size(leaf, path->slots[0]);
4325f39d397SChris Mason if (sub_item_len == item_len) {
4337e38180eSChris Mason ret = btrfs_del_item(trans, root, path);
4347e38180eSChris Mason } else {
4355f39d397SChris Mason /* MARKER */
4365f39d397SChris Mason unsigned long ptr = (unsigned long)di;
4375f39d397SChris Mason unsigned long start;
4385f39d397SChris Mason
4395f39d397SChris Mason start = btrfs_item_ptr_offset(leaf, path->slots[0]);
4405f39d397SChris Mason memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
4417e38180eSChris Mason item_len - (ptr + sub_item_len - start));
442d5e09e38SFilipe Manana btrfs_truncate_item(trans, path, item_len - sub_item_len, 1);
4437e38180eSChris Mason }
444411fc6bcSAndi Kleen return ret;
4457e38180eSChris Mason }
446