]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
21a14fac MB |
2 | /* |
3 | * BTRFS filesystem implementation for U-Boot | |
4 | * | |
5 | * 2017 Marek Behun, CZ.NIC, [email protected] | |
21a14fac MB |
6 | */ |
7 | ||
8 | #include "btrfs.h" | |
565a4147 | 9 | #include "disk-io.h" |
21a14fac | 10 | |
c921aa20 QW |
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 | ||
325dd1f6 QW |
117 | int btrfs_iter_dir(struct btrfs_root *root, u64 ino, |
118 | btrfs_iter_dir_callback_t callback) | |
21a14fac | 119 | { |
325dd1f6 QW |
120 | struct btrfs_path path; |
121 | struct btrfs_key key; | |
122 | int ret; | |
21a14fac | 123 | |
325dd1f6 QW |
124 | btrfs_init_path(&path); |
125 | key.objectid = ino; | |
21a14fac MB |
126 | key.type = BTRFS_DIR_INDEX_KEY; |
127 | key.offset = 0; | |
128 | ||
325dd1f6 QW |
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 | } | |
21a14fac | 146 | do { |
325dd1f6 | 147 | struct btrfs_dir_item *di; |
21a14fac | 148 | |
325dd1f6 QW |
149 | btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]); |
150 | if (key.objectid != ino || key.type != BTRFS_DIR_INDEX_KEY) | |
21a14fac | 151 | break; |
325dd1f6 QW |
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))); | |
21a14fac | 162 | |
325dd1f6 QW |
163 | if (ret > 0) |
164 | ret = 0; | |
165 | out: | |
166 | btrfs_release_path(&path); | |
167 | return ret; | |
21a14fac | 168 | } |