1 /* 2 * Copyright (C) 2007 Oracle. All rights reserved. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public 6 * License v2 as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public 14 * License along with this program; if not, write to the 15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 16 * Boston, MA 021110-1307, USA. 17 */ 18 19 #include "ctree.h" 20 #include "disk-io.h" 21 #include "hash.h" 22 #include "transaction.h" 23 24 /* 25 * insert a name into a directory, doing overflow properly if there is a hash 26 * collision. data_size indicates how big the item inserted should be. On 27 * success a struct btrfs_dir_item pointer is returned, otherwise it is 28 * an ERR_PTR. 29 * 30 * The name is not copied into the dir item, you have to do that yourself. 31 */ 32 static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle 33 *trans, 34 struct btrfs_root *root, 35 struct btrfs_path *path, 36 struct btrfs_key *cpu_key, 37 u32 data_size, 38 const char *name, 39 int name_len) 40 { 41 int ret; 42 char *ptr; 43 struct btrfs_item *item; 44 struct extent_buffer *leaf; 45 46 ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size); 47 if (ret == -EEXIST) { 48 struct btrfs_dir_item *di; 49 di = btrfs_match_dir_item_name(root, path, name, name_len); 50 if (di) 51 return ERR_PTR(-EEXIST); 52 ret = btrfs_extend_item(trans, root, path, data_size); 53 WARN_ON(ret > 0); 54 } 55 if (ret < 0) 56 return ERR_PTR(ret); 57 WARN_ON(ret > 0); 58 leaf = path->nodes[0]; 59 item = btrfs_item_nr(leaf, path->slots[0]); 60 ptr = btrfs_item_ptr(leaf, path->slots[0], char); 61 BUG_ON(data_size > btrfs_item_size(leaf, item)); 62 ptr += btrfs_item_size(leaf, item) - data_size; 63 return (struct btrfs_dir_item *)ptr; 64 } 65 66 /* 67 * xattrs work a lot like directories, this inserts an xattr item 68 * into the tree 69 */ 70 int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, 71 struct btrfs_root *root, const char *name, 72 u16 name_len, const void *data, u16 data_len, 73 u64 dir) 74 { 75 int ret = 0; 76 struct btrfs_path *path; 77 struct btrfs_dir_item *dir_item; 78 unsigned long name_ptr, data_ptr; 79 struct btrfs_key key, location; 80 struct btrfs_disk_key disk_key; 81 struct extent_buffer *leaf; 82 u32 data_size; 83 84 key.objectid = dir; 85 btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY); 86 key.offset = btrfs_name_hash(name, name_len); 87 path = btrfs_alloc_path(); 88 if (!path) 89 return -ENOMEM; 90 if (name_len + data_len + sizeof(struct btrfs_dir_item) > 91 BTRFS_LEAF_DATA_SIZE(root) - sizeof(struct btrfs_item)) 92 return -ENOSPC; 93 94 data_size = sizeof(*dir_item) + name_len + data_len; 95 dir_item = insert_with_overflow(trans, root, path, &key, data_size, 96 name, name_len); 97 /* 98 * FIXME: at some point we should handle xattr's that are larger than 99 * what we can fit in our leaf. We set location to NULL b/c we arent 100 * pointing at anything else, that will change if we store the xattr 101 * data in a separate inode. 102 */ 103 BUG_ON(IS_ERR(dir_item)); 104 memset(&location, 0, sizeof(location)); 105 106 leaf = path->nodes[0]; 107 btrfs_cpu_key_to_disk(&disk_key, &location); 108 btrfs_set_dir_item_key(leaf, dir_item, &disk_key); 109 btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR); 110 btrfs_set_dir_name_len(leaf, dir_item, name_len); 111 btrfs_set_dir_transid(leaf, dir_item, trans->transid); 112 btrfs_set_dir_data_len(leaf, dir_item, data_len); 113 name_ptr = (unsigned long)(dir_item + 1); 114 data_ptr = (unsigned long)((char *)name_ptr + name_len); 115 116 write_extent_buffer(leaf, name, name_ptr, name_len); 117 write_extent_buffer(leaf, data, data_ptr, data_len); 118 btrfs_mark_buffer_dirty(path->nodes[0]); 119 120 btrfs_free_path(path); 121 return ret; 122 } 123 124 /* 125 * insert a directory item in the tree, doing all the magic for 126 * both indexes. 'dir' indicates which objectid to insert it into, 127 * 'location' is the key to stuff into the directory item, 'type' is the 128 * type of the inode we're pointing to, and 'index' is the sequence number 129 * to use for the second index (if one is created). 130 */ 131 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root 132 *root, const char *name, int name_len, u64 dir, 133 struct btrfs_key *location, u8 type, u64 index) 134 { 135 int ret = 0; 136 int ret2 = 0; 137 struct btrfs_path *path; 138 struct btrfs_dir_item *dir_item; 139 struct extent_buffer *leaf; 140 unsigned long name_ptr; 141 struct btrfs_key key; 142 struct btrfs_disk_key disk_key; 143 u32 data_size; 144 145 key.objectid = dir; 146 btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); 147 key.offset = btrfs_name_hash(name, name_len); 148 149 path = btrfs_alloc_path(); 150 path->leave_spinning = 1; 151 152 data_size = sizeof(*dir_item) + name_len; 153 dir_item = insert_with_overflow(trans, root, path, &key, data_size, 154 name, name_len); 155 if (IS_ERR(dir_item)) { 156 ret = PTR_ERR(dir_item); 157 if (ret == -EEXIST) 158 goto second_insert; 159 goto out; 160 } 161 162 leaf = path->nodes[0]; 163 btrfs_cpu_key_to_disk(&disk_key, location); 164 btrfs_set_dir_item_key(leaf, dir_item, &disk_key); 165 btrfs_set_dir_type(leaf, dir_item, type); 166 btrfs_set_dir_data_len(leaf, dir_item, 0); 167 btrfs_set_dir_name_len(leaf, dir_item, name_len); 168 btrfs_set_dir_transid(leaf, dir_item, trans->transid); 169 name_ptr = (unsigned long)(dir_item + 1); 170 171 write_extent_buffer(leaf, name, name_ptr, name_len); 172 btrfs_mark_buffer_dirty(leaf); 173 174 second_insert: 175 /* FIXME, use some real flag for selecting the extra index */ 176 if (root == root->fs_info->tree_root) { 177 ret = 0; 178 goto out; 179 } 180 btrfs_release_path(root, path); 181 182 btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY); 183 key.offset = index; 184 dir_item = insert_with_overflow(trans, root, path, &key, data_size, 185 name, name_len); 186 if (IS_ERR(dir_item)) { 187 ret2 = PTR_ERR(dir_item); 188 goto out; 189 } 190 leaf = path->nodes[0]; 191 btrfs_cpu_key_to_disk(&disk_key, location); 192 btrfs_set_dir_item_key(leaf, dir_item, &disk_key); 193 btrfs_set_dir_type(leaf, dir_item, type); 194 btrfs_set_dir_data_len(leaf, dir_item, 0); 195 btrfs_set_dir_name_len(leaf, dir_item, name_len); 196 btrfs_set_dir_transid(leaf, dir_item, trans->transid); 197 name_ptr = (unsigned long)(dir_item + 1); 198 write_extent_buffer(leaf, name, name_ptr, name_len); 199 btrfs_mark_buffer_dirty(leaf); 200 out: 201 btrfs_free_path(path); 202 if (ret) 203 return ret; 204 if (ret2) 205 return ret2; 206 return 0; 207 } 208 209 /* 210 * lookup a directory item based on name. 'dir' is the objectid 211 * we're searching in, and 'mod' tells us if you plan on deleting the 212 * item (use mod < 0) or changing the options (use mod > 0) 213 */ 214 struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, 215 struct btrfs_root *root, 216 struct btrfs_path *path, u64 dir, 217 const char *name, int name_len, 218 int mod) 219 { 220 int ret; 221 struct btrfs_key key; 222 int ins_len = mod < 0 ? -1 : 0; 223 int cow = mod != 0; 224 struct btrfs_key found_key; 225 struct extent_buffer *leaf; 226 227 key.objectid = dir; 228 btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); 229 230 key.offset = btrfs_name_hash(name, name_len); 231 232 ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); 233 if (ret < 0) 234 return ERR_PTR(ret); 235 if (ret > 0) { 236 if (path->slots[0] == 0) 237 return NULL; 238 path->slots[0]--; 239 } 240 241 leaf = path->nodes[0]; 242 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 243 244 if (found_key.objectid != dir || 245 btrfs_key_type(&found_key) != BTRFS_DIR_ITEM_KEY || 246 found_key.offset != key.offset) 247 return NULL; 248 249 return btrfs_match_dir_item_name(root, path, name, name_len); 250 } 251 252 /* 253 * lookup a directory item based on index. 'dir' is the objectid 254 * we're searching in, and 'mod' tells us if you plan on deleting the 255 * item (use mod < 0) or changing the options (use mod > 0) 256 * 257 * The name is used to make sure the index really points to the name you were 258 * looking for. 259 */ 260 struct btrfs_dir_item * 261 btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans, 262 struct btrfs_root *root, 263 struct btrfs_path *path, u64 dir, 264 u64 objectid, const char *name, int name_len, 265 int mod) 266 { 267 int ret; 268 struct btrfs_key key; 269 int ins_len = mod < 0 ? -1 : 0; 270 int cow = mod != 0; 271 272 key.objectid = dir; 273 btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY); 274 key.offset = objectid; 275 276 ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); 277 if (ret < 0) 278 return ERR_PTR(ret); 279 if (ret > 0) 280 return ERR_PTR(-ENOENT); 281 return btrfs_match_dir_item_name(root, path, name, name_len); 282 } 283 284 struct btrfs_dir_item * 285 btrfs_search_dir_index_item(struct btrfs_root *root, 286 struct btrfs_path *path, u64 dirid, 287 const char *name, int name_len) 288 { 289 struct extent_buffer *leaf; 290 struct btrfs_dir_item *di; 291 struct btrfs_key key; 292 u32 nritems; 293 int ret; 294 295 key.objectid = dirid; 296 key.type = BTRFS_DIR_INDEX_KEY; 297 key.offset = 0; 298 299 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); 300 if (ret < 0) 301 return ERR_PTR(ret); 302 303 leaf = path->nodes[0]; 304 nritems = btrfs_header_nritems(leaf); 305 306 while (1) { 307 if (path->slots[0] >= nritems) { 308 ret = btrfs_next_leaf(root, path); 309 if (ret < 0) 310 return ERR_PTR(ret); 311 if (ret > 0) 312 break; 313 leaf = path->nodes[0]; 314 nritems = btrfs_header_nritems(leaf); 315 continue; 316 } 317 318 btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); 319 if (key.objectid != dirid || key.type != BTRFS_DIR_INDEX_KEY) 320 break; 321 322 di = btrfs_match_dir_item_name(root, path, name, name_len); 323 if (di) 324 return di; 325 326 path->slots[0]++; 327 } 328 return NULL; 329 } 330 331 struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, 332 struct btrfs_root *root, 333 struct btrfs_path *path, u64 dir, 334 const char *name, u16 name_len, 335 int mod) 336 { 337 int ret; 338 struct btrfs_key key; 339 int ins_len = mod < 0 ? -1 : 0; 340 int cow = mod != 0; 341 struct btrfs_key found_key; 342 struct extent_buffer *leaf; 343 344 key.objectid = dir; 345 btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY); 346 key.offset = btrfs_name_hash(name, name_len); 347 ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); 348 if (ret < 0) 349 return ERR_PTR(ret); 350 if (ret > 0) { 351 if (path->slots[0] == 0) 352 return NULL; 353 path->slots[0]--; 354 } 355 356 leaf = path->nodes[0]; 357 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 358 359 if (found_key.objectid != dir || 360 btrfs_key_type(&found_key) != BTRFS_XATTR_ITEM_KEY || 361 found_key.offset != key.offset) 362 return NULL; 363 364 return btrfs_match_dir_item_name(root, path, name, name_len); 365 } 366 367 /* 368 * helper function to look at the directory item pointed to by 'path' 369 * this walks through all the entries in a dir item and finds one 370 * for a specific name. 371 */ 372 struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, 373 struct btrfs_path *path, 374 const char *name, int name_len) 375 { 376 struct btrfs_dir_item *dir_item; 377 unsigned long name_ptr; 378 u32 total_len; 379 u32 cur = 0; 380 u32 this_len; 381 struct extent_buffer *leaf; 382 383 leaf = path->nodes[0]; 384 dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item); 385 total_len = btrfs_item_size_nr(leaf, path->slots[0]); 386 while (cur < total_len) { 387 this_len = sizeof(*dir_item) + 388 btrfs_dir_name_len(leaf, dir_item) + 389 btrfs_dir_data_len(leaf, dir_item); 390 name_ptr = (unsigned long)(dir_item + 1); 391 392 if (btrfs_dir_name_len(leaf, dir_item) == name_len && 393 memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) 394 return dir_item; 395 396 cur += this_len; 397 dir_item = (struct btrfs_dir_item *)((char *)dir_item + 398 this_len); 399 } 400 return NULL; 401 } 402 403 /* 404 * given a pointer into a directory item, delete it. This 405 * handles items that have more than one entry in them. 406 */ 407 int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, 408 struct btrfs_root *root, 409 struct btrfs_path *path, 410 struct btrfs_dir_item *di) 411 { 412 413 struct extent_buffer *leaf; 414 u32 sub_item_len; 415 u32 item_len; 416 int ret = 0; 417 418 leaf = path->nodes[0]; 419 sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) + 420 btrfs_dir_data_len(leaf, di); 421 item_len = btrfs_item_size_nr(leaf, path->slots[0]); 422 if (sub_item_len == item_len) { 423 ret = btrfs_del_item(trans, root, path); 424 } else { 425 /* MARKER */ 426 unsigned long ptr = (unsigned long)di; 427 unsigned long start; 428 429 start = btrfs_item_ptr_offset(leaf, path->slots[0]); 430 memmove_extent_buffer(leaf, ptr, ptr + sub_item_len, 431 item_len - (ptr + sub_item_len - start)); 432 ret = btrfs_truncate_item(trans, root, path, 433 item_len - sub_item_len, 1); 434 } 435 return 0; 436 } 437