Merge tag 'xilinx-for-v2021.01' of https://gitlab.denx.de/u-boot/custodians/u-boot...
[platform/kernel/u-boot.git] / fs / btrfs / dir-item.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * BTRFS filesystem implementation for U-Boot
4  *
5  * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
6  */
7
8 #include "btrfs.h"
9 #include "disk-io.h"
10
11 static int verify_dir_item(struct btrfs_root *root,
12                     struct extent_buffer *leaf,
13                     struct btrfs_dir_item *dir_item)
14 {
15         u16 namelen = BTRFS_NAME_LEN;
16         u8 type = btrfs_dir_type(leaf, dir_item);
17
18         if (type == BTRFS_FT_XATTR)
19                 namelen = XATTR_NAME_MAX;
20
21         if (btrfs_dir_name_len(leaf, dir_item) > namelen) {
22                 fprintf(stderr, "invalid dir item name len: %u\n",
23                         (unsigned)btrfs_dir_data_len(leaf, dir_item));
24                 return 1;
25         }
26
27         /* BTRFS_MAX_XATTR_SIZE is the same for all dir items */
28         if ((btrfs_dir_data_len(leaf, dir_item) +
29              btrfs_dir_name_len(leaf, dir_item)) >
30                         BTRFS_MAX_XATTR_SIZE(root->fs_info)) {
31                 fprintf(stderr, "invalid dir item name + data len: %u + %u\n",
32                         (unsigned)btrfs_dir_name_len(leaf, dir_item),
33                         (unsigned)btrfs_dir_data_len(leaf, dir_item));
34                 return 1;
35         }
36
37         return 0;
38 }
39
40 struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
41                               struct btrfs_path *path,
42                               const char *name, int name_len)
43 {
44         struct btrfs_dir_item *dir_item;
45         unsigned long name_ptr;
46         u32 total_len;
47         u32 cur = 0;
48         u32 this_len;
49         struct extent_buffer *leaf;
50
51         leaf = path->nodes[0];
52         dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
53         total_len = btrfs_item_size_nr(leaf, path->slots[0]);
54         if (verify_dir_item(root, leaf, dir_item))
55                 return NULL;
56
57         while(cur < total_len) {
58                 this_len = sizeof(*dir_item) +
59                         btrfs_dir_name_len(leaf, dir_item) +
60                         btrfs_dir_data_len(leaf, dir_item);
61                 if (this_len > (total_len - cur)) {
62                         fprintf(stderr, "invalid dir item size\n");
63                         return NULL;
64                 }
65
66                 name_ptr = (unsigned long)(dir_item + 1);
67
68                 if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
69                     memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
70                         return dir_item;
71
72                 cur += this_len;
73                 dir_item = (struct btrfs_dir_item *)((char *)dir_item +
74                                                      this_len);
75         }
76         return NULL;
77 }
78
79 struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
80                                              struct btrfs_root *root,
81                                              struct btrfs_path *path, u64 dir,
82                                              const char *name, int name_len,
83                                              int mod)
84 {
85         int ret;
86         struct btrfs_key key;
87         int ins_len = mod < 0 ? -1 : 0;
88         int cow = mod != 0;
89         struct btrfs_key found_key;
90         struct extent_buffer *leaf;
91
92         key.objectid = dir;
93         key.type = BTRFS_DIR_ITEM_KEY;
94
95         key.offset = btrfs_name_hash(name, name_len);
96
97         ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
98         if (ret < 0)
99                 return ERR_PTR(ret);
100         if (ret > 0) {
101                 if (path->slots[0] == 0)
102                         return NULL;
103                 path->slots[0]--;
104         }
105
106         leaf = path->nodes[0];
107         btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
108
109         if (found_key.objectid != dir ||
110             found_key.type != BTRFS_DIR_ITEM_KEY ||
111             found_key.offset != key.offset)
112                 return NULL;
113
114         return btrfs_match_dir_item_name(root, path, name, name_len);
115 }
116
117 int btrfs_iter_dir(struct btrfs_root *root, u64 ino,
118                    btrfs_iter_dir_callback_t callback)
119 {
120         struct btrfs_path path;
121         struct btrfs_key key;
122         int ret;
123
124         btrfs_init_path(&path);
125         key.objectid = ino;
126         key.type = BTRFS_DIR_INDEX_KEY;
127         key.offset = 0;
128
129         ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
130         if (ret < 0)
131                 return ret;
132         /* Should not happen */
133         if (ret == 0) {
134                 ret = -EUCLEAN;
135                 goto out;
136         }
137         if (path.slots[0] >= btrfs_header_nritems(path.nodes[0])) {
138                 ret = btrfs_next_leaf(root, &path);
139                 if (ret < 0)
140                         goto out;
141                 if (ret > 0) {
142                         ret = 0;
143                         goto out;
144                 }
145         }
146         do {
147                 struct btrfs_dir_item *di;
148
149                 btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
150                 if (key.objectid != ino || key.type != BTRFS_DIR_INDEX_KEY)
151                         break;
152                 di = btrfs_item_ptr(path.nodes[0], path.slots[0],
153                                     struct btrfs_dir_item);
154                 if (verify_dir_item(root, path.nodes[0], di)) {
155                         ret = -EUCLEAN;
156                         goto out;
157                 }
158                 ret = callback(root, path.nodes[0], di);
159                 if (ret < 0)
160                         goto out;
161         } while (!(ret = btrfs_next_item(root, &path)));
162
163         if (ret > 0)
164                 ret = 0;
165 out:
166         btrfs_release_path(&path);
167         return ret;
168 }