Blame view
fs/btrfs/dir-item.c
14.5 KB
6cbd55707 Btrfs: add GPLv2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ |
62e2749e0 Btrfs: Use a chun... |
18 19 20 |
#include "ctree.h" #include "disk-io.h" #include "hash.h" |
e089f05c1 Btrfs: transactio... |
21 |
#include "transaction.h" |
62e2749e0 Btrfs: Use a chun... |
22 |
|
d352ac681 Btrfs: add and im... |
23 24 25 26 27 28 29 30 |
/* * insert a name into a directory, doing overflow properly if there is a hash * collision. data_size indicates how big the item inserted should be. On * success a struct btrfs_dir_item pointer is returned, otherwise it is * an ERR_PTR. * * The name is not copied into the dir item, you have to do that yourself. */ |
35b7e4761 Btrfs: fix page c... |
31 32 33 34 35 |
static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *cpu_key, |
e06afa839 Btrfs: rename |
36 37 38 |
u32 data_size, const char *name, int name_len) |
7fcde0e32 Btrfs: finish off... |
39 |
{ |
2ff7e61e0 btrfs: take an fs... |
40 |
struct btrfs_fs_info *fs_info = root->fs_info; |
7fcde0e32 Btrfs: finish off... |
41 |
int ret; |
7e38180e2 Btrfs: directory ... |
42 43 |
char *ptr; struct btrfs_item *item; |
5f39d397d Btrfs: Create ext... |
44 |
struct extent_buffer *leaf; |
7fcde0e32 Btrfs: finish off... |
45 46 |
ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size); |
7e38180e2 Btrfs: directory ... |
47 |
if (ret == -EEXIST) { |
e06afa839 Btrfs: rename |
48 |
struct btrfs_dir_item *di; |
2ff7e61e0 btrfs: take an fs... |
49 |
di = btrfs_match_dir_item_name(fs_info, path, name, name_len); |
e06afa839 Btrfs: rename |
50 51 |
if (di) return ERR_PTR(-EEXIST); |
2ff7e61e0 btrfs: take an fs... |
52 |
btrfs_extend_item(fs_info, path, data_size); |
143bede52 btrfs: return voi... |
53 |
} else if (ret < 0) |
54aa1f4df Btrfs: Audit call... |
54 |
return ERR_PTR(ret); |
7e38180e2 Btrfs: directory ... |
55 |
WARN_ON(ret > 0); |
5f39d397d Btrfs: Create ext... |
56 |
leaf = path->nodes[0]; |
dd3cc16b8 btrfs: drop unuse... |
57 |
item = btrfs_item_nr(path->slots[0]); |
7e38180e2 Btrfs: directory ... |
58 |
ptr = btrfs_item_ptr(leaf, path->slots[0], char); |
5f39d397d Btrfs: Create ext... |
59 60 |
BUG_ON(data_size > btrfs_item_size(leaf, item)); ptr += btrfs_item_size(leaf, item) - data_size; |
7e38180e2 Btrfs: directory ... |
61 |
return (struct btrfs_dir_item *)ptr; |
7fcde0e32 Btrfs: finish off... |
62 |
} |
d352ac681 Btrfs: add and im... |
63 64 65 66 |
/* * xattrs work a lot like directories, this inserts an xattr item * into the tree */ |
5103e947b xattr support for... |
67 |
int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, |
f34f57a3a Btrfs: Pass trans... |
68 69 70 71 |
struct btrfs_root *root, struct btrfs_path *path, u64 objectid, const char *name, u16 name_len, const void *data, u16 data_len) |
5103e947b xattr support for... |
72 73 |
{ int ret = 0; |
5103e947b xattr support for... |
74 75 76 77 78 79 |
struct btrfs_dir_item *dir_item; unsigned long name_ptr, data_ptr; struct btrfs_key key, location; struct btrfs_disk_key disk_key; struct extent_buffer *leaf; u32 data_size; |
b9d04c607 btrfs: do proper ... |
80 81 |
if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root->fs_info)) return -ENOSPC; |
f34f57a3a Btrfs: Pass trans... |
82 83 |
key.objectid = objectid; |
962a298f3 btrfs: kill the k... |
84 |
key.type = BTRFS_XATTR_ITEM_KEY; |
df68b8a7a Btrfs: unaligned ... |
85 |
key.offset = btrfs_name_hash(name, name_len); |
5103e947b xattr support for... |
86 87 88 89 |
data_size = sizeof(*dir_item) + name_len + data_len; dir_item = insert_with_overflow(trans, root, path, &key, data_size, name, name_len); |
fa09200b8 Btrfs: try to onl... |
90 91 |
if (IS_ERR(dir_item)) return PTR_ERR(dir_item); |
5103e947b xattr support for... |
92 93 94 95 96 97 98 |
memset(&location, 0, sizeof(location)); leaf = path->nodes[0]; btrfs_cpu_key_to_disk(&disk_key, &location); btrfs_set_dir_item_key(leaf, dir_item, &disk_key); btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR); btrfs_set_dir_name_len(leaf, dir_item, name_len); |
e02119d5a Btrfs: Add a writ... |
99 |
btrfs_set_dir_transid(leaf, dir_item, trans->transid); |
5103e947b xattr support for... |
100 101 102 103 104 105 106 |
btrfs_set_dir_data_len(leaf, dir_item, data_len); name_ptr = (unsigned long)(dir_item + 1); data_ptr = (unsigned long)((char *)name_ptr + name_len); write_extent_buffer(leaf, name, name_ptr, name_len); write_extent_buffer(leaf, data, data_ptr, data_len); btrfs_mark_buffer_dirty(path->nodes[0]); |
5103e947b xattr support for... |
107 108 |
return ret; } |
d352ac681 Btrfs: add and im... |
109 110 111 112 113 114 |
/* * insert a directory item in the tree, doing all the magic for * both indexes. 'dir' indicates which objectid to insert it into, * 'location' is the key to stuff into the directory item, 'type' is the * type of the inode we're pointing to, and 'index' is the sequence number * to use for the second index (if one is created). |
79787eaab btrfs: replace ma... |
115 |
* Will return 0 or -ENOMEM |
d352ac681 Btrfs: add and im... |
116 |
*/ |
e089f05c1 Btrfs: transactio... |
117 |
int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root |
16cdcec73 btrfs: implement ... |
118 |
*root, const char *name, int name_len, |
8e7611cf3 btrfs: Make btrfs... |
119 |
struct btrfs_inode *dir, struct btrfs_key *location, |
16cdcec73 btrfs: implement ... |
120 |
u8 type, u64 index) |
62e2749e0 Btrfs: Use a chun... |
121 122 |
{ int ret = 0; |
e06afa839 Btrfs: rename |
123 |
int ret2 = 0; |
5caf2a002 Btrfs: dynamic al... |
124 |
struct btrfs_path *path; |
62e2749e0 Btrfs: Use a chun... |
125 |
struct btrfs_dir_item *dir_item; |
5f39d397d Btrfs: Create ext... |
126 127 |
struct extent_buffer *leaf; unsigned long name_ptr; |
62e2749e0 Btrfs: Use a chun... |
128 |
struct btrfs_key key; |
5f39d397d Btrfs: Create ext... |
129 |
struct btrfs_disk_key disk_key; |
62e2749e0 Btrfs: Use a chun... |
130 |
u32 data_size; |
8e7611cf3 btrfs: Make btrfs... |
131 |
key.objectid = btrfs_ino(dir); |
962a298f3 btrfs: kill the k... |
132 |
key.type = BTRFS_DIR_ITEM_KEY; |
df68b8a7a Btrfs: unaligned ... |
133 |
key.offset = btrfs_name_hash(name, name_len); |
b9473439d Btrfs: leave btre... |
134 |
|
5caf2a002 Btrfs: dynamic al... |
135 |
path = btrfs_alloc_path(); |
16cdcec73 btrfs: implement ... |
136 137 |
if (!path) return -ENOMEM; |
b9473439d Btrfs: leave btre... |
138 |
path->leave_spinning = 1; |
16cdcec73 btrfs: implement ... |
139 |
btrfs_cpu_key_to_disk(&disk_key, location); |
62e2749e0 Btrfs: Use a chun... |
140 |
data_size = sizeof(*dir_item) + name_len; |
e06afa839 Btrfs: rename |
141 142 |
dir_item = insert_with_overflow(trans, root, path, &key, data_size, name, name_len); |
7e38180e2 Btrfs: directory ... |
143 144 |
if (IS_ERR(dir_item)) { ret = PTR_ERR(dir_item); |
e06afa839 Btrfs: rename |
145 146 |
if (ret == -EEXIST) goto second_insert; |
c2db1073f Btrfs: check retu... |
147 |
goto out_free; |
7e38180e2 Btrfs: directory ... |
148 |
} |
62e2749e0 Btrfs: Use a chun... |
149 |
|
5f39d397d Btrfs: Create ext... |
150 |
leaf = path->nodes[0]; |
5f39d397d Btrfs: Create ext... |
151 152 |
btrfs_set_dir_item_key(leaf, dir_item, &disk_key); btrfs_set_dir_type(leaf, dir_item, type); |
5103e947b xattr support for... |
153 |
btrfs_set_dir_data_len(leaf, dir_item, 0); |
5f39d397d Btrfs: Create ext... |
154 |
btrfs_set_dir_name_len(leaf, dir_item, name_len); |
e02119d5a Btrfs: Add a writ... |
155 |
btrfs_set_dir_transid(leaf, dir_item, trans->transid); |
5f39d397d Btrfs: Create ext... |
156 |
name_ptr = (unsigned long)(dir_item + 1); |
c5739bba5 Btrfs: snapshot p... |
157 |
|
5f39d397d Btrfs: Create ext... |
158 159 |
write_extent_buffer(leaf, name, name_ptr, name_len); btrfs_mark_buffer_dirty(leaf); |
7e38180e2 Btrfs: directory ... |
160 |
|
e06afa839 Btrfs: rename |
161 |
second_insert: |
7e38180e2 Btrfs: directory ... |
162 163 164 |
/* FIXME, use some real flag for selecting the extra index */ if (root == root->fs_info->tree_root) { ret = 0; |
c2db1073f Btrfs: check retu... |
165 |
goto out_free; |
7e38180e2 Btrfs: directory ... |
166 |
} |
b3b4aa74b btrfs: drop unuse... |
167 |
btrfs_release_path(path); |
7e38180e2 Btrfs: directory ... |
168 |
|
2ff7e61e0 btrfs: take an fs... |
169 |
ret2 = btrfs_insert_delayed_dir_index(trans, root->fs_info, name, |
8e7611cf3 btrfs: Make btrfs... |
170 |
name_len, dir, &disk_key, type, index); |
c2db1073f Btrfs: check retu... |
171 |
out_free: |
5caf2a002 Btrfs: dynamic al... |
172 |
btrfs_free_path(path); |
e06afa839 Btrfs: rename |
173 174 175 176 177 |
if (ret) return ret; if (ret2) return ret2; return 0; |
62e2749e0 Btrfs: Use a chun... |
178 |
} |
d352ac681 Btrfs: add and im... |
179 180 181 182 183 |
/* * lookup a directory item based on name. 'dir' is the objectid * we're searching in, and 'mod' tells us if you plan on deleting the * item (use mod < 0) or changing the options (use mod > 0) */ |
7e38180e2 Btrfs: directory ... |
184 185 186 187 188 |
struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 dir, const char *name, int name_len, int mod) |
62e2749e0 Btrfs: Use a chun... |
189 |
{ |
1d4f6404d Btrfs: directory ... |
190 |
int ret; |
62e2749e0 Btrfs: Use a chun... |
191 |
struct btrfs_key key; |
1d4f6404d Btrfs: directory ... |
192 193 |
int ins_len = mod < 0 ? -1 : 0; int cow = mod != 0; |
62e2749e0 Btrfs: Use a chun... |
194 195 |
key.objectid = dir; |
962a298f3 btrfs: kill the k... |
196 |
key.type = BTRFS_DIR_ITEM_KEY; |
5f39d397d Btrfs: Create ext... |
197 |
|
df68b8a7a Btrfs: unaligned ... |
198 |
key.offset = btrfs_name_hash(name, name_len); |
5f39d397d Btrfs: Create ext... |
199 |
|
7e38180e2 Btrfs: directory ... |
200 201 202 |
ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); if (ret < 0) return ERR_PTR(ret); |
85d85a743 Btrfs: remove red... |
203 |
if (ret > 0) |
7e38180e2 Btrfs: directory ... |
204 |
return NULL; |
2ff7e61e0 btrfs: take an fs... |
205 |
return btrfs_match_dir_item_name(root->fs_info, path, name, name_len); |
62e2749e0 Btrfs: Use a chun... |
206 |
} |
9c52057c6 Btrfs: fix hash o... |
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir, const char *name, int name_len) { int ret; struct btrfs_key key; struct btrfs_dir_item *di; int data_size; struct extent_buffer *leaf; int slot; struct btrfs_path *path; path = btrfs_alloc_path(); if (!path) return -ENOMEM; key.objectid = dir; |
962a298f3 btrfs: kill the k... |
224 |
key.type = BTRFS_DIR_ITEM_KEY; |
9c52057c6 Btrfs: fix hash o... |
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
key.offset = btrfs_name_hash(name, name_len); ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); /* return back any errors */ if (ret < 0) goto out; /* nothing found, we're safe */ if (ret > 0) { ret = 0; goto out; } /* we found an item, look for our name in the item */ |
2ff7e61e0 btrfs: take an fs... |
240 |
di = btrfs_match_dir_item_name(root->fs_info, path, name, name_len); |
9c52057c6 Btrfs: fix hash o... |
241 242 243 244 245 246 247 248 249 250 |
if (di) { /* our exact name was found */ ret = -EEXIST; goto out; } /* * see if there is room in the item to insert this * name */ |
878f2d2cb Btrfs: fix max di... |
251 |
data_size = sizeof(*di) + name_len; |
9c52057c6 Btrfs: fix hash o... |
252 253 254 |
leaf = path->nodes[0]; slot = path->slots[0]; if (data_size + btrfs_item_size_nr(leaf, slot) + |
da17066c4 btrfs: pull node/... |
255 |
sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root->fs_info)) { |
9c52057c6 Btrfs: fix hash o... |
256 257 258 259 260 261 262 263 264 |
ret = -EOVERFLOW; } else { /* plenty of insertion room */ ret = 0; } out: btrfs_free_path(path); return ret; } |
d352ac681 Btrfs: add and im... |
265 266 267 268 269 270 271 272 |
/* * lookup a directory item based on index. 'dir' is the objectid * we're searching in, and 'mod' tells us if you plan on deleting the * item (use mod < 0) or changing the options (use mod > 0) * * The name is used to make sure the index really points to the name you were * looking for. */ |
7e38180e2 Btrfs: directory ... |
273 274 275 276 277 278 279 280 281 282 283 284 285 |
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 objectid, const char *name, int name_len, int mod) { int ret; struct btrfs_key key; int ins_len = mod < 0 ? -1 : 0; int cow = mod != 0; key.objectid = dir; |
962a298f3 btrfs: kill the k... |
286 |
key.type = BTRFS_DIR_INDEX_KEY; |
7e38180e2 Btrfs: directory ... |
287 288 289 290 291 292 293 |
key.offset = objectid; ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); if (ret < 0) return ERR_PTR(ret); if (ret > 0) return ERR_PTR(-ENOENT); |
2ff7e61e0 btrfs: take an fs... |
294 |
return btrfs_match_dir_item_name(root->fs_info, path, name, name_len); |
7e38180e2 Btrfs: directory ... |
295 |
} |
4df27c4d5 Btrfs: change how... |
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
struct btrfs_dir_item * btrfs_search_dir_index_item(struct btrfs_root *root, struct btrfs_path *path, u64 dirid, const char *name, int name_len) { struct extent_buffer *leaf; struct btrfs_dir_item *di; struct btrfs_key key; u32 nritems; int ret; key.objectid = dirid; key.type = BTRFS_DIR_INDEX_KEY; key.offset = 0; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) return ERR_PTR(ret); leaf = path->nodes[0]; nritems = btrfs_header_nritems(leaf); while (1) { if (path->slots[0] >= nritems) { ret = btrfs_next_leaf(root, path); if (ret < 0) return ERR_PTR(ret); if (ret > 0) break; leaf = path->nodes[0]; nritems = btrfs_header_nritems(leaf); continue; } btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); if (key.objectid != dirid || key.type != BTRFS_DIR_INDEX_KEY) break; |
2ff7e61e0 btrfs: take an fs... |
333 334 |
di = btrfs_match_dir_item_name(root->fs_info, path, name, name_len); |
4df27c4d5 Btrfs: change how... |
335 336 337 338 339 340 341 |
if (di) return di; path->slots[0]++; } return NULL; } |
5103e947b xattr support for... |
342 343 344 345 346 347 348 349 350 351 |
struct btrfs_dir_item *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) { int ret; struct btrfs_key key; int ins_len = mod < 0 ? -1 : 0; int cow = mod != 0; |
5103e947b xattr support for... |
352 353 |
key.objectid = dir; |
962a298f3 btrfs: kill the k... |
354 |
key.type = BTRFS_XATTR_ITEM_KEY; |
df68b8a7a Btrfs: unaligned ... |
355 |
key.offset = btrfs_name_hash(name, name_len); |
5103e947b xattr support for... |
356 357 358 |
ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); if (ret < 0) return ERR_PTR(ret); |
85d85a743 Btrfs: remove red... |
359 |
if (ret > 0) |
5103e947b xattr support for... |
360 |
return NULL; |
2ff7e61e0 btrfs: take an fs... |
361 |
return btrfs_match_dir_item_name(root->fs_info, path, name, name_len); |
5103e947b xattr support for... |
362 |
} |
d352ac681 Btrfs: add and im... |
363 364 365 366 367 |
/* * helper function to look at the directory item pointed to by 'path' * this walks through all the entries in a dir item and finds one * for a specific name. */ |
2ff7e61e0 btrfs: take an fs... |
368 |
struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info, |
5f5bc6b1e Btrfs: make xattr... |
369 370 |
struct btrfs_path *path, const char *name, int name_len) |
62e2749e0 Btrfs: Use a chun... |
371 |
{ |
62e2749e0 Btrfs: Use a chun... |
372 |
struct btrfs_dir_item *dir_item; |
5f39d397d Btrfs: Create ext... |
373 |
unsigned long name_ptr; |
7e38180e2 Btrfs: directory ... |
374 375 376 |
u32 total_len; u32 cur = 0; u32 this_len; |
5f39d397d Btrfs: Create ext... |
377 |
struct extent_buffer *leaf; |
a8a2ee0c6 Btrfs: add a name... |
378 |
|
5f39d397d Btrfs: Create ext... |
379 |
leaf = path->nodes[0]; |
7e38180e2 Btrfs: directory ... |
380 |
dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item); |
22a94d44b Btrfs: add checks... |
381 |
|
5f39d397d Btrfs: Create ext... |
382 |
total_len = btrfs_item_size_nr(leaf, path->slots[0]); |
d397712bc Btrfs: Fix checkp... |
383 |
while (cur < total_len) { |
5f39d397d Btrfs: Create ext... |
384 |
this_len = sizeof(*dir_item) + |
5103e947b xattr support for... |
385 386 |
btrfs_dir_name_len(leaf, dir_item) + btrfs_dir_data_len(leaf, dir_item); |
5f39d397d Btrfs: Create ext... |
387 |
name_ptr = (unsigned long)(dir_item + 1); |
7e38180e2 Btrfs: directory ... |
388 |
|
26a836cec btrfs: Check name... |
389 390 |
if (verify_dir_item(fs_info, leaf, path->slots[0], dir_item)) return NULL; |
5f39d397d Btrfs: Create ext... |
391 392 |
if (btrfs_dir_name_len(leaf, dir_item) == name_len && memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) |
7e38180e2 Btrfs: directory ... |
393 394 395 396 397 398 399 |
return dir_item; cur += this_len; dir_item = (struct btrfs_dir_item *)((char *)dir_item + this_len); } return NULL; |
62e2749e0 Btrfs: Use a chun... |
400 |
} |
7e38180e2 Btrfs: directory ... |
401 |
|
d352ac681 Btrfs: add and im... |
402 403 404 405 |
/* * given a pointer into a directory item, delete it. This * handles items that have more than one entry in them. */ |
7e38180e2 Btrfs: directory ... |
406 407 408 409 410 |
int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_dir_item *di) { |
5f39d397d Btrfs: Create ext... |
411 |
struct extent_buffer *leaf; |
7e38180e2 Btrfs: directory ... |
412 413 |
u32 sub_item_len; u32 item_len; |
54aa1f4df Btrfs: Audit call... |
414 |
int ret = 0; |
7e38180e2 Btrfs: directory ... |
415 |
|
5f39d397d Btrfs: Create ext... |
416 |
leaf = path->nodes[0]; |
5103e947b xattr support for... |
417 418 |
sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) + btrfs_dir_data_len(leaf, di); |
5f39d397d Btrfs: Create ext... |
419 420 |
item_len = btrfs_item_size_nr(leaf, path->slots[0]); if (sub_item_len == item_len) { |
7e38180e2 Btrfs: directory ... |
421 |
ret = btrfs_del_item(trans, root, path); |
7e38180e2 Btrfs: directory ... |
422 |
} else { |
5f39d397d Btrfs: Create ext... |
423 424 425 426 427 428 |
/* MARKER */ unsigned long ptr = (unsigned long)di; unsigned long start; start = btrfs_item_ptr_offset(leaf, path->slots[0]); memmove_extent_buffer(leaf, ptr, ptr + sub_item_len, |
7e38180e2 Btrfs: directory ... |
429 |
item_len - (ptr + sub_item_len - start)); |
2ff7e61e0 btrfs: take an fs... |
430 431 |
btrfs_truncate_item(root->fs_info, path, item_len - sub_item_len, 1); |
7e38180e2 Btrfs: directory ... |
432 |
} |
411fc6bce Btrfs: Fix variab... |
433 |
return ret; |
7e38180e2 Btrfs: directory ... |
434 |
} |
22a94d44b Btrfs: add checks... |
435 |
|
2ff7e61e0 btrfs: take an fs... |
436 |
int verify_dir_item(struct btrfs_fs_info *fs_info, |
22a94d44b Btrfs: add checks... |
437 |
struct extent_buffer *leaf, |
e79a33270 btrfs: Check name... |
438 |
int slot, |
22a94d44b Btrfs: add checks... |
439 440 441 |
struct btrfs_dir_item *dir_item) { u16 namelen = BTRFS_NAME_LEN; |
e79a33270 btrfs: Check name... |
442 |
int ret; |
22a94d44b Btrfs: add checks... |
443 444 445 |
u8 type = btrfs_dir_type(leaf, dir_item); if (type >= BTRFS_FT_MAX) { |
0b246afa6 btrfs: root->fs_i... |
446 |
btrfs_crit(fs_info, "invalid dir item type: %d", (int)type); |
22a94d44b Btrfs: add checks... |
447 448 449 450 451 452 453 |
return 1; } if (type == BTRFS_FT_XATTR) namelen = XATTR_NAME_MAX; if (btrfs_dir_name_len(leaf, dir_item) > namelen) { |
0b246afa6 btrfs: root->fs_i... |
454 |
btrfs_crit(fs_info, "invalid dir item name len: %u", |
286b92f43 btrfs: tree-log.c... |
455 |
(unsigned)btrfs_dir_name_len(leaf, dir_item)); |
22a94d44b Btrfs: add checks... |
456 457 |
return 1; } |
e79a33270 btrfs: Check name... |
458 459 460 461 462 |
namelen = btrfs_dir_name_len(leaf, dir_item); ret = btrfs_is_name_len_valid(leaf, slot, (unsigned long)(dir_item + 1), namelen); if (!ret) return 1; |
22a94d44b Btrfs: add checks... |
463 |
/* BTRFS_MAX_XATTR_SIZE is the same for all dir items */ |
e46f5388c Btrfs: fix verifi... |
464 |
if ((btrfs_dir_data_len(leaf, dir_item) + |
0b246afa6 btrfs: root->fs_i... |
465 466 467 |
btrfs_dir_name_len(leaf, dir_item)) > BTRFS_MAX_XATTR_SIZE(fs_info)) { btrfs_crit(fs_info, "invalid dir item name + data len: %u + %u", |
5d163e0e6 btrfs: unsplit pr... |
468 469 |
(unsigned)btrfs_dir_name_len(leaf, dir_item), (unsigned)btrfs_dir_data_len(leaf, dir_item)); |
22a94d44b Btrfs: add checks... |
470 471 472 473 474 |
return 1; } return 0; } |
19c6dcbfa btrfs: Introduce ... |
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 |
bool btrfs_is_name_len_valid(struct extent_buffer *leaf, int slot, unsigned long start, u16 name_len) { struct btrfs_fs_info *fs_info = leaf->fs_info; struct btrfs_key key; u32 read_start; u32 read_end; u32 item_start; u32 item_end; u32 size; bool ret = true; ASSERT(start > BTRFS_LEAF_DATA_OFFSET); read_start = start - BTRFS_LEAF_DATA_OFFSET; read_end = read_start + name_len; item_start = btrfs_item_offset_nr(leaf, slot); item_end = btrfs_item_end_nr(leaf, slot); btrfs_item_key_to_cpu(leaf, &key, slot); switch (key.type) { case BTRFS_DIR_ITEM_KEY: case BTRFS_XATTR_ITEM_KEY: case BTRFS_DIR_INDEX_KEY: size = sizeof(struct btrfs_dir_item); break; case BTRFS_INODE_REF_KEY: size = sizeof(struct btrfs_inode_ref); break; case BTRFS_INODE_EXTREF_KEY: size = sizeof(struct btrfs_inode_extref); break; case BTRFS_ROOT_REF_KEY: case BTRFS_ROOT_BACKREF_KEY: size = sizeof(struct btrfs_root_ref); break; default: ret = false; goto out; } if (read_start < item_start) { ret = false; goto out; } if (read_end > item_end) { ret = false; goto out; } /* there shall be item(s) before name */ if (read_start - item_start < size) { ret = false; goto out; } |
19c6dcbfa btrfs: Introduce ... |
532 533 534 535 536 537 |
out: if (!ret) btrfs_crit(fs_info, "invalid dir item name len: %u", (unsigned int)name_len); return ret; } |