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 */ 32static 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 */ 70int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, 71 struct btrfs_root *root, 72 struct btrfs_path *path, u64 objectid, 73 const char *name, u16 name_len, 74 const void *data, u16 data_len) 75{ 76 int ret = 0; 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 BUG_ON(name_len + data_len > BTRFS_MAX_XATTR_SIZE(root)); 85 86 key.objectid = objectid; 87 btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY); 88 key.offset = btrfs_name_hash(name, name_len); 89 90 data_size = sizeof(*dir_item) + name_len + data_len; 91 dir_item = insert_with_overflow(trans, root, path, &key, data_size, 92 name, name_len); 93 BUG_ON(IS_ERR(dir_item)); 94 memset(&location, 0, sizeof(location)); 95 96 leaf = path->nodes[0]; 97 btrfs_cpu_key_to_disk(&disk_key, &location); 98 btrfs_set_dir_item_key(leaf, dir_item, &disk_key); 99 btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR); 100 btrfs_set_dir_name_len(leaf, dir_item, name_len); 101 btrfs_set_dir_transid(leaf, dir_item, trans->transid); 102 btrfs_set_dir_data_len(leaf, dir_item, data_len); 103 name_ptr = (unsigned long)(dir_item + 1); 104 data_ptr = (unsigned long)((char *)name_ptr + name_len); 105 106 write_extent_buffer(leaf, name, name_ptr, name_len); 107 write_extent_buffer(leaf, data, data_ptr, data_len); 108 btrfs_mark_buffer_dirty(path->nodes[0]); 109 110 return ret; 111} 112 113/* 114 * insert a directory item in the tree, doing all the magic for 115 * both indexes. 'dir' indicates which objectid to insert it into, 116 * 'location' is the key to stuff into the directory item, 'type' is the 117 * type of the inode we're pointing to, and 'index' is the sequence number 118 * to use for the second index (if one is created). 119 */ 120int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root 121 *root, const char *name, int name_len, u64 dir, 122 struct btrfs_key *location, u8 type, u64 index) 123{ 124 int ret = 0; 125 int ret2 = 0; 126 struct btrfs_path *path; 127 struct btrfs_dir_item *dir_item; 128 struct extent_buffer *leaf; 129 unsigned long name_ptr; 130 struct btrfs_key key; 131 struct btrfs_disk_key disk_key; 132 u32 data_size; 133 134 key.objectid = dir; 135 btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); 136 key.offset = btrfs_name_hash(name, name_len); 137 138 path = btrfs_alloc_path(); 139 path->leave_spinning = 1; 140 141 data_size = sizeof(*dir_item) + name_len; 142 dir_item = insert_with_overflow(trans, root, path, &key, data_size, 143 name, name_len); 144 if (IS_ERR(dir_item)) { 145 ret = PTR_ERR(dir_item); 146 if (ret == -EEXIST) 147 goto second_insert; 148 goto out; 149 } 150 151 leaf = path->nodes[0]; 152 btrfs_cpu_key_to_disk(&disk_key, location); 153 btrfs_set_dir_item_key(leaf, dir_item, &disk_key); 154 btrfs_set_dir_type(leaf, dir_item, type); 155 btrfs_set_dir_data_len(leaf, dir_item, 0); 156 btrfs_set_dir_name_len(leaf, dir_item, name_len); 157 btrfs_set_dir_transid(leaf, dir_item, trans->transid); 158 name_ptr = (unsigned long)(dir_item + 1); 159 160 write_extent_buffer(leaf, name, name_ptr, name_len); 161 btrfs_mark_buffer_dirty(leaf); 162 163second_insert: 164 if (root == root->fs_info->tree_root) { 165 ret = 0; 166 goto out; 167 } 168 btrfs_release_path(root, path); 169 170 btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY); 171 key.offset = index; 172 dir_item = insert_with_overflow(trans, root, path, &key, data_size, 173 name, name_len); 174 if (IS_ERR(dir_item)) { 175 ret2 = PTR_ERR(dir_item); 176 goto out; 177 } 178 leaf = path->nodes[0]; 179 btrfs_cpu_key_to_disk(&disk_key, location); 180 btrfs_set_dir_item_key(leaf, dir_item, &disk_key); 181 btrfs_set_dir_type(leaf, dir_item, type); 182 btrfs_set_dir_data_len(leaf, dir_item, 0); 183 btrfs_set_dir_name_len(leaf, dir_item, name_len); 184 btrfs_set_dir_transid(leaf, dir_item, trans->transid); 185 name_ptr = (unsigned long)(dir_item + 1); 186 write_extent_buffer(leaf, name, name_ptr, name_len); 187 btrfs_mark_buffer_dirty(leaf); 188out: 189 btrfs_free_path(path); 190 if (ret) 191 return ret; 192 if (ret2) 193 return ret2; 194 return 0; 195} 196 197/* 198 * lookup a directory item based on name. 'dir' is the objectid 199 * we're searching in, and 'mod' tells us if you plan on deleting the 200 * item (use mod < 0) or changing the options (use mod > 0) 201 */ 202struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, 203 struct btrfs_root *root, 204 struct btrfs_path *path, u64 dir, 205 const char *name, int name_len, 206 int mod) 207{ 208 int ret; 209 struct btrfs_key key; 210 int ins_len = mod < 0 ? -1 : 0; 211 int cow = mod != 0; 212 struct btrfs_key found_key; 213 struct extent_buffer *leaf; 214 215 key.objectid = dir; 216 btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); 217 218 key.offset = btrfs_name_hash(name, name_len); 219 220 ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); 221 if (ret < 0) 222 return ERR_PTR(ret); 223 if (ret > 0) { 224 if (path->slots[0] == 0) 225 return NULL; 226 path->slots[0]--; 227 } 228 229 leaf = path->nodes[0]; 230 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 231 232 if (found_key.objectid != dir || 233 btrfs_key_type(&found_key) != BTRFS_DIR_ITEM_KEY || 234 found_key.offset != key.offset) 235 return NULL; 236 237 return btrfs_match_dir_item_name(root, path, name, name_len); 238} 239 240/* 241 * lookup a directory item based on index. 'dir' is the objectid 242 * we're searching in, and 'mod' tells us if you plan on deleting the 243 * item (use mod < 0) or changing the options (use mod > 0) 244 * 245 * The name is used to make sure the index really points to the name you were 246 * looking for. 247 */ 248struct btrfs_dir_item * 249btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans, 250 struct btrfs_root *root, 251 struct btrfs_path *path, u64 dir, 252 u64 objectid, const char *name, int name_len, 253 int mod) 254{ 255 int ret; 256 struct btrfs_key key; 257 int ins_len = mod < 0 ? -1 : 0; 258 int cow = mod != 0; 259 260 key.objectid = dir; 261 btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY); 262 key.offset = objectid; 263 264 ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); 265 if (ret < 0) 266 return ERR_PTR(ret); 267 if (ret > 0) 268 return ERR_PTR(-ENOENT); 269 return btrfs_match_dir_item_name(root, path, name, name_len); 270} 271 272struct btrfs_dir_item * 273btrfs_search_dir_index_item(struct btrfs_root *root, 274 struct btrfs_path *path, u64 dirid, 275 const char *name, int name_len) 276{ 277 struct extent_buffer *leaf; 278 struct btrfs_dir_item *di; 279 struct btrfs_key key; 280 u32 nritems; 281 int ret; 282 283 key.objectid = dirid; 284 key.type = BTRFS_DIR_INDEX_KEY; 285 key.offset = 0; 286 287 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); 288 if (ret < 0) 289 return ERR_PTR(ret); 290 291 leaf = path->nodes[0]; 292 nritems = btrfs_header_nritems(leaf); 293 294 while (1) { 295 if (path->slots[0] >= nritems) { 296 ret = btrfs_next_leaf(root, path); 297 if (ret < 0) 298 return ERR_PTR(ret); 299 if (ret > 0) 300 break; 301 leaf = path->nodes[0]; 302 nritems = btrfs_header_nritems(leaf); 303 continue; 304 } 305 306 btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); 307 if (key.objectid != dirid || key.type != BTRFS_DIR_INDEX_KEY) 308 break; 309 310 di = btrfs_match_dir_item_name(root, path, name, name_len); 311 if (di) 312 return di; 313 314 path->slots[0]++; 315 } 316 return NULL; 317} 318 319struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, 320 struct btrfs_root *root, 321 struct btrfs_path *path, u64 dir, 322 const char *name, u16 name_len, 323 int mod) 324{ 325 int ret; 326 struct btrfs_key key; 327 int ins_len = mod < 0 ? -1 : 0; 328 int cow = mod != 0; 329 struct btrfs_key found_key; 330 struct extent_buffer *leaf; 331 332 key.objectid = dir; 333 btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY); 334 key.offset = btrfs_name_hash(name, name_len); 335 ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); 336 if (ret < 0) 337 return ERR_PTR(ret); 338 if (ret > 0) { 339 if (path->slots[0] == 0) 340 return NULL; 341 path->slots[0]--; 342 } 343 344 leaf = path->nodes[0]; 345 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 346 347 if (found_key.objectid != dir || 348 btrfs_key_type(&found_key) != BTRFS_XATTR_ITEM_KEY || 349 found_key.offset != key.offset) 350 return NULL; 351 352 return btrfs_match_dir_item_name(root, path, name, name_len); 353} 354 355/* 356 * helper function to look at the directory item pointed to by 'path' 357 * this walks through all the entries in a dir item and finds one 358 * for a specific name. 359 */ 360struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, 361 struct btrfs_path *path, 362 const char *name, int name_len) 363{ 364 struct btrfs_dir_item *dir_item; 365 unsigned long name_ptr; 366 u32 total_len; 367 u32 cur = 0; 368 u32 this_len; 369 struct extent_buffer *leaf; 370 371 leaf = path->nodes[0]; 372 dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item); 373 total_len = btrfs_item_size_nr(leaf, path->slots[0]); 374 while (cur < total_len) { 375 this_len = sizeof(*dir_item) + 376 btrfs_dir_name_len(leaf, dir_item) + 377 btrfs_dir_data_len(leaf, dir_item); 378 name_ptr = (unsigned long)(dir_item + 1); 379 380 if (btrfs_dir_name_len(leaf, dir_item) == name_len && 381 memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) 382 return dir_item; 383 384 cur += this_len; 385 dir_item = (struct btrfs_dir_item *)((char *)dir_item + 386 this_len); 387 } 388 return NULL; 389} 390 391/* 392 * given a pointer into a directory item, delete it. This 393 * handles items that have more than one entry in them. 394 */ 395int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, 396 struct btrfs_root *root, 397 struct btrfs_path *path, 398 struct btrfs_dir_item *di) 399{ 400 401 struct extent_buffer *leaf; 402 u32 sub_item_len; 403 u32 item_len; 404 int ret = 0; 405 406 leaf = path->nodes[0]; 407 sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) + 408 btrfs_dir_data_len(leaf, di); 409 item_len = btrfs_item_size_nr(leaf, path->slots[0]); 410 if (sub_item_len == item_len) { 411 ret = btrfs_del_item(trans, root, path); 412 } else { 413 /* MARKER */ 414 unsigned long ptr = (unsigned long)di; 415 unsigned long start; 416 417 start = btrfs_item_ptr_offset(leaf, path->slots[0]); 418 memmove_extent_buffer(leaf, ptr, ptr + sub_item_len, 419 item_len - (ptr + sub_item_len - start)); 420 ret = btrfs_truncate_item(trans, root, path, 421 item_len - sub_item_len, 1); 422 } 423 return 0; 424} 425