1 /** 2 * index.c - NTFS index handling. Originated from the Linux-NTFS project. 3 * 4 * Copyright (c) 2004-2005 Anton Altaparmakov 5 * Copyright (c) 2004-2005 Richard Russon 6 * Copyright (c) 2005-2006 Yura Pakhuchiy 7 * Copyright (c) 2005-2006 Szabolcs Szakacsits 8 * 9 * This program/include file is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License as published 11 * by the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program/include file is distributed in the hope that it will be 15 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 16 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program (in the main directory of the NTFS-3G 21 * distribution in the file COPYING); if not, write to the Free Software 22 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 */ 24 25 #ifdef HAVE_CONFIG_H 26 #include "config.h" 27 #endif 28 29 #ifdef HAVE_STDLIB_H 30 #include <stdlib.h> 31 #endif 32 #ifdef HAVE_STRING_H 33 #include <string.h> 34 #endif 35 #ifdef HAVE_ERRNO_H 36 #include <errno.h> 37 #endif 38 39 #include "attrib.h" 40 #include "collate.h" 41 #include "debug.h" 42 #include "index.h" 43 #include "mst.h" 44 #include "dir.h" 45 #include "logging.h" 46 #include "bitmap.h" 47 #include "misc.h" 48 49 /** 50 * ntfs_index_entry_mark_dirty - mark an index entry dirty 51 * @ictx: ntfs index context describing the index entry 52 * 53 * Mark the index entry described by the index entry context @ictx dirty. 54 * 55 * If the index entry is in the index root attribute, simply mark the inode 56 * containing the index root attribute dirty. This ensures the mftrecord, and 57 * hence the index root attribute, will be written out to disk later. 58 * 59 * If the index entry is in an index block belonging to the index allocation 60 * attribute, set ib_dirty to TRUE, thus index block will be updated during 61 * ntfs_index_ctx_put. 62 */ 63 void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx) 64 { 65 if (ictx->is_in_root) 66 ntfs_inode_mark_dirty(ictx->actx->ntfs_ino); 67 else 68 ictx->ib_dirty = TRUE; 69 } 70 71 static s64 ntfs_ib_vcn_to_pos(ntfs_index_context *icx, VCN vcn) 72 { 73 return vcn << icx->vcn_size_bits; 74 } 75 76 static VCN ntfs_ib_pos_to_vcn(ntfs_index_context *icx, s64 pos) 77 { 78 return pos >> icx->vcn_size_bits; 79 } 80 81 static int ntfs_ib_write(ntfs_index_context *icx, VCN vcn, void *buf) 82 { 83 s64 ret; 84 85 ntfs_log_trace("vcn: %lld\n", vcn); 86 87 ret = ntfs_attr_mst_pwrite(icx->ia_na, ntfs_ib_vcn_to_pos(icx, vcn), 88 1, icx->block_size, buf); 89 if (ret != 1) { 90 ntfs_log_perror("Failed to write index block %lld of inode " 91 "%llu", (long long)vcn, 92 (unsigned long long)icx->ni->mft_no); 93 return STATUS_ERROR; 94 } 95 96 return STATUS_OK; 97 } 98 99 static int ntfs_icx_ib_write(ntfs_index_context *icx) 100 { 101 if (ntfs_ib_write(icx, icx->ib_vcn, icx->ib)) 102 return STATUS_ERROR; 103 104 icx->ib_dirty = FALSE; 105 106 return STATUS_OK; 107 } 108 109 /** 110 * ntfs_index_ctx_get - allocate and initialize a new index context 111 * @ni: ntfs inode with which to initialize the context 112 * @name: name of the which context describes 113 * @name_len: length of the index name 114 * 115 * Allocate a new index context, initialize it with @ni and return it. 116 * Return NULL if allocation failed. 117 */ 118 ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni, 119 ntfschar *name, u32 name_len) 120 { 121 ntfs_index_context *icx; 122 123 ntfs_log_trace("Entering\n"); 124 125 if (!ni) { 126 errno = EINVAL; 127 return NULL; 128 } 129 if (ni->nr_extents == -1) 130 ni = ni->base_ni; 131 icx = ntfs_calloc(sizeof(ntfs_index_context)); 132 if (icx) 133 *icx = (ntfs_index_context) { 134 .ni = ni, 135 .name = name, 136 .name_len = name_len, 137 }; 138 return icx; 139 } 140 141 static void ntfs_index_ctx_free(ntfs_index_context *icx) 142 { 143 ntfs_log_trace("Entering\n"); 144 145 if (!icx->entry) 146 return; 147 148 if (icx->actx) 149 ntfs_attr_put_search_ctx(icx->actx); 150 151 if (icx->is_in_root) { 152 if (icx->ia_na) 153 ntfs_attr_close(icx->ia_na); 154 return; 155 } 156 157 if (icx->ib_dirty) { 158 /* FIXME: Error handling!!! */ 159 ntfs_ib_write(icx, icx->ib_vcn, icx->ib); 160 } 161 162 free(icx->ib); 163 ntfs_attr_close(icx->ia_na); 164 } 165 166 /** 167 * ntfs_index_ctx_put - release an index context 168 * @icx: index context to free 169 * 170 * Release the index context @icx, releasing all associated resources. 171 */ 172 void ntfs_index_ctx_put(ntfs_index_context *icx) 173 { 174 ntfs_index_ctx_free(icx); 175 free(icx); 176 } 177 178 /** 179 * ntfs_index_ctx_reinit - reinitialize an index context 180 * @icx: index context to reinitialize 181 * 182 * Reinitialize the index context @icx so it can be used for ntfs_index_lookup. 183 */ 184 void ntfs_index_ctx_reinit(ntfs_index_context *icx) 185 { 186 ntfs_log_trace("Entering\n"); 187 188 ntfs_index_ctx_free(icx); 189 190 *icx = (ntfs_index_context) { 191 .ni = icx->ni, 192 .name = icx->name, 193 .name_len = icx->name_len, 194 }; 195 } 196 197 static VCN *ntfs_ie_get_vcn_addr(INDEX_ENTRY *ie) 198 { 199 return (VCN *)((u8 *)ie + le16_to_cpu(ie->length) - sizeof(VCN)); 200 } 201 202 /** 203 * Get the subnode vcn to which the index entry refers. 204 */ 205 VCN ntfs_ie_get_vcn(INDEX_ENTRY *ie) 206 { 207 return sle64_to_cpup(ntfs_ie_get_vcn_addr(ie)); 208 } 209 210 static INDEX_ENTRY *ntfs_ie_get_first(INDEX_HEADER *ih) 211 { 212 return (INDEX_ENTRY *)((u8 *)ih + le32_to_cpu(ih->entries_offset)); 213 } 214 215 static INDEX_ENTRY *ntfs_ie_get_next(INDEX_ENTRY *ie) 216 { 217 return (INDEX_ENTRY *)((char *)ie + le16_to_cpu(ie->length)); 218 } 219 220 static u8 *ntfs_ie_get_end(INDEX_HEADER *ih) 221 { 222 /* FIXME: check if it isn't overflowing the index block size */ 223 return (u8 *)ih + le32_to_cpu(ih->index_length); 224 } 225 226 static int ntfs_ie_end(INDEX_ENTRY *ie) 227 { 228 return ie->ie_flags & INDEX_ENTRY_END; 229 } 230 231 /** 232 * Find the last entry in the index block 233 */ 234 static INDEX_ENTRY *ntfs_ie_get_last(INDEX_ENTRY *ie, char *ies_end) 235 { 236 ntfs_log_trace("Entering\n"); 237 238 while ((char *)ie < ies_end && !ntfs_ie_end(ie)) 239 ie = ntfs_ie_get_next(ie); 240 241 return ie; 242 } 243 244 static INDEX_ENTRY *ntfs_ie_get_by_pos(INDEX_HEADER *ih, int pos) 245 { 246 INDEX_ENTRY *ie; 247 248 ntfs_log_trace("pos: %d\n", pos); 249 250 ie = ntfs_ie_get_first(ih); 251 252 while (pos-- > 0) 253 ie = ntfs_ie_get_next(ie); 254 255 return ie; 256 } 257 258 static INDEX_ENTRY *ntfs_ie_prev(INDEX_HEADER *ih, INDEX_ENTRY *ie) 259 { 260 INDEX_ENTRY *ie_prev = NULL; 261 INDEX_ENTRY *tmp; 262 263 ntfs_log_trace("Entering\n"); 264 265 tmp = ntfs_ie_get_first(ih); 266 267 while (tmp != ie) { 268 ie_prev = tmp; 269 tmp = ntfs_ie_get_next(tmp); 270 } 271 272 return ie_prev; 273 } 274 275 char *ntfs_ie_filename_get(INDEX_ENTRY *ie) 276 { 277 FILE_NAME_ATTR *fn; 278 279 fn = (FILE_NAME_ATTR *)&ie->key; 280 return ntfs_attr_name_get(fn->file_name, fn->file_name_length); 281 } 282 283 void ntfs_ie_filename_dump(INDEX_ENTRY *ie) 284 { 285 char *s; 286 287 s = ntfs_ie_filename_get(ie); 288 ntfs_log_debug("'%s' ", s); 289 ntfs_attr_name_free(&s); 290 } 291 292 void ntfs_ih_filename_dump(INDEX_HEADER *ih) 293 { 294 INDEX_ENTRY *ie; 295 296 ntfs_log_trace("Entering\n"); 297 298 ie = ntfs_ie_get_first(ih); 299 while (!ntfs_ie_end(ie)) { 300 ntfs_ie_filename_dump(ie); 301 ie = ntfs_ie_get_next(ie); 302 } 303 } 304 305 static int ntfs_ih_numof_entries(INDEX_HEADER *ih) 306 { 307 int n; 308 INDEX_ENTRY *ie; 309 310 ntfs_log_trace("Entering\n"); 311 312 ie = ntfs_ie_get_first(ih); 313 for (n = 0; !ntfs_ie_end(ie); n++) 314 ie = ntfs_ie_get_next(ie); 315 return n; 316 } 317 318 static int ntfs_ih_one_entry(INDEX_HEADER *ih) 319 { 320 return (ntfs_ih_numof_entries(ih) == 1); 321 } 322 323 static int ntfs_ih_zero_entry(INDEX_HEADER *ih) 324 { 325 return (ntfs_ih_numof_entries(ih) == 0); 326 } 327 328 static void ntfs_ie_delete(INDEX_HEADER *ih, INDEX_ENTRY *ie) 329 { 330 u32 new_size; 331 332 ntfs_log_trace("Entering\n"); 333 334 new_size = le32_to_cpu(ih->index_length) - le16_to_cpu(ie->length); 335 ih->index_length = cpu_to_le32(new_size); 336 memmove(ie, (u8 *)ie + le16_to_cpu(ie->length), 337 new_size - ((u8 *)ie - (u8 *)ih)); 338 } 339 340 static void ntfs_ie_set_vcn(INDEX_ENTRY *ie, VCN vcn) 341 { 342 *ntfs_ie_get_vcn_addr(ie) = cpu_to_le64(vcn); 343 } 344 345 /** 346 * Insert @ie index entry at @pos entry. Used @ih values should be ok already. 347 */ 348 static void ntfs_ie_insert(INDEX_HEADER *ih, INDEX_ENTRY *ie, INDEX_ENTRY *pos) 349 { 350 int ie_size = le16_to_cpu(ie->length); 351 352 ntfs_log_trace("Entering\n"); 353 354 ih->index_length = cpu_to_le32(le32_to_cpu(ih->index_length) + ie_size); 355 memmove((u8 *)pos + ie_size, pos, 356 le32_to_cpu(ih->index_length) - ((u8 *)pos - (u8 *)ih) - ie_size); 357 memcpy(pos, ie, ie_size); 358 } 359 360 static INDEX_ENTRY *ntfs_ie_dup(INDEX_ENTRY *ie) 361 { 362 INDEX_ENTRY *dup; 363 364 ntfs_log_trace("Entering\n"); 365 366 dup = ntfs_malloc(le16_to_cpu(ie->length)); 367 if (dup) 368 memcpy(dup, ie, le16_to_cpu(ie->length)); 369 370 return dup; 371 } 372 373 static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie) 374 { 375 INDEX_ENTRY *dup; 376 int size = le16_to_cpu(ie->length); 377 378 ntfs_log_trace("Entering\n"); 379 380 if (ie->ie_flags & INDEX_ENTRY_NODE) 381 size -= sizeof(VCN); 382 383 dup = ntfs_malloc(size); 384 if (dup) { 385 memcpy(dup, ie, size); 386 dup->ie_flags &= ~INDEX_ENTRY_NODE; 387 dup->length = cpu_to_le16(size); 388 } 389 return dup; 390 } 391 392 static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn) 393 { 394 u32 ib_size = (unsigned)le32_to_cpu(ib->index.allocated_size) + 0x18; 395 396 ntfs_log_trace("Entering\n"); 397 398 if (!ntfs_is_indx_record(ib->magic)) { 399 400 ntfs_log_error("Corrupt index block signature: vcn %lld inode " 401 "%llu\n", (long long)vcn, 402 (unsigned long long)icx->ni->mft_no); 403 return -1; 404 } 405 406 if (sle64_to_cpu(ib->index_block_vcn) != vcn) { 407 408 ntfs_log_error("Corrupt index block: VCN (%lld) is different " 409 "from expected VCN (%lld) in inode %llu\n", 410 (long long)sle64_to_cpu(ib->index_block_vcn), 411 (long long)vcn, 412 (unsigned long long)icx->ni->mft_no); 413 return -1; 414 } 415 416 if (ib_size != icx->block_size) { 417 418 ntfs_log_error("Corrupt index block : VCN (%lld) of inode %llu " 419 "has a size (%u) differing from the index " 420 "specified size (%u)\n", (long long)vcn, 421 (unsigned long long)icx->ni->mft_no, ib_size, 422 icx->block_size); 423 return -1; 424 } 425 return 0; 426 } 427 428 static INDEX_ROOT *ntfs_ir_lookup(ntfs_inode *ni, ntfschar *name, 429 u32 name_len, ntfs_attr_search_ctx **ctx) 430 { 431 ATTR_RECORD *a; 432 INDEX_ROOT *ir = NULL; 433 434 ntfs_log_trace("Entering\n"); 435 436 *ctx = ntfs_attr_get_search_ctx(ni, NULL); 437 if (!*ctx) { 438 ntfs_log_perror("Failed to get $INDEX_ROOT search context"); 439 return NULL; 440 } 441 442 if (ntfs_attr_lookup(AT_INDEX_ROOT, name, name_len, CASE_SENSITIVE, 443 0, NULL, 0, *ctx)) { 444 ntfs_log_perror("Failed to lookup $INDEX_ROOT"); 445 goto err_out; 446 } 447 448 a = (*ctx)->attr; 449 if (a->non_resident) { 450 errno = EINVAL; 451 ntfs_log_perror("Non-resident $INDEX_ROOT detected"); 452 goto err_out; 453 } 454 455 ir = (INDEX_ROOT *)((char *)a + le16_to_cpu(a->value_offset)); 456 err_out: 457 if (!ir) 458 ntfs_attr_put_search_ctx(*ctx); 459 return ir; 460 } 461 462 /** 463 * Find a key in the index block. 464 * 465 * Return values: 466 * STATUS_OK with errno set to ESUCCESS if we know for sure that the 467 * entry exists and @ie_out points to this entry. 468 * STATUS_NOT_FOUND with errno set to ENOENT if we know for sure the 469 * entry doesn't exist and @ie_out is the insertion point. 470 * STATUS_KEEP_SEARCHING if we can't answer the above question and 471 * @vcn will contain the node index block. 472 * STATUS_ERROR with errno set if on unexpected error during lookup. 473 */ 474 static int ntfs_ie_lookup(const void *key, const int key_len, 475 ntfs_index_context *icx, INDEX_HEADER *ih, 476 VCN *vcn, INDEX_ENTRY **ie_out) 477 { 478 INDEX_ENTRY *ie; 479 u8 *index_end; 480 int rc, item = 0; 481 482 ntfs_log_trace("Entering\n"); 483 484 index_end = ntfs_ie_get_end(ih); 485 486 /* 487 * Loop until we exceed valid memory (corruption case) or until we 488 * reach the last entry. 489 */ 490 for (ie = ntfs_ie_get_first(ih); ; ie = ntfs_ie_get_next(ie)) { 491 /* Bounds checks. */ 492 if ((u8 *)ie + sizeof(INDEX_ENTRY_HEADER) > index_end || 493 (u8 *)ie + le16_to_cpu(ie->length) > index_end) { 494 errno = ERANGE; 495 ntfs_log_error("Index entry out of bounds in inode " 496 "%llu.\n", 497 (unsigned long long)icx->ni->mft_no); 498 return STATUS_ERROR; 499 } 500 /* 501 * The last entry cannot contain a key. It can however contain 502 * a pointer to a child node in the B+tree so we just break out. 503 */ 504 if (ntfs_ie_end(ie)) 505 break; 506 /* 507 * Not a perfect match, need to do full blown collation so we 508 * know which way in the B+tree we have to go. 509 */ 510 rc = ntfs_collate(icx->ni->vol, icx->cr, key, key_len, &ie->key, 511 le16_to_cpu(ie->key_length)); 512 if (rc == NTFS_COLLATION_ERROR) { 513 ntfs_log_error("Collation error. Perhaps a filename " 514 "contains invalid characters?\n"); 515 errno = ERANGE; 516 return STATUS_ERROR; 517 } 518 /* 519 * If @key collates before the key of the current entry, there 520 * is definitely no such key in this index but we might need to 521 * descend into the B+tree so we just break out of the loop. 522 */ 523 if (rc == -1) 524 break; 525 526 if (!rc) { 527 *ie_out = ie; 528 errno = 0; 529 icx->parent_pos[icx->pindex] = item; 530 return STATUS_OK; 531 } 532 533 item++; 534 } 535 /* 536 * We have finished with this index block without success. Check for the 537 * presence of a child node and if not present return with errno ENOENT, 538 * otherwise we will keep searching in another index block. 539 */ 540 if (!(ie->ie_flags & INDEX_ENTRY_NODE)) { 541 ntfs_log_debug("Index entry wasn't found.\n"); 542 *ie_out = ie; 543 errno = ENOENT; 544 return STATUS_NOT_FOUND; 545 } 546 547 /* Get the starting vcn of the index_block holding the child node. */ 548 *vcn = ntfs_ie_get_vcn(ie); 549 if (*vcn < 0) { 550 errno = EINVAL; 551 ntfs_log_perror("Negative vcn in inode %llu\n", 552 (unsigned long long)icx->ni->mft_no); 553 return STATUS_ERROR; 554 } 555 556 ntfs_log_trace("Parent entry number %d\n", item); 557 icx->parent_pos[icx->pindex] = item; 558 559 return STATUS_KEEP_SEARCHING; 560 } 561 562 static ntfs_attr *ntfs_ia_open(ntfs_index_context *icx, ntfs_inode *ni) 563 { 564 ntfs_attr *na; 565 566 na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len); 567 if (!na) { 568 ntfs_log_perror("Failed to open index allocation of inode " 569 "%llu", (unsigned long long)ni->mft_no); 570 return NULL; 571 } 572 573 return na; 574 } 575 576 static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst) 577 { 578 s64 pos, ret; 579 580 ntfs_log_trace("vcn: %lld\n", vcn); 581 582 pos = ntfs_ib_vcn_to_pos(icx, vcn); 583 584 ret = ntfs_attr_mst_pread(icx->ia_na, pos, 1, icx->block_size, (u8 *)dst); 585 if (ret != 1) { 586 if (ret == -1) 587 ntfs_log_perror("Failed to read index block"); 588 else 589 ntfs_log_error("Failed to read full index block at " 590 "%lld\n", (long long)pos); 591 return -1; 592 } 593 594 if (ntfs_ia_check(icx, dst, vcn)) 595 return -1; 596 597 return 0; 598 } 599 600 static int ntfs_icx_parent_inc(ntfs_index_context *icx) 601 { 602 icx->pindex++; 603 if (icx->pindex >= MAX_PARENT_VCN) { 604 errno = EOPNOTSUPP; 605 ntfs_log_perror("Index is over %d level deep", MAX_PARENT_VCN); 606 return STATUS_ERROR; 607 } 608 return STATUS_OK; 609 } 610 611 static int ntfs_icx_parent_dec(ntfs_index_context *icx) 612 { 613 icx->pindex--; 614 if (icx->pindex < 0) { 615 errno = EINVAL; 616 ntfs_log_perror("Corrupt index pointer (%d)", icx->pindex); 617 return STATUS_ERROR; 618 } 619 return STATUS_OK; 620 } 621 622 /** 623 * ntfs_index_lookup - find a key in an index and return its index entry 624 * @key: [IN] key for which to search in the index 625 * @key_len: [IN] length of @key in bytes 626 * @icx: [IN/OUT] context describing the index and the returned entry 627 * 628 * Before calling ntfs_index_lookup(), @icx must have been obtained from a 629 * call to ntfs_index_ctx_get(). 630 * 631 * Look for the @key in the index specified by the index lookup context @icx. 632 * ntfs_index_lookup() walks the contents of the index looking for the @key. 633 * 634 * If the @key is found in the index, 0 is returned and @icx is setup to 635 * describe the index entry containing the matching @key. @icx->entry is the 636 * index entry and @icx->data and @icx->data_len are the index entry data and 637 * its length in bytes, respectively. 638 * 639 * If the @key is not found in the index, -1 is returned, errno = ENOENT and 640 * @icx is setup to describe the index entry whose key collates immediately 641 * after the search @key, i.e. this is the position in the index at which 642 * an index entry with a key of @key would need to be inserted. 643 * 644 * If an error occurs return -1, set errno to error code and @icx is left 645 * untouched. 646 * 647 * When finished with the entry and its data, call ntfs_index_ctx_put() to free 648 * the context and other associated resources. 649 * 650 * If the index entry was modified, call ntfs_index_entry_mark_dirty() before 651 * the call to ntfs_index_ctx_put() to ensure that the changes are written 652 * to disk. 653 */ 654 int ntfs_index_lookup(const void *key, const int key_len, 655 ntfs_index_context *icx) 656 { 657 VCN old_vcn, vcn; 658 ntfs_inode *ni = icx->ni; 659 INDEX_ROOT *ir; 660 INDEX_ENTRY *ie; 661 INDEX_BLOCK *ib = NULL; 662 ntfs_attr_search_ctx *actx; 663 int ret, err = 0; 664 665 ntfs_log_trace("Entering\n"); 666 667 if (!key || key_len <= 0) { 668 errno = EINVAL; 669 ntfs_log_perror("key: %p key_len: %d", key, key_len); 670 return -1; 671 } 672 673 ir = ntfs_ir_lookup(ni, icx->name, icx->name_len, &actx); 674 if (!ir) { 675 if (errno == ENOENT) 676 errno = EIO; 677 return -1; 678 } 679 680 icx->block_size = le32_to_cpu(ir->index_block_size); 681 if (icx->block_size < NTFS_BLOCK_SIZE) { 682 errno = EINVAL; 683 ntfs_log_perror("Index block size (%d) is smaller than the " 684 "sector size (%d)", icx->block_size, NTFS_BLOCK_SIZE); 685 return -1; 686 } 687 688 if (ni->vol->cluster_size <= icx->block_size) 689 icx->vcn_size_bits = ni->vol->cluster_size_bits; 690 else 691 icx->vcn_size_bits = ni->vol->sector_size_bits; 692 693 icx->cr = ir->collation_rule; 694 if (!ntfs_is_collation_rule_supported(icx->cr)) { 695 err = errno = EOPNOTSUPP; 696 ntfs_log_perror("Unknown collation rule 0x%x", 697 (unsigned)le32_to_cpu(icx->cr)); 698 goto err_out; 699 } 700 701 old_vcn = VCN_INDEX_ROOT_PARENT; 702 /* 703 * FIXME: check for both ir and ib that the first index entry is 704 * within the index block. 705 */ 706 ret = ntfs_ie_lookup(key, key_len, icx, &ir->index, &vcn, &ie); 707 if (ret == STATUS_ERROR) { 708 err = errno; 709 goto err_out; 710 } 711 712 icx->actx = actx; 713 icx->ir = ir; 714 715 if (ret != STATUS_KEEP_SEARCHING) { 716 /* STATUS_OK or STATUS_NOT_FOUND */ 717 err = errno; 718 icx->is_in_root = TRUE; 719 icx->parent_vcn[icx->pindex] = old_vcn; 720 goto done; 721 } 722 723 /* Child node present, descend into it. */ 724 725 icx->ia_na = ntfs_ia_open(icx, ni); 726 if (!icx->ia_na) 727 goto err_out; 728 729 ib = ntfs_malloc(icx->block_size); 730 if (!ib) { 731 err = errno; 732 goto err_out; 733 } 734 735 descend_into_child_node: 736 737 icx->parent_vcn[icx->pindex] = old_vcn; 738 if (ntfs_icx_parent_inc(icx)) { 739 err = errno; 740 goto err_out; 741 } 742 old_vcn = vcn; 743 744 ntfs_log_debug("Descend into node with VCN %lld.\n", vcn); 745 746 if (ntfs_ib_read(icx, vcn, ib)) 747 goto err_out; 748 749 ret = ntfs_ie_lookup(key, key_len, icx, &ib->index, &vcn, &ie); 750 if (ret != STATUS_KEEP_SEARCHING) { 751 err = errno; 752 if (ret == STATUS_ERROR) 753 goto err_out; 754 755 /* STATUS_OK or STATUS_NOT_FOUND */ 756 icx->is_in_root = FALSE; 757 icx->ib = ib; 758 icx->parent_vcn[icx->pindex] = icx->ib_vcn = vcn; 759 goto done; 760 } 761 762 if ((ib->index.ih_flags & NODE_MASK) == LEAF_NODE) { 763 ntfs_log_error("Index entry with child node found in a leaf " 764 "node in inode 0x%llx.\n", 765 (unsigned long long)ni->mft_no); 766 goto err_out; 767 } 768 769 goto descend_into_child_node; 770 err_out: 771 if (icx->ia_na) 772 ntfs_attr_close(icx->ia_na); 773 free(ib); 774 if (!err) 775 err = EIO; 776 if (actx) 777 ntfs_attr_put_search_ctx(actx); 778 errno = err; 779 return -1; 780 done: 781 icx->entry = ie; 782 icx->data = (u8 *)ie + offsetof(INDEX_ENTRY, key); 783 icx->data_len = le16_to_cpu(ie->key_length); 784 icx->max_depth = icx->pindex; 785 ntfs_log_trace("Done.\n"); 786 if (err) { 787 errno = err; 788 return -1; 789 } 790 return 0; 791 792 } 793 794 static INDEX_BLOCK *ntfs_ib_alloc(VCN ib_vcn, u32 ib_size, 795 INDEX_HEADER_FLAGS node_type) 796 { 797 INDEX_BLOCK *ib; 798 int ih_size = sizeof(INDEX_HEADER); 799 800 ntfs_log_trace("Entering ib_vcn = %lld ib_size = %u\n", ib_vcn, ib_size); 801 802 ib = ntfs_calloc(ib_size); 803 if (!ib) 804 return NULL; 805 806 ib->magic = magic_INDX; 807 ib->usa_ofs = cpu_to_le16(sizeof(INDEX_BLOCK)); 808 ib->usa_count = cpu_to_le16(ib_size / NTFS_BLOCK_SIZE + 1); 809 /* Set USN to 1 */ 810 *(u16 *)((char *)ib + le16_to_cpu(ib->usa_ofs)) = cpu_to_le16(1); 811 ib->lsn = cpu_to_le64(0); 812 813 ib->index_block_vcn = cpu_to_sle64(ib_vcn); 814 815 ib->index.entries_offset = cpu_to_le32((ih_size + 816 le16_to_cpu(ib->usa_count) * 2 + 7) & ~7); 817 ib->index.index_length = 0; 818 ib->index.allocated_size = cpu_to_le32(ib_size - 819 (sizeof(INDEX_BLOCK) - ih_size)); 820 ib->index.ih_flags = node_type; 821 822 return ib; 823 } 824 825 /** 826 * Find the median by going through all the entries 827 */ 828 static INDEX_ENTRY *ntfs_ie_get_median(INDEX_HEADER *ih) 829 { 830 INDEX_ENTRY *ie, *ie_start; 831 u8 *ie_end; 832 int i = 0, median; 833 834 ntfs_log_trace("Entering\n"); 835 836 ie = ie_start = ntfs_ie_get_first(ih); 837 ie_end = (u8 *)ntfs_ie_get_end(ih); 838 839 while ((u8 *)ie < ie_end && !ntfs_ie_end(ie)) { 840 ie = ntfs_ie_get_next(ie); 841 i++; 842 } 843 /* 844 * NOTE: this could be also the entry at the half of the index block. 845 */ 846 median = i / 2 - 1; 847 848 ntfs_log_trace("Entries: %d median: %d\n", i, median); 849 850 for (i = 0, ie = ie_start; i <= median; i++) 851 ie = ntfs_ie_get_next(ie); 852 853 return ie; 854 } 855 856 static s64 ntfs_ibm_vcn_to_pos(ntfs_index_context *icx, VCN vcn) 857 { 858 return ntfs_ib_vcn_to_pos(icx, vcn) / icx->block_size; 859 } 860 861 static s64 ntfs_ibm_pos_to_vcn(ntfs_index_context *icx, s64 pos) 862 { 863 return ntfs_ib_pos_to_vcn(icx, pos * icx->block_size); 864 } 865 866 static int ntfs_ibm_add(ntfs_index_context *icx) 867 { 868 u8 bmp[8]; 869 870 ntfs_log_trace("Entering\n"); 871 872 if (ntfs_attr_exist(icx->ni, AT_BITMAP, icx->name, icx->name_len)) 873 return STATUS_OK; 874 /* 875 * AT_BITMAP must be at least 8 bytes. 876 */ 877 memset(bmp, 0, sizeof(bmp)); 878 if (ntfs_attr_add(icx->ni, AT_BITMAP, icx->name, icx->name_len, 879 bmp, sizeof(bmp))) { 880 ntfs_log_perror("Failed to add AT_BITMAP"); 881 return STATUS_ERROR; 882 } 883 884 return STATUS_OK; 885 } 886 887 static int ntfs_ibm_modify(ntfs_index_context *icx, VCN vcn, int set) 888 { 889 u8 byte; 890 s64 pos = ntfs_ibm_vcn_to_pos(icx, vcn); 891 u32 bpos = pos / 8; 892 u32 bit = 1 << (pos % 8); 893 ntfs_attr *na; 894 int ret = STATUS_ERROR; 895 896 ntfs_log_trace("%s vcn: %lld\n", set ? "set" : "clear", vcn); 897 898 na = ntfs_attr_open(icx->ni, AT_BITMAP, icx->name, icx->name_len); 899 if (!na) { 900 ntfs_log_perror("Failed to open $BITMAP attribute"); 901 return -1; 902 } 903 904 if (set) { 905 if (na->data_size < bpos + 1) { 906 if (ntfs_attr_truncate(na, (na->data_size + 8) & ~7)) { 907 ntfs_log_perror("Failed to truncate AT_BITMAP"); 908 goto err_na; 909 } 910 } 911 } 912 913 if (ntfs_attr_pread(na, bpos, 1, &byte) != 1) { 914 ntfs_log_perror("Failed to read $BITMAP"); 915 goto err_na; 916 } 917 918 if (set) 919 byte |= bit; 920 else 921 byte &= ~bit; 922 923 if (ntfs_attr_pwrite(na, bpos, 1, &byte) != 1) { 924 ntfs_log_perror("Failed to write $Bitmap"); 925 goto err_na; 926 } 927 928 ret = STATUS_OK; 929 err_na: 930 ntfs_attr_close(na); 931 return ret; 932 } 933 934 935 static int ntfs_ibm_set(ntfs_index_context *icx, VCN vcn) 936 { 937 return ntfs_ibm_modify(icx, vcn, 1); 938 } 939 940 static int ntfs_ibm_clear(ntfs_index_context *icx, VCN vcn) 941 { 942 return ntfs_ibm_modify(icx, vcn, 0); 943 } 944 945 static VCN ntfs_ibm_get_free(ntfs_index_context *icx) 946 { 947 u8 *bm; 948 int bit; 949 s64 vcn, byte, size; 950 951 ntfs_log_trace("Entering\n"); 952 953 bm = ntfs_attr_readall(icx->ni, AT_BITMAP, icx->name, icx->name_len, 954 &size); 955 if (!bm) 956 return (VCN)-1; 957 958 for (byte = 0; byte < size; byte++) { 959 960 if (bm[byte] == 255) 961 continue; 962 963 for (bit = 0; bit < 8; bit++) { 964 if (!(bm[byte] & (1 << bit))) { 965 vcn = ntfs_ibm_pos_to_vcn(icx, byte * 8 + bit); 966 goto out; 967 } 968 } 969 } 970 971 vcn = ntfs_ibm_pos_to_vcn(icx, size * 8); 972 out: 973 ntfs_log_trace("allocated vcn: %lld\n", vcn); 974 975 if (ntfs_ibm_set(icx, vcn)) 976 vcn = (VCN)-1; 977 978 free(bm); 979 return vcn; 980 } 981 982 static INDEX_BLOCK *ntfs_ir_to_ib(INDEX_ROOT *ir, VCN ib_vcn) 983 { 984 INDEX_BLOCK *ib; 985 INDEX_ENTRY *ie_last; 986 char *ies_start, *ies_end; 987 int i; 988 989 ntfs_log_trace("Entering\n"); 990 991 ib = ntfs_ib_alloc(ib_vcn, le32_to_cpu(ir->index_block_size), LEAF_NODE); 992 if (!ib) 993 return NULL; 994 995 ies_start = (char *)ntfs_ie_get_first(&ir->index); 996 ies_end = (char *)ntfs_ie_get_end(&ir->index); 997 ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end); 998 /* 999 * Copy all entries, including the termination entry 1000 * as well, which can never have any data. 1001 */ 1002 i = (char *)ie_last - ies_start + le16_to_cpu(ie_last->length); 1003 memcpy(ntfs_ie_get_first(&ib->index), ies_start, i); 1004 1005 ib->index.ih_flags = ir->index.ih_flags; 1006 ib->index.index_length = cpu_to_le32(i + 1007 le32_to_cpu(ib->index.entries_offset)); 1008 return ib; 1009 } 1010 1011 static void ntfs_ir_nill(INDEX_ROOT *ir) 1012 { 1013 INDEX_ENTRY *ie_last; 1014 char *ies_start, *ies_end; 1015 1016 ntfs_log_trace("Entering\n"); 1017 /* 1018 * TODO: This function could be much simpler. 1019 */ 1020 ies_start = (char *)ntfs_ie_get_first(&ir->index); 1021 ies_end = (char *)ntfs_ie_get_end(&ir->index); 1022 ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end); 1023 /* 1024 * Move the index root termination entry forward 1025 */ 1026 if ((char *)ie_last > ies_start) { 1027 memmove(ies_start, (char *)ie_last, le16_to_cpu(ie_last->length)); 1028 ie_last = (INDEX_ENTRY *)ies_start; 1029 } 1030 } 1031 1032 static int ntfs_ib_copy_tail(ntfs_index_context *icx, INDEX_BLOCK *src, 1033 INDEX_ENTRY *median, VCN new_vcn) 1034 { 1035 u8 *ies_end; 1036 INDEX_ENTRY *ie_head; /* first entry after the median */ 1037 int tail_size, ret; 1038 INDEX_BLOCK *dst; 1039 1040 ntfs_log_trace("Entering\n"); 1041 1042 dst = ntfs_ib_alloc(new_vcn, icx->block_size, 1043 src->index.ih_flags & NODE_MASK); 1044 if (!dst) 1045 return STATUS_ERROR; 1046 1047 ie_head = ntfs_ie_get_next(median); 1048 1049 ies_end = (u8 *)ntfs_ie_get_end(&src->index); 1050 tail_size = ies_end - (u8 *)ie_head; 1051 memcpy(ntfs_ie_get_first(&dst->index), ie_head, tail_size); 1052 1053 dst->index.index_length = cpu_to_le32(tail_size + 1054 le32_to_cpu(dst->index.entries_offset)); 1055 ret = ntfs_ib_write(icx, new_vcn, dst); 1056 1057 free(dst); 1058 return ret; 1059 } 1060 1061 static int ntfs_ib_cut_tail(ntfs_index_context *icx, INDEX_BLOCK *src, 1062 INDEX_ENTRY *ie) 1063 { 1064 char *ies_start, *ies_end; 1065 INDEX_ENTRY *ie_last; 1066 1067 ntfs_log_trace("Entering\n"); 1068 1069 ies_start = (char *)ntfs_ie_get_first(&src->index); 1070 ies_end = (char *)ntfs_ie_get_end(&src->index); 1071 1072 ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end); 1073 if (ie_last->ie_flags & INDEX_ENTRY_NODE) 1074 ntfs_ie_set_vcn(ie_last, ntfs_ie_get_vcn(ie)); 1075 1076 memcpy(ie, ie_last, le16_to_cpu(ie_last->length)); 1077 1078 src->index.index_length = cpu_to_le32(((char *)ie - ies_start) + 1079 le16_to_cpu(ie->length) + le32_to_cpu(src->index.entries_offset)); 1080 1081 if (ntfs_ib_write(icx, icx->parent_vcn[icx->pindex + 1], src)) 1082 return STATUS_ERROR; 1083 1084 return STATUS_OK; 1085 } 1086 1087 static int ntfs_ia_add(ntfs_index_context *icx) 1088 { 1089 ntfs_log_trace("Entering\n"); 1090 1091 if (ntfs_ibm_add(icx)) 1092 return -1; 1093 1094 if (!ntfs_attr_exist(icx->ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len)) { 1095 1096 if (ntfs_attr_add(icx->ni, AT_INDEX_ALLOCATION, icx->name, 1097 icx->name_len, NULL, 0)) { 1098 ntfs_log_perror("Failed to add AT_INDEX_ALLOCATION"); 1099 return -1; 1100 } 1101 } 1102 1103 icx->ia_na = ntfs_ia_open(icx, icx->ni); 1104 if (!icx->ia_na) 1105 return -1; 1106 1107 return 0; 1108 } 1109 1110 static int ntfs_ir_reparent(ntfs_index_context *icx) 1111 { 1112 ntfs_attr_search_ctx *ctx; 1113 INDEX_ROOT *ir; 1114 INDEX_ENTRY *ie; 1115 INDEX_BLOCK *ib = NULL; 1116 VCN new_ib_vcn; 1117 int ret = STATUS_ERROR; 1118 1119 ntfs_log_trace("Entering\n"); 1120 1121 ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, &ctx); 1122 if (!ir) 1123 return -1; 1124 1125 if ((ir->index.ih_flags & NODE_MASK) == SMALL_INDEX) 1126 if (ntfs_ia_add(icx)) 1127 goto err_out; 1128 1129 new_ib_vcn = ntfs_ibm_get_free(icx); 1130 if (new_ib_vcn == -1) 1131 goto err_out; 1132 1133 ib = ntfs_ir_to_ib(ir, new_ib_vcn); 1134 if (ib == NULL) { 1135 ntfs_log_perror("Failed to move index root to index block"); 1136 goto clear_bmp; 1137 } 1138 1139 if (ntfs_ib_write(icx, new_ib_vcn, ib)) 1140 goto clear_bmp; 1141 1142 ntfs_ir_nill(ir); 1143 1144 ie = ntfs_ie_get_first(&ir->index); 1145 ie->ie_flags |= INDEX_ENTRY_NODE; 1146 ie->length = cpu_to_le16(sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN)); 1147 1148 ir->index.ih_flags = LARGE_INDEX; 1149 ir->index.index_length = cpu_to_le32(le32_to_cpu(ir->index.entries_offset) 1150 + le16_to_cpu(ie->length)); 1151 ir->index.allocated_size = ir->index.index_length; 1152 1153 if (ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, 1154 sizeof(INDEX_ROOT) - sizeof(INDEX_HEADER) + 1155 le32_to_cpu(ir->index.allocated_size))) 1156 /* FIXME: revert bitmap, index root */ 1157 goto err_out; 1158 /* 1159 * FIXME: do it earlier if we have enough space in IR (should always), 1160 * so in error case we wouldn't lose the IB. 1161 */ 1162 ntfs_ie_set_vcn(ie, new_ib_vcn); 1163 1164 ret = STATUS_OK; 1165 err_out: 1166 free(ib); 1167 ntfs_attr_put_search_ctx(ctx); 1168 return ret; 1169 clear_bmp: 1170 ntfs_ibm_clear(icx, new_ib_vcn); 1171 goto err_out; 1172 } 1173 1174 /** 1175 * ntfs_ir_truncate - Truncate index root attribute 1176 * 1177 * Returns STATUS_OK, STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT or STATUS_ERROR. 1178 */ 1179 static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size) 1180 { 1181 ntfs_attr *na; 1182 int ret; 1183 1184 ntfs_log_trace("Entering\n"); 1185 1186 na = ntfs_attr_open(icx->ni, AT_INDEX_ROOT, icx->name, icx->name_len); 1187 if (!na) { 1188 ntfs_log_perror("Failed to open INDEX_ROOT"); 1189 return STATUS_ERROR; 1190 } 1191 /* 1192 * INDEX_ROOT must be resident and its entries can be moved to 1193 * INDEX_BLOCK, so ENOSPC isn't a real error. 1194 */ 1195 ret = ntfs_attr_truncate(na, data_size + offsetof(INDEX_ROOT, index)); 1196 if (ret == STATUS_OK) { 1197 1198 ntfs_attr_search_ctx *ctx; 1199 1200 icx->ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, &ctx); 1201 if (!icx->ir) 1202 return STATUS_ERROR; 1203 1204 icx->ir->index.allocated_size = cpu_to_le32(data_size); 1205 1206 ntfs_attr_put_search_ctx(ctx); 1207 1208 } else if (errno != ENOSPC) 1209 ntfs_log_trace("Failed to truncate INDEX_ROOT"); 1210 1211 ntfs_attr_close(na); 1212 return ret; 1213 } 1214 1215 /** 1216 * ntfs_ir_make_space - Make more space for the index root attribute 1217 * 1218 * On success return STATUS_OK or STATUS_KEEP_SEARCHING. 1219 * On error return STATUS_ERROR. 1220 */ 1221 static int ntfs_ir_make_space(ntfs_index_context *icx, int data_size) 1222 { 1223 int ret; 1224 1225 ntfs_log_trace("Entering\n"); 1226 1227 ret = ntfs_ir_truncate(icx, data_size); 1228 if (ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT) { 1229 1230 ret = ntfs_ir_reparent(icx); 1231 if (ret == STATUS_OK) 1232 ret = STATUS_KEEP_SEARCHING; 1233 else 1234 ntfs_log_perror("Failed to nodify INDEX_ROOT"); 1235 } 1236 1237 return ret; 1238 } 1239 1240 /* 1241 * NOTE: 'ie' must be a copy of a real index entry. 1242 */ 1243 static int ntfs_ie_add_vcn(INDEX_ENTRY **ie) 1244 { 1245 INDEX_ENTRY *p, *old = *ie; 1246 1247 old->length = cpu_to_le16(le16_to_cpu(old->length) + sizeof(VCN)); 1248 p = realloc(old, le16_to_cpu(old->length)); 1249 if (!p) 1250 return STATUS_ERROR; 1251 1252 p->ie_flags |= INDEX_ENTRY_NODE; 1253 *ie = p; 1254 1255 return STATUS_OK; 1256 } 1257 1258 static int ntfs_ih_insert(INDEX_HEADER *ih, INDEX_ENTRY *orig_ie, VCN new_vcn, 1259 int pos) 1260 { 1261 INDEX_ENTRY *ie_node, *ie; 1262 int ret = STATUS_ERROR; 1263 VCN old_vcn; 1264 1265 ntfs_log_trace("Entering\n"); 1266 1267 ie = ntfs_ie_dup(orig_ie); 1268 if (!ie) 1269 return STATUS_ERROR; 1270 1271 if (!(ie->ie_flags & INDEX_ENTRY_NODE)) 1272 if (ntfs_ie_add_vcn(&ie)) 1273 goto out; 1274 1275 ie_node = ntfs_ie_get_by_pos(ih, pos); 1276 old_vcn = ntfs_ie_get_vcn(ie_node); 1277 ntfs_ie_set_vcn(ie_node, new_vcn); 1278 1279 ntfs_ie_insert(ih, ie, ie_node); 1280 ntfs_ie_set_vcn(ie_node, old_vcn); 1281 ret = STATUS_OK; 1282 out: 1283 free(ie); 1284 1285 return ret; 1286 } 1287 1288 static VCN ntfs_icx_parent_vcn(ntfs_index_context *icx) 1289 { 1290 return icx->parent_vcn[icx->pindex]; 1291 } 1292 1293 static VCN ntfs_icx_parent_pos(ntfs_index_context *icx) 1294 { 1295 return icx->parent_pos[icx->pindex]; 1296 } 1297 1298 1299 static int ntfs_ir_insert_median(ntfs_index_context *icx, INDEX_ENTRY *median, 1300 VCN new_vcn) 1301 { 1302 u32 new_size; 1303 int ret; 1304 1305 ntfs_log_trace("Entering\n"); 1306 1307 new_size = le32_to_cpu(icx->ir->index.index_length) + 1308 le16_to_cpu(median->length); 1309 if (!(median->ie_flags & INDEX_ENTRY_NODE)) 1310 new_size += sizeof(VCN); 1311 1312 ret = ntfs_ir_make_space(icx, new_size); 1313 if (ret != STATUS_OK) 1314 return ret; 1315 1316 return ntfs_ih_insert(&icx->ir->index, median, new_vcn, 1317 ntfs_icx_parent_pos(icx)); 1318 } 1319 1320 static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib); 1321 1322 /** 1323 * On success return STATUS_OK or STATUS_KEEP_SEARCHING. 1324 * On error return STATUS_ERROR. 1325 */ 1326 static int ntfs_ib_insert(ntfs_index_context *icx, INDEX_ENTRY *ie, VCN new_vcn) 1327 { 1328 INDEX_BLOCK *ib; 1329 u32 idx_size, allocated_size; 1330 int err = STATUS_ERROR; 1331 VCN old_vcn; 1332 1333 ntfs_log_trace("Entering\n"); 1334 1335 ib = ntfs_malloc(icx->block_size); 1336 if (!ib) 1337 return -1; 1338 1339 old_vcn = ntfs_icx_parent_vcn(icx); 1340 1341 if (ntfs_ib_read(icx, old_vcn, ib)) 1342 goto err_out; 1343 1344 idx_size = le32_to_cpu(ib->index.index_length); 1345 allocated_size = le32_to_cpu(ib->index.allocated_size); 1346 /* FIXME: sizeof(VCN) should be included only if ie has no VCN */ 1347 if (idx_size + le16_to_cpu(ie->length) + sizeof(VCN) > allocated_size) { 1348 err = ntfs_ib_split(icx, ib); 1349 if (err == STATUS_OK) 1350 err = STATUS_KEEP_SEARCHING; 1351 goto err_out; 1352 } 1353 1354 if (ntfs_ih_insert(&ib->index, ie, new_vcn, ntfs_icx_parent_pos(icx))) 1355 goto err_out; 1356 1357 if (ntfs_ib_write(icx, old_vcn, ib)) 1358 goto err_out; 1359 1360 err = STATUS_OK; 1361 err_out: 1362 free(ib); 1363 return err; 1364 } 1365 1366 /** 1367 * ntfs_ib_split - Split index allocation attribute 1368 * 1369 * On success return STATUS_OK or STATUS_KEEP_SEARCHING. 1370 * On error return is STATUS_ERROR. 1371 */ 1372 static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib) 1373 { 1374 INDEX_ENTRY *median; 1375 VCN new_vcn; 1376 int ret; 1377 1378 ntfs_log_trace("Entering\n"); 1379 1380 if (ntfs_icx_parent_dec(icx)) 1381 return STATUS_ERROR; 1382 1383 median = ntfs_ie_get_median(&ib->index); 1384 new_vcn = ntfs_ibm_get_free(icx); 1385 if (new_vcn == -1) 1386 return STATUS_ERROR; 1387 1388 if (ntfs_ib_copy_tail(icx, ib, median, new_vcn)) { 1389 ntfs_ibm_clear(icx, new_vcn); 1390 return STATUS_ERROR; 1391 } 1392 1393 if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) 1394 ret = ntfs_ir_insert_median(icx, median, new_vcn); 1395 else 1396 ret = ntfs_ib_insert(icx, median, new_vcn); 1397 1398 ntfs_inode_mark_dirty(icx->actx->ntfs_ino); 1399 1400 if (ret != STATUS_OK) { 1401 ntfs_ibm_clear(icx, new_vcn); 1402 return ret; 1403 } 1404 1405 ret = ntfs_ib_cut_tail(icx, ib, median); 1406 1407 return ret; 1408 } 1409 1410 1411 static int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie) 1412 { 1413 char *fn; 1414 INDEX_HEADER *ih; 1415 int allocated_size, new_size; 1416 int ret = STATUS_ERROR; 1417 1418 fn = ntfs_ie_filename_get(ie); 1419 ntfs_log_trace("file: '%s'\n", fn); 1420 1421 while (1) { 1422 1423 if (!ntfs_index_lookup(&ie->key, le16_to_cpu(ie->key_length), icx)) { 1424 errno = EEXIST; 1425 ntfs_log_perror("Index already have such entry"); 1426 goto err_out; 1427 } 1428 if (errno != ENOENT) { 1429 ntfs_log_perror("Failed to find place for new entry"); 1430 goto err_out; 1431 } 1432 1433 if (icx->is_in_root) 1434 ih = &icx->ir->index; 1435 else 1436 ih = &icx->ib->index; 1437 1438 allocated_size = le32_to_cpu(ih->allocated_size); 1439 new_size = le32_to_cpu(ih->index_length) + le16_to_cpu(ie->length); 1440 1441 if (new_size <= allocated_size) 1442 break; 1443 1444 ntfs_log_trace("index block sizes: allocated: %d needed: %d\n", 1445 allocated_size, new_size); 1446 1447 if (icx->is_in_root) { 1448 if (ntfs_ir_make_space(icx, new_size) == STATUS_ERROR) 1449 goto err_out; 1450 } else { 1451 if (ntfs_ib_split(icx, icx->ib) == STATUS_ERROR) 1452 goto err_out; 1453 } 1454 1455 ntfs_inode_mark_dirty(icx->actx->ntfs_ino); 1456 ntfs_index_ctx_reinit(icx); 1457 } 1458 1459 ntfs_ie_insert(ih, ie, icx->entry); 1460 ntfs_index_entry_mark_dirty(icx); 1461 1462 ret = STATUS_OK; 1463 err_out: 1464 ntfs_attr_name_free(&fn); 1465 ntfs_log_trace("%s\n", ret ? "Failed" : "Done"); 1466 return ret; 1467 } 1468 1469 /** 1470 * ntfs_index_add_filename - add filename to directory index 1471 * @ni: ntfs inode describing directory to which index add filename 1472 * @fn: FILE_NAME attribute to add 1473 * @mref: reference of the inode which @fn describes 1474 * 1475 * Return 0 on success or -1 on error with errno set to the error code. 1476 */ 1477 int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref) 1478 { 1479 INDEX_ENTRY *ie; 1480 ntfs_index_context *icx; 1481 int fn_size, ie_size, ret = -1; 1482 1483 ntfs_log_trace("Entering\n"); 1484 1485 if (!ni || !fn) { 1486 ntfs_log_error("Invalid arguments.\n"); 1487 errno = EINVAL; 1488 return -1; 1489 } 1490 1491 fn_size = (fn->file_name_length * sizeof(ntfschar)) + 1492 sizeof(FILE_NAME_ATTR); 1493 ie_size = (sizeof(INDEX_ENTRY_HEADER) + fn_size + 7) & ~7; 1494 1495 ie = ntfs_calloc(ie_size); 1496 if (!ie) 1497 return -1; 1498 1499 ie->indexed_file = cpu_to_le64(mref); 1500 ie->length = cpu_to_le16(ie_size); 1501 ie->key_length = cpu_to_le16(fn_size); 1502 memcpy(&ie->key, fn, fn_size); 1503 1504 icx = ntfs_index_ctx_get(ni, NTFS_INDEX_I30, 4); 1505 if (!icx) 1506 goto out; 1507 1508 ret = ntfs_ie_add(icx, ie); 1509 1510 ntfs_index_ctx_put(icx); 1511 out: 1512 free(ie); 1513 return ret; 1514 } 1515 1516 static int ntfs_ih_takeout(ntfs_index_context *icx, INDEX_HEADER *ih, 1517 INDEX_ENTRY *ie, INDEX_BLOCK *ib) 1518 { 1519 INDEX_ENTRY *ie_roam; 1520 int ret = STATUS_ERROR; 1521 1522 ntfs_log_trace("Entering\n"); 1523 1524 ie_roam = ntfs_ie_dup_novcn(ie); 1525 if (!ie_roam) 1526 return STATUS_ERROR; 1527 1528 ntfs_ie_delete(ih, ie); 1529 1530 if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) 1531 ntfs_inode_mark_dirty(icx->actx->ntfs_ino); 1532 else 1533 if (ntfs_ib_write(icx, ntfs_icx_parent_vcn(icx), ib)) 1534 goto out; 1535 1536 ntfs_index_ctx_reinit(icx); 1537 1538 ret = ntfs_ie_add(icx, ie_roam); 1539 out: 1540 free(ie_roam); 1541 return ret; 1542 } 1543 1544 /** 1545 * Used if an empty index block to be deleted has END entry as the parent 1546 * in the INDEX_ROOT which is the only one there. 1547 */ 1548 static void ntfs_ir_leafify(ntfs_index_context *icx, INDEX_HEADER *ih) 1549 { 1550 INDEX_ENTRY *ie; 1551 1552 ntfs_log_trace("Entering\n"); 1553 1554 ie = ntfs_ie_get_first(ih); 1555 ie->ie_flags &= ~INDEX_ENTRY_NODE; 1556 ie->length = cpu_to_le16(le16_to_cpu(ie->length) - sizeof(VCN)); 1557 1558 ih->index_length = cpu_to_le32(le32_to_cpu(ih->index_length) - sizeof(VCN)); 1559 ih->ih_flags &= ~LARGE_INDEX; 1560 1561 /* Not fatal error */ 1562 ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length)); 1563 1564 ntfs_inode_mark_dirty(icx->actx->ntfs_ino); 1565 ntfs_index_ctx_reinit(icx); 1566 } 1567 1568 /** 1569 * Used if an empty index block to be deleted has END entry as the parent 1570 * in the INDEX_ROOT which is not the only one there. 1571 */ 1572 static int ntfs_ih_reparent_end(ntfs_index_context *icx, INDEX_HEADER *ih, 1573 INDEX_BLOCK *ib) 1574 { 1575 INDEX_ENTRY *ie, *ie_prev; 1576 1577 ntfs_log_trace("Entering\n"); 1578 1579 ie = ntfs_ie_get_by_pos(ih, ntfs_icx_parent_pos(icx)); 1580 ie_prev = ntfs_ie_prev(ih, ie); 1581 1582 ntfs_ie_set_vcn(ie, ntfs_ie_get_vcn(ie_prev)); 1583 1584 return ntfs_ih_takeout(icx, ih, ie_prev, ib); 1585 } 1586 1587 static int ntfs_index_rm_leaf(ntfs_index_context *icx) 1588 { 1589 INDEX_BLOCK *ib = NULL; 1590 INDEX_HEADER *parent_ih; 1591 INDEX_ENTRY *ie; 1592 int ret = STATUS_ERROR; 1593 1594 ntfs_log_trace("pindex: %d\n", icx->pindex); 1595 1596 if (ntfs_icx_parent_dec(icx)) 1597 return STATUS_ERROR; 1598 1599 if (ntfs_ibm_clear(icx, icx->parent_vcn[icx->pindex + 1])) 1600 return STATUS_ERROR; 1601 1602 if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) 1603 parent_ih = &icx->ir->index; 1604 else { 1605 ib = ntfs_malloc(icx->block_size); 1606 if (!ib) 1607 return STATUS_ERROR; 1608 1609 if (ntfs_ib_read(icx, ntfs_icx_parent_vcn(icx), ib)) 1610 goto out; 1611 1612 parent_ih = &ib->index; 1613 } 1614 1615 ie = ntfs_ie_get_by_pos(parent_ih, ntfs_icx_parent_pos(icx)); 1616 if (!ntfs_ie_end(ie)) { 1617 ret = ntfs_ih_takeout(icx, parent_ih, ie, ib); 1618 goto out; 1619 } 1620 1621 if (ntfs_ih_zero_entry(parent_ih)) { 1622 1623 if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) { 1624 ntfs_ir_leafify(icx, parent_ih); 1625 goto ok; 1626 } 1627 1628 ret = ntfs_index_rm_leaf(icx); 1629 goto out; 1630 } 1631 1632 if (ntfs_ih_reparent_end(icx, parent_ih, ib)) 1633 goto out; 1634 ok: 1635 ret = STATUS_OK; 1636 out: 1637 free(ib); 1638 return ret; 1639 } 1640 1641 static int ntfs_index_rm_node(ntfs_index_context *icx) 1642 { 1643 int entry_pos; 1644 VCN vcn; 1645 INDEX_BLOCK *ib = NULL; 1646 INDEX_ENTRY *ie_succ, *ie, *entry = icx->entry; 1647 INDEX_HEADER *ih; 1648 u32 new_size; 1649 int delta, ret = STATUS_ERROR; 1650 1651 ntfs_log_trace("Entering\n"); 1652 1653 if (!icx->ia_na) { 1654 icx->ia_na = ntfs_ia_open(icx, icx->ni); 1655 if (!icx->ia_na) 1656 return STATUS_ERROR; 1657 } 1658 1659 ib = ntfs_malloc(icx->block_size); 1660 if (!ib) 1661 return STATUS_ERROR; 1662 1663 ie_succ = ntfs_ie_get_next(icx->entry); 1664 entry_pos = icx->parent_pos[icx->pindex]++; 1665 descend: 1666 vcn = ntfs_ie_get_vcn(ie_succ); 1667 if (ntfs_ib_read(icx, vcn, ib)) 1668 goto out; 1669 1670 ie_succ = ntfs_ie_get_first(&ib->index); 1671 1672 if (ntfs_icx_parent_inc(icx)) 1673 goto out; 1674 1675 icx->parent_vcn[icx->pindex] = vcn; 1676 icx->parent_pos[icx->pindex] = 0; 1677 1678 if ((ib->index.ih_flags & NODE_MASK) == INDEX_NODE) 1679 goto descend; 1680 1681 if (ntfs_ih_zero_entry(&ib->index)) { 1682 errno = EOPNOTSUPP; 1683 ntfs_log_perror("Failed to find any entry in an index block. " 1684 "Please run chkdsk."); 1685 goto out; 1686 } 1687 1688 ie = ntfs_ie_dup(ie_succ); 1689 if (!ie) 1690 goto out; 1691 1692 if (ntfs_ie_add_vcn(&ie)) 1693 goto out2; 1694 1695 ntfs_ie_set_vcn(ie, ntfs_ie_get_vcn(icx->entry)); 1696 1697 if (icx->is_in_root) 1698 ih = &icx->ir->index; 1699 else 1700 ih = &icx->ib->index; 1701 1702 delta = le16_to_cpu(ie->length) - le16_to_cpu(icx->entry->length); 1703 new_size = le32_to_cpu(ih->index_length) + delta; 1704 if (delta > 0) { 1705 if (icx->is_in_root) { 1706 if (ntfs_ir_truncate(icx, new_size)) { 1707 errno = EOPNOTSUPP; 1708 ntfs_log_perror("Denied to truncate INDEX ROOT during entry removal"); 1709 goto out2; 1710 } 1711 1712 ih = &icx->ir->index; 1713 entry = ntfs_ie_get_by_pos(ih, entry_pos); 1714 1715 } else if (new_size > le32_to_cpu(ih->allocated_size)) { 1716 errno = EOPNOTSUPP; 1717 ntfs_log_perror("Denied to split INDEX BLOCK during entry removal"); 1718 goto out2; 1719 } 1720 } 1721 1722 ntfs_ie_delete(ih, entry); 1723 ntfs_ie_insert(ih, ie, entry); 1724 1725 if (icx->is_in_root) { 1726 if (ntfs_ir_truncate(icx, new_size)) 1727 goto out2; 1728 ntfs_inode_mark_dirty(icx->actx->ntfs_ino); 1729 } else 1730 if (ntfs_icx_ib_write(icx)) 1731 goto out2; 1732 1733 ntfs_ie_delete(&ib->index, ie_succ); 1734 1735 if (ntfs_ih_zero_entry(&ib->index)) { 1736 if (ntfs_index_rm_leaf(icx)) 1737 goto out2; 1738 } else 1739 if (ntfs_ib_write(icx, vcn, ib)) 1740 goto out2; 1741 1742 ret = STATUS_OK; 1743 out2: 1744 free(ie); 1745 out: 1746 free(ib); 1747 return ret; 1748 } 1749 1750 /** 1751 * ntfs_index_rm - remove entry from the index 1752 * @icx: index context describing entry to delete 1753 * 1754 * Delete entry described by @icx from the index. Index context is always 1755 * reinitialized after use of this function, so it can be used for index 1756 * lookup once again. 1757 * 1758 * Return 0 on success or -1 on error with errno set to the error code. 1759 */ 1760 int ntfs_index_rm(ntfs_index_context *icx) 1761 { 1762 INDEX_HEADER *ih; 1763 int err; 1764 1765 ntfs_log_trace("Entering\n"); 1766 1767 if (!icx || (!icx->ib && !icx->ir) || ntfs_ie_end(icx->entry)) { 1768 ntfs_log_error("Invalid arguments.\n"); 1769 errno = EINVAL; 1770 goto err_out; 1771 } 1772 if (icx->is_in_root) 1773 ih = &icx->ir->index; 1774 else 1775 ih = &icx->ib->index; 1776 1777 if (icx->entry->ie_flags & INDEX_ENTRY_NODE) { 1778 1779 if (ntfs_index_rm_node(icx)) 1780 goto err_out; 1781 1782 } else if (icx->is_in_root || !ntfs_ih_one_entry(ih)) { 1783 1784 ntfs_ie_delete(ih, icx->entry); 1785 1786 if (icx->is_in_root) { 1787 err = ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length)); 1788 if (err != STATUS_OK) 1789 goto err_out; 1790 } else 1791 if (ntfs_icx_ib_write(icx)) 1792 goto err_out; 1793 } else { 1794 if (ntfs_index_rm_leaf(icx)) 1795 goto err_out; 1796 } 1797 1798 ntfs_index_ctx_reinit(icx); 1799 ntfs_log_trace("Done.\n"); 1800 return 0; 1801 err_out: 1802 err = errno; 1803 ntfs_index_ctx_reinit(icx); 1804 errno = err; 1805 ntfs_log_trace("Failed.\n"); 1806 return -1; 1807 } 1808 1809 /** 1810 * ntfs_index_root_get - read the index root of an attribute 1811 * @ni: open ntfs inode in which the ntfs attribute resides 1812 * @attr: attribute for which we want its index root 1813 * 1814 * This function will read the related index root an ntfs attribute. 1815 * 1816 * On success a buffer is allocated with the content of the index root 1817 * and which needs to be freed when it's not needed anymore. 1818 * 1819 * On error NULL is returned with errno set to the error code. 1820 */ 1821 INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr) 1822 { 1823 ntfs_attr_search_ctx *ctx; 1824 ntfschar *name; 1825 INDEX_ROOT *root = NULL; 1826 1827 name = (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)); 1828 1829 if (!ntfs_ir_lookup(ni, name, attr->name_length, &ctx)) 1830 return NULL; 1831 1832 root = ntfs_malloc(sizeof(INDEX_ROOT)); 1833 if (!root) 1834 goto out; 1835 1836 *root = *((INDEX_ROOT *)((u8 *)ctx->attr + 1837 le16_to_cpu(ctx->attr->value_offset))); 1838 out: 1839 ntfs_attr_put_search_ctx(ctx); 1840 return root; 1841 } 1842 1843 1844