1/* 2 * ntfs_attr_list.c - NTFS kernel attribute list attribute operations. 3 * 4 * Copyright (c) 2006-2008 Anton Altaparmakov. All Rights Reserved. 5 * Portions Copyright (c) 2006-2008 Apple Inc. All Rights Reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 16 * contributors may be used to endorse or promote products derived from this 17 * software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * ALTERNATIVELY, provided that this notice and licensing terms are retained in 31 * full, this file may be redistributed and/or modified under the terms of the 32 * GNU General Public License (GPL) Version 2, in which case the provisions of 33 * that version of the GPL will apply to you instead of the license terms 34 * above. You can obtain a copy of the GPL Version 2 at 35 * http://developer.apple.com/opensource/licenses/gpl-2.txt. 36 */ 37 38#include <sys/errno.h> 39 40#include <string.h> 41 42#include <libkern/OSMalloc.h> 43 44#include <kern/sched_prim.h> 45 46#include "ntfs.h" 47#include "ntfs_attr.h" 48#include "ntfs_attr_list.h" 49#include "ntfs_debug.h" 50#include "ntfs_endian.h" 51#include "ntfs_inode.h" 52#include "ntfs_layout.h" 53#include "ntfs_lcnalloc.h" 54#include "ntfs_mft.h" 55#include "ntfs_types.h" 56#include "ntfs_unistr.h" 57#include "ntfs_volume.h" 58 59/** 60 * ntfs_attr_list_is_needed - check if attribute list attribute is still needed 61 * @ni: base ntfs inode to check 62 * @skip_entry: attribute list entry to skip when checking 63 * @attr_list_is_needed: pointer in which to return the result 64 * 65 * Check the attribute list attribute of the base ntfs inode @ni. If there are 66 * no attribute list attribute entries other than @skip_entry which reference 67 * extent mft records it means the attribute list attribute is no longer needed 68 * thus we set *@attr_list_is_needed to false and return success. 69 * 70 * If there are attribute list attribute entries other than @skip_entry which 71 * reference extent mft records the attribute list attribute is still needed 72 * thus we set *@attr_list_is_needed to true and return success. 73 * 74 * Return 0 on success and errno on error. On success *@attr_list_is_needed is 75 * set to true if the attribute list attribute is still needed and to false if 76 * it is no longer needed (and hence can be deleted). On error 77 * *@attr_list_is_needed is not defined. 78 */ 79errno_t ntfs_attr_list_is_needed(ntfs_inode *ni, ATTR_LIST_ENTRY *skip_entry, 80 BOOL *attr_list_is_needed) 81{ 82 leMFT_REF base_mref; 83 ATTR_LIST_ENTRY *entry; 84 u8 *al, *al_end; 85 86 ntfs_debug("Entering for base mft_no 0x%llx.", 87 (unsigned long long)ni->mft_no); 88 /* Scan all entries in the attribute list attribute. */ 89 base_mref = MK_LE_MREF(ni->mft_no, ni->seq_no); 90 *attr_list_is_needed = FALSE; 91 al = ni->attr_list; 92 entry = (ATTR_LIST_ENTRY*)al; 93 al_end = (u8*)al + ni->attr_list_size; 94 for (;; entry = (ATTR_LIST_ENTRY*)((u8*)entry + 95 le16_to_cpu(entry->length))) { 96 /* Out of bounds check. */ 97 if ((u8*)entry < al || (u8*)entry > al_end) 98 goto err; 99 /* Catch the end of the attribute list. */ 100 if ((u8*)entry == al_end) 101 break; 102 /* More sanity checks. */ 103 if (!entry->length || (u8*)entry + sizeof(*entry) > al_end) 104 goto err; 105 /* 106 * If there is an entry to be skipped and the current entry 107 * matches it, then skip this entry. We do not need to check 108 * whether @skip_entry is NULL because @entry cannot be NULL so 109 * this condition would never be true in @skip_entry is NULL. 110 */ 111 if (entry == skip_entry) 112 continue; 113 /* 114 * If this entry references an extent mft record no need to 115 * search any further, we know there is at least one extent mft 116 * record in use thus the attribute list attribute is still 117 * needed. 118 */ 119 if (entry->mft_reference != base_mref) { 120 *attr_list_is_needed = TRUE; 121 break; 122 } 123 } 124 ntfs_debug("Done for mft_no 0x%llx, attribute list attribute is " 125 "%s needed.", (unsigned long long)ni->mft_no, 126 (*attr_list_is_needed) ? "still" : "no longer"); 127 return 0; 128err: 129 ntfs_error(ni->vol->mp, "Attribute list attribute of mft_no 0x%llx is " 130 "corrupt. Unmount and run chkdsk.", 131 (unsigned long long)ni->mft_no); 132 NVolSetErrors(ni->vol); 133 return EIO; 134} 135 136/** 137 * ntfs_attr_list_delete - delete the attribute list attribute of an ntfs inode 138 * @ni: base ntfs inode whose attribute list attribugte to delete 139 * @ctx: initialized attribute search context 140 * 141 * Delete the attribute list attribute of the base ntfs inode @ni. 142 * 143 * @ctx is an initialized, ready to use attribute search context that we use to 144 * look up the attribute list attribute in the mapped, base mft record. 145 * 146 * This function assumes that the caller has ensured that the attribute list 147 * attribute is no longer needed by calling ntfs_attr_list_is_needed(). 148 * 149 * Return 0 on success and errno on error. 150 */ 151errno_t ntfs_attr_list_delete(ntfs_inode *ni, ntfs_attr_search_ctx *ctx) 152{ 153 errno_t err; 154 155 ntfs_debug("Entering for base mft_no 0x%llx.", 156 (unsigned long long)ni->mft_no); 157 /* Find the attribute list attribute in the base mft record. */ 158 err = ntfs_attr_find_in_mft_record(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 159 NULL, 0, ctx); 160 if (err) 161 goto err; 162 /* 163 * If the attribute list attribute is non-resident we need to free the 164 * allocated clusters and runlist. 165 */ 166 if (ctx->a->non_resident) { 167 /* Free the allocated clusters. */ 168 err = ntfs_cluster_free_from_rl(ni->vol, ni->attr_list_rl.rl, 169 0, -1, NULL); 170 if (err) { 171 ntfs_warning(ni->vol->mp, "Failed to free some " 172 "allocated clusters belonging to the " 173 "attribute list attribute of mft_no " 174 "0x%llx (error %d). Continuing " 175 "regardless. Unmount and run chkdsk " 176 "to recover the lost space.", 177 (unsigned long long)ni->mft_no, err); 178 NVolSetErrors(ni->vol); 179 } 180 /* Free the runlist of the attribute list attribute. */ 181 OSFree(ni->attr_list_rl.rl, ni->attr_list_rl.alloc, 182 ntfs_malloc_tag); 183 ni->attr_list_rl.alloc = 0; 184 } 185 /* Delete the attribute list attribute record. */ 186 ntfs_attr_record_delete_internal(ctx->m, ctx->a); 187 /* Make sure the modified base mft record is written out. */ 188 NInoSetMrecNeedsDirtying(ni); 189 /* Update the in-memory base inode and free memory. */ 190 ni->attr_list_size = 0; 191 OSFree(ni->attr_list, ni->attr_list_alloc, ntfs_malloc_tag); 192 ni->attr_list_alloc = 0; 193 NInoClearAttrList(ni); 194 ntfs_debug("Done."); 195 return 0; 196err: 197 ntfs_error(ni->vol->mp, "Failed to find attribute list attribute in " 198 "base mft_no 0x%llx (error %d). Unmount and run " 199 "chkdsk.", (unsigned long long)ni->mft_no, err); 200 NVolSetErrors(ni->vol); 201 return EIO; 202} 203 204/** 205 * ntfs_attr_list_add - add an attribute list attribute to an inode 206 * @base_ni: base ntfs inode to which to add an attribute list attribute 207 * @m: base mft record of the base ntfs inode @base_ni 208 * @ctx: attribute search context describing attribute being resized 209 * 210 * Add an attribute list attribute to the base ntfs inode @base_ni with mapped 211 * base mft record @m. 212 * 213 * @ctx (if not NULL) is an attribute search context describing the attribute 214 * being resized which is causing the attribute list attribute to be added. 215 * The pointers in the search context are updated with the new location of the 216 * attribute in the mft record. @ctx is also updated to reflect that this is 217 * now a search in an attribute list attribute containing inode. 218 * 219 * Return 0 on success and the negative error code on error. 220 * 221 * WARNING: If @ctx is supplied, regardless of whether success or failure is 222 * returned, you need to check @ctx->is_error and if 1 the @ctx is no 223 * longer valid, i.e. you need to either call 224 * ntfs_attr_search_ctx_reinit() or ntfs_attr_search_ctx_put() on it. 225 * In that case @ctx->error will give you the error code for why the 226 * mapping of the inode failed. 227 */ 228errno_t ntfs_attr_list_add(ntfs_inode *base_ni, MFT_RECORD *m, 229 ntfs_attr_search_ctx *ctx) 230{ 231 leMFT_REF mref; 232 ntfs_volume *vol; 233 ATTR_RECORD *a; 234 u8 *al, *al_end; 235 ATTR_LIST_ENTRY *al_entry; 236 unsigned al_alloc, al_size, bytes_free, attr_len, mp_size = 0; 237 errno_t err, err2; 238 BOOL for_mft, have_std_info, have_idx_root, insert_resident; 239 ntfs_attr_search_ctx al_ctx; 240 241 vol = base_ni->vol; 242 for_mft = FALSE; 243 if (base_ni == vol->mft_ni) 244 for_mft = TRUE; 245 ntfs_debug("Entering for mft_no 0x%llx%s.", 246 (unsigned long long)base_ni->mft_no, 247 for_mft ? ", for $MFT" : ""); 248 lck_rw_lock_exclusive(&base_ni->attr_list_rl.lock); 249 if (NInoAttrList(base_ni)) 250 panic("%s(): NInoAttrList(base_ni)\n", __FUNCTION__); 251 if (!m) 252 panic("%s(): !m\n", __FUNCTION__); 253 if (ctx && m != ctx->m) 254 panic("%s(): ctx && m != ctx->m\n", __FUNCTION__); 255 if (base_ni->attr_list_alloc) 256 panic("%s(): base_ni->attr_list_alloc\n", __FUNCTION__); 257 if (base_ni->attr_list_rl.alloc) 258 panic("%s(): base_ni->attr_list_rl.alloc\n", __FUNCTION__); 259 if (base_ni->attr_list_rl.elements) 260 panic("%s(): base_ni->attr_list_rl.elements\n", __FUNCTION__); 261 have_idx_root = have_std_info = FALSE; 262 /* 263 * Iterate over all the attribute records in the base mft record and 264 * build the attribute list attribute up in memory. 265 */ 266 al_alloc = NTFS_ALLOC_BLOCK; 267 al = OSMalloc(NTFS_ALLOC_BLOCK, ntfs_malloc_tag); 268 if (!al) { 269 ntfs_error(vol->mp, "Not enough memory to allocate buffer for " 270 "attribute list attribute."); 271 lck_rw_unlock_exclusive(&base_ni->attr_list_rl.lock); 272 return ENOMEM; 273 } 274 al_end = al + NTFS_ALLOC_BLOCK; 275 al_entry = (ATTR_LIST_ENTRY*)al; 276 ntfs_attr_search_ctx_init(&al_ctx, base_ni, m); 277 al_ctx.is_iteration = 1; 278 mref = MK_LE_MREF(base_ni->mft_no, base_ni->seq_no); 279 /* Maximum number of usable bytes in the mft record. */ 280 bytes_free = le32_to_cpu(m->bytes_allocated) - 281 le16_to_cpu(m->attrs_offset); 282 do { 283 unsigned al_entry_len, len; 284 285 /* Get the next attribute in the mft record. */ 286 err = ntfs_attr_find_in_mft_record(AT_UNUSED, NULL, 0, NULL, 0, 287 &al_ctx); 288 if (err) { 289 /* 290 * If we reached the end we now have all the attribute 291 * records in the attribute list attribute buffer. 292 */ 293 if (err == ENOENT) 294 break; 295 ntfs_error(vol->mp, "Failed to iterate over " 296 "attribute records in base mft record " 297 "(error %d).", err); 298 goto free_err; 299 } 300 a = al_ctx.a; 301 if (a->type == AT_ATTRIBUTE_LIST) { 302 ntfs_error(vol->mp, "Failed to add attribute list " 303 "attribute as it already exists."); 304 err = EIO; 305 goto free_err; 306 } 307 if (a->non_resident && a->lowest_vcn) 308 panic("%s(): a->non_resident && a->lowest_vcn\n", 309 __FUNCTION__); 310 /* 311 * Just some book keeping for later. If the current attribute 312 * cannot be moved out of the base mft record subtract its size 313 * from the amount of free space. 314 */ 315 if (a->type == AT_STANDARD_INFORMATION || 316 a->type == AT_INDEX_ROOT) { 317 bytes_free -= le32_to_cpu(a->length); 318 if (a->type == AT_STANDARD_INFORMATION) 319 have_std_info = TRUE; 320 else 321 have_idx_root = TRUE; 322 } 323 /* 324 * If we are adding the attribute list attribute to the $MFT 325 * system file, we cannot move out the $DATA attribute to make 326 * space although we could shrink it so that it contains only 327 * enough clusters in its mapping pairs array as to get us to 328 * the next fragment. However given everything is currently in 329 * the base mft record this means we can at least move out the 330 * filename attribute and the bitmap attribute which is 331 * guaranteed to give us enough space to add a non-resident 332 * attribute list attribute so we do not bother implementing 333 * such truncation here as it cannot be required. 334 */ 335 if (for_mft) { 336 if (a->type == AT_DATA && !a->name_length) 337 bytes_free -= le32_to_cpu(a->length); 338 } 339 /* 340 * If the current attribute is the attribute to be resized 341 * record its attribute list entry in @ctx->al_entry so we do 342 * not have to look it up later. 343 */ 344 if (ctx && ctx->a == a) 345 ctx->al_entry = al_entry; 346 len = offsetof(ATTR_LIST_ENTRY, name) + 347 (a->name_length * sizeof(ntfschar)); 348 /* 349 * Attribute list attribute entries must be aligned to 8-byte 350 * boundaries. 351 */ 352 al_entry_len = (len + 7) & ~7; 353 /* 354 * A single mft record cannot have enough attribute records to 355 * overflow a whole NTFS_ALLOC_BLOCK bytes worth of attribute 356 * list attribute entries. 357 */ 358 if ((u8*)al_entry + al_entry_len > al_end) 359 panic("%s(): (u8*)al_entry + al_entry_len > al_end\n", 360 __FUNCTION__); 361 /* 362 * Create the attribute list entry for the current attribute 363 * record. 364 */ 365 *al_entry = (ATTR_LIST_ENTRY) { 366 .type = a->type, 367 .length = cpu_to_le16(al_entry_len), 368 .name_length = a->name_length, 369 .name_offset = offsetof(ATTR_LIST_ENTRY, name), 370 .lowest_vcn = 0, 371 .mft_reference = mref, 372 .instance = a->instance, 373 }; 374 /* Copy the name if the attribute is named. */ 375 if (a->name_length) 376 memcpy(&al_entry->name, 377 (u8*)a + le16_to_cpu(a->name_offset), 378 a->name_length * sizeof(ntfschar)); 379 /* Zero the padding area at the end if it exists. */ 380 if (al_entry_len - len > 0) 381 memset((u8*)al_entry + len, 0, al_entry_len - len); 382 /* 383 * We are done with this attribute list entry, switch to the 384 * next one. 385 */ 386 al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry + al_entry_len); 387 } while (1); 388 al_size = (u8*)al_entry - al; 389 /* 390 * We now have built the attribute list attribute value in @al. 391 * 392 * Determine the size needed for the attribute list attribute if it is 393 * resident. 394 */ 395 attr_len = offsetof(ATTR_RECORD, reservedR) + sizeof(a->reservedR) + 396 al_size; 397 /* 398 * If the size is greater than the maximum size possible to insert into 399 * the mft record then insert the attribute list attribute as a 400 * non-resident attribute record. 401 */ 402 if (attr_len > bytes_free) { 403 insert_resident = FALSE; 404 goto insert; 405 } 406 /* 407 * If we do not have enough space to insert the attribute list 408 * attribute as a resident attribute record try to make enough space 409 * available by making other attributes non-resident and/or moving 410 * other attributes to extent mft records. 411 */ 412 insert_resident = TRUE; 413 ntfs_attr_search_ctx_reinit(&al_ctx); 414 al_ctx.is_iteration = 1; 415 for (al_entry = (ATTR_LIST_ENTRY*)al; 416 attr_len > le32_to_cpu(m->bytes_allocated) - 417 le32_to_cpu(m->bytes_in_use); 418 al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry + 419 le16_to_cpu(al_entry->length))) { 420 /* Get the next attribute in the mft record. */ 421 err = ntfs_attr_find_in_mft_record(AT_UNUSED, NULL, 0, NULL, 0, 422 &al_ctx); 423 if (err) { 424 /* 425 * We reached the end and we still do not have enough 426 * space to insert the attribute list attribute as a 427 * resident attribute record thus try to insert it as a 428 * non-resident attribute record. 429 */ 430 if (err == ENOENT) { 431 insert_resident = FALSE; 432 break; 433 } 434 ntfs_error(vol->mp, "Failed to iterate over " 435 "attribute records in base mft record " 436 "(error %d).", err); 437 goto undo; 438 } 439 a = al_ctx.a; 440 /* 441 * We already checked above that the attribute list attribute 442 * does not exist yet. 443 */ 444 if (a->type == AT_ATTRIBUTE_LIST) 445 panic("%s(): a->type == AT_ATTRIBUTE_LIST\n", 446 __FUNCTION__); 447 /* 448 * Do not touch standard information and index root attributes 449 * at this stage. They will be moved out to extent mft records 450 * further below if really necessary. 451 * 452 * TODO: Probably want to add unnamed data attributes to this 453 * as well. 454 */ 455 if (a->type == AT_STANDARD_INFORMATION || 456 a->type == AT_INDEX_ROOT) 457 continue; 458 /* 459 * If we are working on the $MFT system file, do not touch the 460 * unnamed $DATA attribute. 461 */ 462 if (for_mft) { 463 if (a->type == AT_DATA && !a->name_length) 464 continue; 465 } 466 /* 467 * If the attribute is resident and we can expect the 468 * non-resident form to be smaller than the resident form 469 * switch the attribute to non-resident now. 470 * 471 * FIXME: We cannot do this at present unless the attribute is 472 * the attribute being resized as there could be an ntfs inode 473 * matching this attribute in memory and it would become out of 474 * date with its metadata if we touch its attribute record. 475 * 476 * FIXME: We do not need to do this if this is the attribute 477 * being resized as the caller will have already tried to make 478 * the attribute non-resident and this will not have worked or 479 * we would never have gotten here in the first place. 480 */ 481 /* 482 * Move the attribute out to an extent mft record and update 483 * its attribute list entry. If it is the attribute to be 484 * resized, also update the attribute search context to match 485 * the new attribute. If it is not the attribute to be resized 486 * but it is in front of the attribute to be resized update the 487 * attribute search context to account for the removed 488 * attribute record. 489 */ 490 err = ntfs_attr_record_move_for_attr_list_attribute(&al_ctx, 491 al_entry, ctx, NULL); 492 if (err) { 493 ntfs_error(vol->mp, "Failed to move attribute type " 494 "0x%x out of base mft record 0x%llx " 495 "and into an extent mft record (error " 496 "%d).", (unsigned)le32_to_cpu(a->type), 497 (unsigned long long)base_ni->mft_no, 498 err); 499 goto undo; 500 } 501 } 502insert: 503 /* 504 * Find the location at which to insert the attribute list attribute 505 * record in the base mft record. 506 */ 507 ntfs_attr_search_ctx_reinit(&al_ctx); 508 err = ntfs_attr_find_in_mft_record(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 509 NULL, 0, &al_ctx); 510 if (!err || err != ENOENT) { 511 /* 512 * We already checked above that the attribute list attribute 513 * does not exist yet. 514 */ 515 if (!err) 516 panic("%s(): !err\n", __FUNCTION__); 517 ntfs_error(vol->mp, "Failed to find location at which to " 518 "insert attribute list attribute (error %d).", 519 err); 520 goto undo; 521 } 522 a = al_ctx.a; 523 /* 524 * If @insert_resident is true try to insert the attribute list 525 * attribute as a resident attribute record. 526 */ 527 if (insert_resident) { 528 err = ntfs_resident_attr_record_insert_internal(m, a, 529 AT_ATTRIBUTE_LIST, NULL, 0, al_size); 530 if (!err) { 531 memcpy((u8*)a + le16_to_cpu(a->value_offset), al, 532 al_size); 533 /* 534 * If we already allocated some clusters in a previous 535 * iteration need to free them now. 536 * 537 * Note we warn about errors and schedule the volume 538 * for chkdsk but otherwise we ignore the error as it 539 * does not in any way affect anything we are doing. 540 * The volume just ends up having some clusters marked 541 * in use but nothing is referencing them. Running 542 * chkdsk will clear those bits in the bitmap thus 543 * causing the clusters to be made available for use 544 * again. 545 */ 546 if (base_ni->attr_list_rl.elements) { 547 err = ntfs_cluster_free_from_rl(vol, 548 base_ni->attr_list_rl.rl, 549 0, -1, NULL); 550 if (err) { 551 ntfs_warning(vol->mp, "Failed to " 552 "release no longer " 553 "needed allocated " 554 "cluster(s) (error " 555 "%d). Run chkdsk to " 556 "recover the lost " 557 "cluster(s).", err); 558 NVolSetErrors(vol); 559 } 560 OSFree(base_ni->attr_list_rl.rl, 561 base_ni->attr_list_rl.alloc, 562 ntfs_malloc_tag); 563 base_ni->attr_list_rl.elements = 0; 564 base_ni->attr_list_rl.alloc = 0; 565 } 566 goto done; 567 } 568 if (err != ENOSPC) 569 panic("%s(): err != ENOSPC\n", __FUNCTION__); 570 } 571 /* 572 * Attempt to insert the attribute list attribute as a non-resident 573 * atribute record. 574 * 575 * First allocate enough clusters to store the attribute list attribute 576 * data. 577 */ 578 if (!base_ni->attr_list_rl.elements) { 579 attr_len = (al_size + vol->cluster_size_mask) & 580 ~vol->cluster_size_mask; 581 err = ntfs_cluster_alloc(vol, 0, attr_len / vol->cluster_size, 582 -1, DATA_ZONE, TRUE, &base_ni->attr_list_rl); 583 if (err) { 584 ntfs_error(vol->mp, "Failed to allocate clusters for " 585 "the non-resident attribute list " 586 "attribute (error %d).", err); 587 goto undo; 588 } 589 /* Determine the size of the mapping pairs array. */ 590 err = ntfs_get_size_for_mapping_pairs(vol, 591 base_ni->attr_list_rl.rl, 0, -1, &mp_size); 592 if (err) 593 panic("%s(): err (ntfs_get_size_for_mapping_pairs())\n", 594 __FUNCTION__); 595 } 596 /* 597 * As the attribute is unnamed the mapping pairs array is placed 598 * immediately after the non-resident attribute record itself. 599 * 600 * To determine the size of the attribute record take the offset to the 601 * mapping pairs array and add the size of the mapping pairs array in 602 * bytes aligned to an 8-byte boundary. Note we do not need to do the 603 * alignment as ntfs_attr_record_make_space() does it anyway. 604 */ 605 err = ntfs_attr_record_make_space(m, a, offsetof(ATTR_RECORD, 606 compressed_size) + mp_size); 607 if (err) { 608 ntfschar *a_name; 609 le32 type; 610 611 if (err != ENOSPC) 612 panic("%s(): err != ENOSPC\n", __FUNCTION__); 613 if (!have_std_info && !have_idx_root) { 614 /* 615 * We moved all attributes out of the base mft record 616 * and we still do not have enough space to add the 617 * attribute list attribute. 618 * 619 * TODO: The only thing that can help is to defragment 620 * the attribute list attribute and/or other fragmented 621 * attributes. The former would make the runlist of 622 * the attribute list attribute directly smaller thus 623 * it may then fit and the latter would reduce the 624 * number of extent attributes and thus the number of 625 * attribute list attribute entries which would 626 * indirectly make the runlist of the attribute list 627 * attribute smaller. For now we do not implement 628 * defragmentation so there is nothing we can do when 629 * this case occurs. It should be very, very hard to 630 * trigger this case though and I doubt even the 631 * Windows NTFS driver deals with it so we are not 632 * doing any worse than Windows so I think leaving 633 * things as they are is acceptable. 634 */ 635out_of_space: 636 ntfs_error(vol->mp, "The runlist of the attribute " 637 "list attribute is too large to fit " 638 "in the base mft record. You need to " 639 "defragment your volume and then try " 640 "again."); 641 err = ENOSPC; 642 goto undo; 643 } 644 /* 645 * Start with the index root(s) if present then do the standard 646 * information attribute. 647 * 648 * TODO: Need to get these cases triggered and then need to run 649 * chkdsk to check for validity of moving these attributes out 650 * of the base mft record. 651 */ 652 if (have_idx_root) 653 type = AT_INDEX_ROOT; 654 else { 655try_std_info: 656 type = AT_STANDARD_INFORMATION; 657 have_std_info = FALSE; 658 } 659 /* 660 * Find the attribute in the base mft record. Note for the 661 * index root there can be several index root attributes so we 662 * can get here multiple times once for each index root. 663 */ 664 ntfs_attr_search_ctx_reinit(&al_ctx); 665 al_ctx.is_iteration = 1; 666 err = ntfs_attr_find_in_mft_record(type, NULL, 0, NULL, 0, 667 &al_ctx); 668 if (err) { 669 /* 670 * The mft record cannot be corrupt given we have fully 671 * managed to parse it when generating the attribute 672 * list attribute entries. 673 */ 674 if (err != ENOENT) 675 panic("%s(): err != ENOENT\n", __FUNCTION__); 676 /* 677 * We should never get here for the standard 678 * information attribute. 679 */ 680 if (type != AT_INDEX_ROOT) 681 panic("%s(): type != AT_INDEX_ROOT\n", 682 __FUNCTION__); 683 if (!have_idx_root) 684 panic("%s(): !have_idx_root\n", __FUNCTION__); 685 /* 686 * We have done the index root attribute(s). Now try 687 * the standard information attribute if present. 688 */ 689 have_idx_root = FALSE; 690 if (have_std_info) 691 goto try_std_info; 692 /* We have really run out of space. */ 693 goto out_of_space; 694 } 695 a = al_ctx.a; 696 /* 697 * If the attribute is resident and we can expect the 698 * non-resident form to be smaller than the resident form 699 * switch the attribute to non-resident now. 700 * 701 * FIXME: We cannot do this at present unless the attribute is 702 * the attribute being resized as there could be an ntfs inode 703 * matching this attribute in memory and it would become out of 704 * date with its metadata if we touch its attribute record. 705 * 706 * FIXME: We do not need to do this if this is the attribute 707 * being resized as the caller will have already tried to make 708 * the attribute non-resident and this will not have worked or 709 * we would never have gotten here in the first place. 710 */ 711 /* 712 * Move the attribute out to an extent mft record and update 713 * its attribute list entry. If it is the attribute to be 714 * resized, also update the attribute search context to match 715 * the new attribute. If it is not the attribute to be resized 716 * but it is in front of the attribute to be resized update the 717 * attribute search context to account for the removed 718 * attribute record. 719 * 720 * But first find the attribute list entry matching the 721 * attribute record so it can be updated. 722 */ 723 a_name = (ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)); 724 al_entry = (ATTR_LIST_ENTRY*)base_ni->attr_list; 725 do { 726 /* 727 * We only just generated the attribute list thus it 728 * cannot be corrupt. 729 */ 730 if ((u8*)al_entry >= al_end || !al_entry->length) 731 panic("%s(): (u8*)al_entry >= al_end || " 732 "!al_entry->length\n", 733 __FUNCTION__); 734 if (al_entry->mft_reference == mref && 735 al_entry->instance == a->instance) { 736 /* 737 * We found the entry, stop looking but first 738 * perform a quick sanity check that we really 739 * do have the correct attribute record. 740 */ 741 if (al_entry->type != a->type) 742 panic("%s(): al_entry->type != " 743 "a->type\n", 744 __FUNCTION__); 745 if (!ntfs_are_names_equal( 746 (ntfschar*)((u8*)al_entry + 747 al_entry->name_offset), 748 al_entry->name_length, a_name, 749 a->name_length, TRUE, 750 vol->upcase, vol->upcase_len)) 751 panic("%s(): !ntfs_are_named_equal()\n", 752 __FUNCTION__); 753 break; 754 } 755 /* Go to the next attribute list entry. */ 756 al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry + 757 le16_to_cpu(al_entry->length)); 758 } while (1); 759 err = ntfs_attr_record_move_for_attr_list_attribute(&al_ctx, 760 al_entry, ctx, NULL); 761 if (err) { 762 ntfs_error(vol->mp, "Failed to move attribute type " 763 "0x%x out of base mft record 0x%llx " 764 "and into an extent mft record (error " 765 "%d).", (unsigned)le32_to_cpu(a->type), 766 (unsigned long long)base_ni->mft_no, 767 err); 768 goto undo; 769 } 770 /* 771 * We moved an attribute out of the base mft record so retry to 772 * insert the attribute list attribute now that we have more 773 * space in the base mft record. 774 */ 775 goto insert; 776 } 777 /* 778 * Now setup the new non-resident attribute list attribute record. The 779 * entire attribute has been zeroed and the length of the attribute 780 * record has been already set up by ntfs_attr_record_make_space(). 781 */ 782 a->type = AT_ATTRIBUTE_LIST; 783 a->non_resident = 1; 784 a->mapping_pairs_offset = a->name_offset = const_cpu_to_le16( 785 offsetof(ATTR_RECORD, compressed_size)); 786 a->instance = m->next_attr_instance; 787 /* 788 * Increment the next attribute instance number in the mft record as we 789 * consumed the old one. 790 */ 791 m->next_attr_instance = cpu_to_le16( 792 (le16_to_cpu(m->next_attr_instance) + 1) & 0xffff); 793 a->highest_vcn = cpu_to_sle64((attr_len / vol->cluster_size) - 1); 794 a->allocated_size = cpu_to_sle64(attr_len); 795 a->initialized_size = a->data_size = cpu_to_sle64(al_size); 796 /* 797 * Generate the mapping pairs array into place. This cannot fail as we 798 * determined how much space we need and then made that much space 799 * available. So unless we did something wrong we must have enough 800 * space available and the runlist must be in order. 801 */ 802 err = ntfs_mapping_pairs_build(vol, (s8*)a + offsetof(ATTR_RECORD, 803 compressed_size), mp_size, base_ni->attr_list_rl.rl, 0, 804 -1, NULL); 805 if (err) 806 panic("%s(): err (ntfs_mapping_pairs_build())\n", __FUNCTION__); 807done: 808 /* Ensure the changes make it to disk later. */ 809 NInoSetMrecNeedsDirtying(base_ni); 810 /* 811 * If we inserted the attribute list attribute as a non-resident 812 * attribute, write it out to disk now. 813 */ 814 if (a->non_resident) { 815 err = ntfs_rl_write(vol, al, al_size, &base_ni->attr_list_rl, 816 0, 0); 817 if (err) { 818 ntfs_error(vol->mp, "Failed to write non-resident " 819 "attribute list attribute value to " 820 "disk (error %d).", err); 821 goto rm_undo; 822 } 823 } 824 /* 825 * Set the base ntfs inode up to reflect that it now has an attribute 826 * list attribute. 827 */ 828 base_ni->attr_list = al; 829 base_ni->attr_list_size = al_size; 830 base_ni->attr_list_alloc = al_alloc; 831 NInoSetAttrList(base_ni); 832 lck_rw_unlock_exclusive(&base_ni->attr_list_rl.lock); 833 /* 834 * Update @ctx if the attribute it describes is still in the base mft 835 * record to reflect that the attribute list attribute was inserted in 836 * front of it. 837 */ 838 if (ctx) { 839 if (ctx->ni == base_ni) { 840 if ((u8*)a <= (u8*)ctx->a) 841 ctx->a = (ATTR_RECORD*)((u8*)ctx->a + 842 le32_to_cpu(a->length)); 843 } else { 844 MFT_RECORD *em; 845 846 /* 847 * @ctx is not in the base mft record, map the extent 848 * inode it is in and if it is mapped at a different 849 * address than before update the pointers in @ctx. 850 */ 851retry_map: 852 err2 = ntfs_mft_record_map(ctx->ni, &em); 853 if (err2) { 854 /* 855 * Something bad has happened. If out of 856 * memory retry till it succeeds. Any other 857 * errors are fatal and we return the error 858 * code in @ctx->m. We cannot undo as we would 859 * need to map the mft record to be able to 860 * move the attribute back into the base mft 861 * record and exactly that operation has just 862 * failed. 863 * 864 * We just need to fudge things so the caller 865 * can reinit and/or put the search context 866 * safely. 867 */ 868 if (err2 == ENOMEM) { 869 (void)thread_block( 870 THREAD_CONTINUE_NULL); 871 goto retry_map; 872 } 873 ctx->is_error = 1; 874 ctx->error = err2; 875 ctx->ni = base_ni; 876 } 877 if (!ctx->is_error && em != ctx->m) { 878 ctx->a = (ATTR_RECORD*)((u8*)em + 879 ((u8*)ctx->a - (u8*)ctx->m)); 880 ctx->m = em; 881 } 882 } 883 /* 884 * Finally, update @ctx to reflect the fact that it now is the 885 * result of a search inside an inode with an attribute list 886 * attribute. 887 */ 888 ctx->base_ni = base_ni; 889 ctx->base_m = m; 890 ctx->base_a = (ATTR_RECORD*)((u8*)m + 891 le16_to_cpu(m->attrs_offset)); 892 } 893 ntfs_debug("Done."); 894 return 0; 895rm_undo: 896 /* 897 * Need to delete the added attribute list attribute record from the 898 * base mft record. 899 */ 900 ntfs_attr_record_delete_internal(m, a); 901undo: 902 /* 903 * If we already allocated some clusters for the non-resident attribute 904 * list attribute need to free them now. 905 */ 906 if (base_ni->attr_list_rl.elements) { 907 err2 = ntfs_cluster_free_from_rl(vol, base_ni->attr_list_rl.rl, 908 0, -1, NULL); 909 if (err2) { 910 ntfs_error(vol->mp, "Failed to release allocated " 911 "cluster(s) in error code path (error " 912 "%d). Run chkdsk to recover the lost " 913 "cluster(s).", err2); 914 NVolSetErrors(vol); 915 } 916 OSFree(base_ni->attr_list_rl.rl, base_ni->attr_list_rl.alloc, 917 ntfs_malloc_tag); 918 base_ni->attr_list_rl.elements = 0; 919 base_ni->attr_list_rl.alloc = 0; 920 } 921 /* 922 * Move any attribute records that we moved out of the base mft record 923 * back into the base mft record and free the extent mft records we 924 * allocated for them. 925 */ 926 al_end = al + al_size; 927 for (al_entry = (ATTR_LIST_ENTRY*)al; (u8*)al_entry < al_end; 928 al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry + 929 le16_to_cpu(al_entry->length))) { 930 ntfs_inode *ni; 931 ntfschar *a_name; 932 u8 *val; 933 unsigned val_len; 934 935 /* Skip all attributes that are in the base mft record. */ 936 if (al_entry->mft_reference == mref) 937 continue; 938retry_undo_map: 939 /* Find the extent record in the base ntfs inode. */ 940 err2 = ntfs_extent_mft_record_map(base_ni, 941 le64_to_cpu(al_entry->mft_reference), &ni, &m); 942 if (err2) { 943 if (err2 == ENOMEM) 944 goto retry_undo_map; 945 /* 946 * There is nothing we can do to get this attribute 947 * back into the base mft record thus we simply skip 948 * it and continue with the next one. 949 * 950 * Note we do not free the extent mft record as that 951 * would confuse our mft allocator as we would leave 952 * the mft record itself marked in use. 953 */ 954 ntfs_error(vol->mp, "Failed to undo move of attribute " 955 "type 0x%x in mft_no 0x%llx in error " 956 "code path because mapping the extent " 957 "mft record 0x%llx faled (error %d). " 958 "Leaving corrupt metadata. Run " 959 "chkdsk.", 960 (unsigned)le32_to_cpu(al_entry->type), 961 (unsigned long long)base_ni->mft_no, 962 (unsigned long long) 963 MREF_LE(al_entry->mft_reference), err2); 964 NVolSetErrors(vol); 965 /* 966 * Proceed with the next one as we may be able to move 967 * others back. 968 */ 969 continue; 970 } 971 /* Find the attribute record that needs moving back. */ 972 a = (ATTR_RECORD*)((u8*)m + le16_to_cpu(m->attrs_offset)); 973 if (a->type == AT_END) 974 panic("%s(): a->type == AT_END\n", __FUNCTION__); 975 while (a->instance != al_entry->instance) { 976 a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length)); 977 if (a->type == AT_END) 978 panic("%s(): a->type == AT_END\n", 979 __FUNCTION__); 980 } 981 /* We must have found the right one. */ 982 if (al_entry->type != a->type) 983 panic("%s(): al_entry->type != a->type\n", 984 __FUNCTION__); 985 a_name = (ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)); 986 if (!ntfs_are_names_equal((ntfschar*)((u8*)al_entry + 987 al_entry->name_offset), al_entry->name_length, 988 a_name, a->name_length, TRUE, vol->upcase, 989 vol->upcase_len)) 990 panic("%s(): !ntfs_are_names_equal()\n", __FUNCTION__); 991 /* 992 * Find the location at which the attribute needs to be 993 * reinserted in the base mft record. 994 * 995 * As there can be multiple otherwise identical filename 996 * attributes we need to search using the attribute value in 997 * this case so we find the correct place to insert the 998 * attribute. 999 */ 1000 if (a->type == AT_FILENAME) { 1001 val = (u8*)a + le16_to_cpu(a->value_offset); 1002 val_len = le32_to_cpu(a->value_length); 1003 } else { 1004 val = NULL; 1005 val_len = 0; 1006 } 1007 ntfs_attr_search_ctx_reinit(&al_ctx); 1008 err2 = ntfs_attr_find_in_mft_record(a->type, a_name, 1009 a->name_length, val, val_len, &al_ctx); 1010 /* The attribute cannot be there already. */ 1011 if (!err2) 1012 panic("%s(): !err2\n", __FUNCTION__); 1013 /* 1014 * The mft record cannot be corrupt given we have fully managed 1015 * to parse it when generating the attribute list attribute 1016 * entries. 1017 */ 1018 if (err2 != ENOENT) 1019 panic("%s(): err2 != ENOENT\n", __FUNCTION__); 1020 attr_len = le32_to_cpu(a->length); 1021 /* Make space for the attribute and copy it into place. */ 1022 err2 = ntfs_attr_record_make_space(al_ctx.m, al_ctx.a, 1023 attr_len); 1024 /* 1025 * This cannot fail as the base mft record must have enough 1026 * space to hold the attribute record given it fitted before we 1027 * moved it out. 1028 */ 1029 if (err2) 1030 panic("%s(): err2\n", __FUNCTION__); 1031 memcpy(al_ctx.a, a, attr_len); 1032 /* 1033 * Assign a new instance number to the copied attribute record 1034 * as it now has moved into the base mft record. 1035 */ 1036 a->instance = al_ctx.m->next_attr_instance; 1037 /* 1038 * Increment the next attribute instance number in the mft 1039 * record as we consumed the old one. 1040 */ 1041 al_ctx.m->next_attr_instance = cpu_to_le16((le16_to_cpu( 1042 al_ctx.m->next_attr_instance) + 1) & 0xffff); 1043 /* 1044 * If this is the only attribute in the extent mft record, free 1045 * the extent mft record and disconnect it from the base ntfs 1046 * inode. 1047 * 1048 * If this is not the only attribute in the extent mft record, 1049 * delete the attribute record from the extent mft record. 1050 */ 1051 if (ntfs_attr_record_is_only_one(m, a)) { 1052 err2 = ntfs_extent_mft_record_free(base_ni, ni, m); 1053 if (err2) { 1054 ntfs_error(vol->mp, "Failed to free extent " 1055 "mft record 0x%llx after " 1056 "moving back attribute type " 1057 "0x%x in mft_no 0x%llx in " 1058 "error code path (error %d). " 1059 "Leaving corrupt metadata. " 1060 "Run chkdsk.", 1061 (unsigned long long)ni->mft_no, 1062 (unsigned)le32_to_cpu(a->type), 1063 (unsigned long long) 1064 base_ni->mft_no, err2); 1065 NVolSetErrors(vol); 1066 /* 1067 * Fall back to at least deleting the attribute 1068 * record from the extent mft record to 1069 * maintain some consistency. 1070 */ 1071 goto delete_err; 1072 } 1073 } else { 1074delete_err: 1075 ntfs_attr_record_delete_internal(m, a); 1076 NInoSetMrecNeedsDirtying(ni); 1077 ntfs_extent_mft_record_unmap(ni); 1078 } 1079 } 1080 /* Finally mark the fully restored base mft record dirty. */ 1081 NInoSetMrecNeedsDirtying(base_ni); 1082free_err: 1083 lck_rw_unlock_exclusive(&base_ni->attr_list_rl.lock); 1084 OSFree(al, al_alloc, ntfs_malloc_tag); 1085 return err; 1086} 1087 1088/** 1089 * ntfs_attr_list_sync_shrink - update the attribute list of an ntfs inode 1090 * @ni: base ntfs inode whose attribute list attribugte to update 1091 * @start_ofs: byte offset into attribute list attribute from which to write 1092 * @ctx: initialized attribute search context 1093 * 1094 * Update the on-disk attribute list attribute of the base ntfs inode @ni. The 1095 * caller has updated the attribute list attribute value that is cached in the 1096 * ntfs inode @ni and this function takes the updated value and resizes the 1097 * attribute record if necessary and then writes out the modified value 1098 * starting at offset @start_ofs bytes into the attribute value. 1099 * 1100 * This function only works for shrinking the attribute list attribute or if 1101 * the size has not changed. 1102 * 1103 * @ctx is an initialized, ready to use attribute search context that we use to 1104 * look up the attribute list attribute in the mapped, base mft record. 1105 * 1106 * Return 0 on success and errno on error. 1107 */ 1108errno_t ntfs_attr_list_sync_shrink(ntfs_inode *ni, const unsigned start_ofs, 1109 ntfs_attr_search_ctx *ctx) 1110{ 1111 s64 size, alloc_size; 1112 ntfs_volume *vol; 1113 ATTR_RECORD *a; 1114 unsigned mp_size; 1115 errno_t err; 1116 BOOL dirty_mft; 1117 static const char es[] = " Leaving inconsistent metadata. Unmount " 1118 "and run chkdsk."; 1119 1120 ntfs_debug("Entering for base mft_no 0x%llx.", 1121 (unsigned long long)ni->mft_no); 1122 /* 1123 * We currently do not implement adding the attribute list attribute. 1124 * 1125 * Use ntfs_attr_list_add() instead. 1126 */ 1127 if (!NInoAttrList(ni)) 1128 panic("%s(): !NInoAttrList(ni)\n", __FUNCTION__); 1129 if (start_ofs > ni->attr_list_size) 1130 panic("%s(): start_ofs > ni->attr_list_size\n", __FUNCTION__); 1131 /* 1132 * We should never have allowed the attribute list attribute to grow 1133 * above its maximum size. 1134 */ 1135 if (ni->attr_list_size > NTFS_MAX_ATTR_LIST_SIZE) 1136 panic("%s(): ni->attr_list_size > NTFS_MAX_ATTR_LIST_SIZE\n", 1137 __FUNCTION__); 1138 vol = ni->vol; 1139 dirty_mft = FALSE; 1140 /* Find the attribute list attribute in the base mft record. */ 1141 err = ntfs_attr_find_in_mft_record(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 1142 NULL, 0, ctx); 1143 if (err) { 1144 ntfs_error(vol->mp, "Failed to find attribute list attribute " 1145 "in base mft_no 0x%llx (error %d). Unmount " 1146 "and run chkdsk.", 1147 (unsigned long long)ni->mft_no, err); 1148 NVolSetErrors(vol); 1149 return EIO; 1150 } 1151 a = ctx->a; 1152 size = ntfs_attr_size(a); 1153 /* 1154 * We currently only implement shrinking the attribute list attribute. 1155 * 1156 * Use ntfs_attr_list_sync_extend() when extending it. 1157 */ 1158 if (ni->attr_list_size > size) 1159 panic("%s(): ni->attr_list_size > size\n", __FUNCTION__); 1160 /* 1161 * If the size has not changed skip the resize and go straight onto the 1162 * data update. 1163 */ 1164 if (ni->attr_list_size == size) { 1165 if (!a->non_resident) 1166 goto update_resident; 1167 goto update_non_resident; 1168 } 1169 /* Shrink the attribute list attribute. */ 1170 if (!a->non_resident) { 1171 /* 1172 * The attribute list attribute is resident, shrink the 1173 * attribute record and value. 1174 */ 1175 err = ntfs_resident_attr_value_resize(ctx->m, a, 1176 ni->attr_list_size); 1177 /* Shrinking the attribute record cannot fail. */ 1178 if (err) 1179 panic("%s(): err (resident)\n", __FUNCTION__); 1180 dirty_mft = TRUE; 1181update_resident: 1182 /* Update the part of the attribute value that has changed. */ 1183 if (start_ofs < ni->attr_list_size) { 1184 memcpy((u8*)a + le16_to_cpu(a->value_offset) + 1185 start_ofs, ni->attr_list + start_ofs, 1186 ni->attr_list_size - start_ofs); 1187 dirty_mft = TRUE; 1188 } 1189 goto done; 1190 } 1191 /* 1192 * The attribute list attribute is non-resident, as we are shrinking it 1193 * we need to update the attribute sizes first. 1194 */ 1195 lck_rw_lock_exclusive(&ni->attr_list_rl.lock); 1196 /* Update the attribute sizes. */ 1197 if (ni->attr_list_size < sle64_to_cpu(a->initialized_size)) 1198 a->initialized_size = cpu_to_sle64(ni->attr_list_size); 1199 a->data_size = cpu_to_sle64(ni->attr_list_size); 1200 dirty_mft = TRUE; 1201 alloc_size = (ni->attr_list_size + vol->cluster_size_mask) & 1202 ~vol->cluster_size_mask; 1203 if (alloc_size > sle64_to_cpu(a->allocated_size)) 1204 panic("%s(): alloc_size > sle64_to_cpu(a->allocated_size)\n", 1205 __FUNCTION__); 1206 /* 1207 * If the attribute allocation has not changed we are done with the 1208 * resize and go straight onto the data update. 1209 */ 1210 if (alloc_size == sle64_to_cpu(a->allocated_size)) 1211 goto update_non_resident; 1212 /* 1213 * The allocated size has shrunk by at least one cluster thus we need 1214 * to free the no longer in-use clusters and truncate the runlist 1215 * accordingly. We then also need to update the mapping pairs array in 1216 * the attribute record as well as the allocated size and the highest 1217 * vcn. 1218 */ 1219 err = ntfs_cluster_free_from_rl(vol, ni->attr_list_rl.rl, 1220 alloc_size >> vol->cluster_size_shift, -1, NULL); 1221 if (err) { 1222 ntfs_warning(vol->mp, "Failed to free some allocated clusters " 1223 "belonging to the attribute list attribute of " 1224 "mft_no 0x%llx (error %d). Unmount and run " 1225 "chkdsk to recover the lost space.", 1226 (unsigned long long)ni->mft_no, err); 1227 NVolSetErrors(vol); 1228 } 1229 err = ntfs_rl_truncate_nolock(vol, &ni->attr_list_rl, 1230 alloc_size >> vol->cluster_size_shift); 1231 if (err) { 1232 ntfs_warning(vol->mp, "Failed to truncate attribute list " 1233 "attribute runlist of mft_no 0x%llx (error " 1234 "%d).%s", (unsigned long long)ni->mft_no, err, 1235 es); 1236 goto err; 1237 } 1238 err = ntfs_get_size_for_mapping_pairs(vol, ni->attr_list_rl.rl, 0, -1, 1239 &mp_size); 1240 if (err) { 1241 ntfs_error(vol->mp, "Cannot shrink attribute list attribute " 1242 "of mft_no 0x%llx because determining the " 1243 "size for the mapping pairs failed (error " 1244 "%d).%s", (unsigned long long)ni->mft_no, err, 1245 es); 1246 goto err; 1247 } 1248 err = ntfs_mapping_pairs_build(vol, (s8*)a + 1249 le16_to_cpu(a->mapping_pairs_offset), mp_size, 1250 ni->attr_list_rl.rl, 0, -1, NULL); 1251 if (err) { 1252 ntfs_error(vol->mp, "Cannot shrink attribute list attribute " 1253 "of mft_no 0x%llx because building the " 1254 "mapping pairs failed (error %d).%s", 1255 (unsigned long long)ni->mft_no, err, es); 1256 goto err; 1257 } 1258 a->allocated_size = cpu_to_sle64(alloc_size); 1259 a->highest_vcn = cpu_to_sle64((alloc_size >> vol->cluster_size_shift) - 1260 1); 1261 err = ntfs_attr_record_resize(ctx->m, a, 1262 le16_to_cpu(a->mapping_pairs_offset) + mp_size); 1263 /* Shrinking the attribute record cannot fail. */ 1264 if (err) 1265 panic("%s(): err (non-resident)\n", __FUNCTION__); 1266update_non_resident: 1267 /* Write the modified attribute list attribute value to disk. */ 1268 err = ntfs_rl_write(vol, ni->attr_list, ni->attr_list_size, 1269 &ni->attr_list_rl, start_ofs, 0); 1270 if (err) { 1271 ntfs_error(vol->mp, "Failed to update attribute list " 1272 "attribute of mft_no 0x%llx (error %d).%s", 1273 (unsigned long long)ni->mft_no, err, es); 1274 goto err; 1275 } 1276 lck_rw_unlock_exclusive(&ni->attr_list_rl.lock); 1277done: 1278 ntfs_debug("Done."); 1279out: 1280 /* Make sure the modified mft record is written out. */ 1281 if (dirty_mft) 1282 NInoSetMrecNeedsDirtying(ni); 1283 return err; 1284err: 1285 lck_rw_unlock_exclusive(&ni->attr_list_rl.lock); 1286 NVolSetErrors(vol); 1287 err = EIO; 1288 goto out; 1289} 1290 1291/** 1292 * ntfs_attr_list_sync_extend - sync an inode's attribute list attribute 1293 * @base_ni: base ntfs inode whose attribute list attribute to sync 1294 * @base_m: base mft record of the ntfs inode @base_ni 1295 * @al_ofs: offset into attribute list attribute at which to begin syncing 1296 * @ctx: attribute search context describing attribute being resized 1297 * 1298 * Sync the attribute list attribute of the base ntfs inode @base_ni with mft 1299 * record @base_m by extending it to fit the cached attribute list attribute 1300 * value, then copying the modified, cached attribute list value into place in 1301 * the extended attribute list attribute value starting at offset @al_ofs into 1302 * the attribute list attribute. 1303 * 1304 * @ctx is an attribute search context describing the attribute being resized 1305 * which is causing the attribute list attribute to be added. The search 1306 * context describes a mapped mft record and this is unmapped as needed and 1307 * then mapped again. Also the pointers in the search context are updated with 1308 * the new location of the attribute in the mft record if it is moved and with 1309 * the new location in memory of the re-mapped mft record if it is re-mapped at 1310 * a different virtual address. 1311 * 1312 * Return 0 on success and errno on error. 1313 * 1314 * WARNING: If @ctx is supplied, regardless of whether success or failure is 1315 * returned, you need to check @ctx->is_error and if 1 the @ctx is no 1316 * longer valid, i.e. you need to either call 1317 * ntfs_attr_search_ctx_reinit() or ntfs_attr_search_ctx_put() on it. 1318 * In that case @ctx->error will give you the error code for why the 1319 * mapping of the inode failed. 1320 * 1321 * NOTE: When this function fails it is very likely that the attribute list 1322 * attribute value both in memory and on-disk has been modified but it is 1323 * also very likely that a disparity is left between the in-memory and 1324 * the on-disk value thus the caller should undo their extension to the 1325 * attribute list attribute value and then rewrite the complete attribute 1326 * list attribute starting at offset zero bytes to ensure everything is 1327 * made consistent. 1328 */ 1329errno_t ntfs_attr_list_sync_extend(ntfs_inode *base_ni, MFT_RECORD *base_m, 1330 unsigned al_ofs, ntfs_attr_search_ctx *ctx) 1331{ 1332 leMFT_REF mref; 1333 LCN lcn; 1334 ntfs_volume *vol; 1335 ATTR_RECORD *al_a, *a; 1336 ATTR_LIST_ENTRY *al_entry; 1337 u8 *al_end; 1338 unsigned bytes_needed, bytes_free, alloc_size, name_ofs; 1339 unsigned mp_size, mp_ofs, arec_size, old_arec_size; 1340 errno_t err, err2; 1341 le32 type; 1342 BOOL dirty_mft, remap_needed; 1343 ntfs_attr_search_ctx al_ctx, actx; 1344 ntfs_runlist runlist; 1345 1346 ntfs_debug("Entering for base mft_no 0x%llx, offset 0x%x.", 1347 (unsigned long long)base_ni->mft_no, al_ofs); 1348 if (!NInoAttrList(base_ni)) 1349 panic("%s(): !NInoAttrList(base_ni)\n", __FUNCTION__); 1350 if (al_ofs > base_ni->attr_list_size) 1351 panic("%s(): al_ofs > base_ni->attr_list_size\n", 1352 __FUNCTION__); 1353 /* 1354 * We should never have allowed the attribute list attribute to grow 1355 * above its maximum size. 1356 */ 1357 if (base_ni->attr_list_size > NTFS_MAX_ATTR_LIST_SIZE) 1358 panic("%s(): base_ni->attr_list_size > " 1359 "NTFS_MAX_ATTR_LIST_SIZE\n", __FUNCTION__); 1360 vol = base_ni->vol; 1361 remap_needed = dirty_mft = FALSE; 1362 /* Find the attribute list attribute record in the base mft record. */ 1363 ntfs_attr_search_ctx_init(&al_ctx, base_ni, base_m); 1364 err = ntfs_attr_find_in_mft_record(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 1365 NULL, 0, &al_ctx); 1366 if (err) { 1367 ntfs_error(vol->mp, "Failed to look up attribute list " 1368 "attribute in base mft_no 0x%llx (error %d).", 1369 (unsigned long long)base_ni->mft_no, err); 1370 return err; 1371 } 1372 al_a = al_ctx.a; 1373 arec_size = ntfs_attr_size(al_a); 1374 /* 1375 * We currently only implement extending the attribute list attribute. 1376 * 1377 * Use ntfs_attr_list_sync_shrink() when shrinking it. 1378 */ 1379 if (base_ni->attr_list_size < arec_size) 1380 panic("%s(): base_ni->attr_list_size < arec_size\n", 1381 __FUNCTION__); 1382 /* 1383 * If the size has not changed skip the resize and go straight onto the 1384 * data update. 1385 */ 1386 if (base_ni->attr_list_size == arec_size) { 1387 if (!al_a->non_resident) 1388 goto update_resident; 1389 lck_rw_lock_exclusive(&base_ni->attr_list_rl.lock); 1390 goto update_non_resident; 1391 } 1392 mref = MK_LE_MREF(base_ni->mft_no, base_ni->seq_no); 1393 if (al_a->non_resident) 1394 goto non_resident; 1395 arec_size = le32_to_cpu(al_a->length); 1396 /* Extend the attribute list attribute record value. */ 1397 err = ntfs_resident_attr_value_resize(al_ctx.m, al_a, 1398 base_ni->attr_list_size); 1399 if (!err) { 1400 /* 1401 * Update the pointer in @ctx because the attribute has now 1402 * moved inside the mft record. 1403 */ 1404 if (ctx->ni == base_ni && (u8*)al_a <= (u8*)ctx->a) 1405 ctx->a = (ATTR_RECORD*)((u8*)ctx->a + (signed) 1406 ((signed)le32_to_cpu(al_a->length) - 1407 (signed)arec_size)); 1408update_resident: 1409 dirty_mft = TRUE; 1410 /* 1411 * Update the part of the attribute list attribute record value 1412 * that has changed. 1413 */ 1414 memcpy((u8*)al_a + le16_to_cpu(al_a->value_offset) + al_ofs, 1415 base_ni->attr_list + al_ofs, 1416 base_ni->attr_list_size - al_ofs); 1417 goto done; 1418 } 1419 if (err != ENOSPC) 1420 panic("%s(): err != ENOSPC\n", __FUNCTION__); 1421 /* 1422 * There was not enough space in the mft record to extend the attribute 1423 * list attribute record. Deal with this by making other attributes 1424 * non-resident and/or moving other attributes out to extent mft 1425 * records and if that is not enough make the attribute list attribute 1426 * non-resident. 1427 */ 1428 bytes_needed = ((base_ni->attr_list_size + 7) & ~7) - 1429 ((le32_to_cpu(al_a->value_length) + 7) & ~7); 1430 /* Maximum number of usable bytes in the mft record. */ 1431 bytes_free = le32_to_cpu(base_m->bytes_allocated) - 1432 le16_to_cpu(base_m->attrs_offset); 1433 /* 1434 * If the attribute list attribute has become bigger than fits in an 1435 * mft record switch it to a non-resident attribute record. 1436 */ 1437 if (bytes_needed > bytes_free) 1438 goto make_non_resident; 1439 /* 1440 * Need to unmap the extent mft record for now which means we have to 1441 * mark it dirty first. 1442 */ 1443 if (ctx->ni != base_ni) { 1444 NInoSetMrecNeedsDirtying(ctx->ni); 1445 ntfs_extent_mft_record_unmap(ctx->ni); 1446 remap_needed = TRUE; 1447 } 1448 ntfs_attr_search_ctx_init(&actx, base_ni, base_m); 1449 actx.is_iteration = 1; 1450 while (bytes_needed > le32_to_cpu(base_m->bytes_allocated) - 1451 le32_to_cpu(base_m->bytes_in_use)) { 1452 ntfschar *a_name; 1453 1454 /* Get the next attribute in the mft record. */ 1455 err = ntfs_attr_find_in_mft_record(AT_UNUSED, NULL, 0, NULL, 0, 1456 &actx); 1457 if (err) { 1458 /* 1459 * We reached the end and we still do not have enough 1460 * space to extend the attribute list attribute as a 1461 * resident attribute record thus try to switch it to a 1462 * non-resident attribute record. 1463 */ 1464 if (err == ENOENT) 1465 goto make_non_resident; 1466 /* 1467 * The base mft record is corrupt. There is nothing we 1468 * can do just bail out. Note we are leaving the 1469 * in-memory attribute list attribute out of sync with 1470 * the on-disk attribute list attribute after possibly 1471 * having moved some attributes out of the base mft 1472 * record. We hope the caller will manage to undo the 1473 * extension it did in memory and then write out the 1474 * attribute list attribute to disk. This would bring 1475 * back in sync any changes we just made and if it 1476 * fails the caller will then display appropriate 1477 * corruption announcing error messages. 1478 */ 1479 ntfs_error(vol->mp, "Failed to iterate over attribute " 1480 "records in base mft record 0x%llx " 1481 "(error %d).%s", 1482 (unsigned long long)base_ni->mft_no, 1483 err, dirty_mft ? " Run chkdsk." : ""); 1484 if (dirty_mft) 1485 NVolSetErrors(vol); 1486 goto done; 1487 } 1488 a = actx.a; 1489 /* 1490 * Skip the attribute list attribute itself as that is not 1491 * represented inside itself and it must stay in the base mft 1492 * record. 1493 */ 1494 if (a->type == AT_ATTRIBUTE_LIST) 1495 continue; 1496 /* 1497 * Do not touch standard information and index root attributes 1498 * at this stage. They will be moved out to extent mft records 1499 * further below if really necessary. 1500 * 1501 * TODO: Probably want to add unnamed data attributes to this 1502 * as well. 1503 */ 1504 if (a->type == AT_STANDARD_INFORMATION || 1505 a->type == AT_INDEX_ROOT) { 1506 /* 1507 * If the attribute list attribute has become bigger 1508 * than fits in the mft record switch it to a 1509 * non-resident attribute record. 1510 */ 1511 bytes_free -= le32_to_cpu(a->length); 1512 if (bytes_needed > bytes_free) 1513 goto make_non_resident; 1514 continue; 1515 } 1516 /* 1517 * If the attribute is resident and we can expect the 1518 * non-resident form to be smaller than the resident form 1519 * switch the attribute to non-resident now. 1520 * 1521 * FIXME: We cannot do this at present unless the attribute is 1522 * the attribute being resized as there could be an ntfs inode 1523 * matching this attribute in memory and it would become out of 1524 * date with its metadata if we touch its attribute record. 1525 * 1526 * FIXME: We do not need to do this if this is the attribute 1527 * being resized as the caller will have already tried to make 1528 * the attribute non-resident and this will not have worked or 1529 * we would never have gotten here in the first place. 1530 */ 1531 /* 1532 * Move the attribute out to an extent mft record and update 1533 * its attribute list entry. If it is the attribute to be 1534 * resized, also update the attribute search context to match 1535 * the new attribute. If it is not the attribute to be resized 1536 * but it is in front of the attribute to be resized update the 1537 * attribute search context to account for the removed 1538 * attribute record. 1539 * 1540 * But first find the attribute list entry matching the 1541 * attribute record so it can be updated. 1542 */ 1543 a_name = (ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)); 1544 al_entry = (ATTR_LIST_ENTRY*)base_ni->attr_list; 1545 al_end = base_ni->attr_list + base_ni->attr_list_size; 1546 do { 1547 /* 1548 * The attribute must be present in the attribute list 1549 * attribute or something is corrupt. 1550 */ 1551 if ((u8*)al_entry >= al_end || !al_entry->length) { 1552 ntfs_error(vol->mp, "Attribute type 0x%x not " 1553 "found in attribute list " 1554 "attribute of base mft record " 1555 "0x%llx. Run chkdsk.", 1556 (unsigned)le32_to_cpu(a->type), 1557 (unsigned long long) 1558 base_ni->mft_no); 1559 NVolSetErrors(vol); 1560 err = EIO; 1561 goto done; 1562 } 1563 if (al_entry->mft_reference == mref && 1564 al_entry->instance == a->instance) { 1565 /* 1566 * We found the entry, stop looking but first 1567 * perform a quick sanity check that we really 1568 * do have the correct attribute record. 1569 */ 1570 if (al_entry->type == a->type && 1571 ntfs_are_names_equal( 1572 (ntfschar*)((u8*)al_entry + 1573 al_entry->name_offset), 1574 al_entry->name_length, a_name, 1575 a->name_length, TRUE, 1576 vol->upcase, vol->upcase_len)) 1577 break; 1578 ntfs_error(vol->mp, "Found corrupt attribute " 1579 "list attribute when looking " 1580 "for attribute type 0x%x in " 1581 "attribute list attribute of " 1582 "base mft record 0x%llx. Run " 1583 "chkdsk.", 1584 (unsigned)le32_to_cpu(a->type), 1585 (unsigned long long) 1586 base_ni->mft_no); 1587 NVolSetErrors(vol); 1588 err = EIO; 1589 goto done; 1590 } 1591 /* Go to the next attribute list entry. */ 1592 al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry + 1593 le16_to_cpu(al_entry->length)); 1594 } while (1); 1595 err = ntfs_attr_record_move_for_attr_list_attribute(&actx, 1596 al_entry, ctx, &remap_needed); 1597 if (err) { 1598 ntfs_error(vol->mp, "Failed to move attribute type " 1599 "0x%x out of base mft record 0x%llx " 1600 "and into an extent mft record (error " 1601 "%d).%s", 1602 (unsigned)le32_to_cpu(a->type), 1603 (unsigned long long)base_ni->mft_no, 1604 err, dirty_mft ? " Run chkdsk." : ""); 1605 if (dirty_mft) 1606 NVolSetErrors(vol); 1607 goto done; 1608 } 1609 /* We modified the base mft record. */ 1610 dirty_mft = TRUE; 1611 /* 1612 * If the modified attribute list entry is before the current 1613 * start of attribute list modification we need to sync this 1614 * entry as well. For simplicity we just set @al_ofs to the 1615 * new value thus syncing everything starting at that offset. 1616 */ 1617 if ((u8*)al_entry - base_ni->attr_list < (long)al_ofs) 1618 al_ofs = (u8*)al_entry - base_ni->attr_list; 1619 } 1620 /* 1621 * Find the attribute list attribute record in the base mft record 1622 * again in case it has moved. This cannot fail as we looked it up 1623 * successfully above. 1624 */ 1625 ntfs_attr_search_ctx_reinit(&al_ctx); 1626 err = ntfs_attr_find_in_mft_record(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 1627 NULL, 0, &al_ctx); 1628 if (err) 1629 panic("%s(): err (attribute list attribute not found)\n", 1630 __FUNCTION__); 1631 al_a = al_ctx.a; 1632 arec_size = le32_to_cpu(al_a->length); 1633 /* Try to extend the attribute list attribute record value. */ 1634 err = ntfs_resident_attr_value_resize(base_m, al_a, 1635 base_ni->attr_list_size); 1636 if (!err) { 1637 dirty_mft = TRUE; 1638 /* 1639 * Update the part of the attribute list attribute record value 1640 * that has changed. 1641 */ 1642 memcpy((u8*)al_a + le16_to_cpu(al_a->value_offset) + al_ofs, 1643 base_ni->attr_list + al_ofs, 1644 base_ni->attr_list_size - al_ofs); 1645 /* 1646 * Update the pointer in @ctx because the attribute has now 1647 * moved inside the mft record. 1648 */ 1649 if (ctx->ni == base_ni && (u8*)al_a <= (u8*)ctx->a) 1650 ctx->a = (ATTR_RECORD*)((u8*)ctx->a + (signed)( 1651 (signed)le32_to_cpu(al_a->length) - 1652 (signed)arec_size)); 1653 goto done; 1654 } 1655 if (err != ENOSPC) 1656 panic("%s(): err != ENOSPC\n", __FUNCTION__); 1657 /* 1658 * There was not enough space in the mft record to extend the attribute 1659 * list attribute record. Deal with this by making the attribute list 1660 * attribute non-resident and then extending it. 1661 */ 1662make_non_resident: 1663 /* Work out the new allocated size we need. */ 1664 alloc_size = (base_ni->attr_list_size + vol->cluster_size_mask) & 1665 ~vol->cluster_size_mask; 1666 if (!alloc_size) 1667 panic("%s(): !alloc_size\n", __FUNCTION__); 1668 lck_rw_lock_exclusive(&base_ni->attr_list_rl.lock); 1669 if (al_a->non_resident) 1670 panic("%s(): al_a->non_resident\n", __FUNCTION__); 1671 if (base_ni->attr_list_rl.rl) 1672 panic("%s(): base_ni->attr_list_rl.rl\n", __FUNCTION__); 1673 /* 1674 * Start by allocating clusters to hold the attribute list attribute 1675 * value. 1676 */ 1677 err = ntfs_cluster_alloc(vol, 0, alloc_size >> vol->cluster_size_shift, 1678 -1, DATA_ZONE, TRUE, &base_ni->attr_list_rl); 1679 if (err) { 1680 ntfs_error(vol->mp, "Failed to allocate cluster%s for " 1681 "non-resident attribute list attribute in " 1682 "base mft record 0x%llx (error %d).", 1683 (alloc_size >> vol->cluster_size_shift) > 1 ? 1684 "s" : "", (unsigned long long)base_ni->mft_no, 1685 err); 1686 goto unl_done; 1687 } 1688 /* 1689 * Determine the size of the mapping pairs array. 1690 * 1691 * This cannot fail as we just allocated the runlist so it must be ok. 1692 */ 1693 err = ntfs_get_size_for_mapping_pairs(vol, base_ni->attr_list_rl.rl, 0, 1694 -1, &mp_size); 1695 if (err) 1696 panic("%s(): err (ntfs_get_size_for_mapping_pairs(), " 1697 "resident)\n", __FUNCTION__); 1698 /* Calculate new offsets for the name and the mapping pairs array. */ 1699 name_ofs = (offsetof(ATTR_REC, compressed_size) + 7) & ~7; 1700 mp_ofs = (name_ofs + 7) & ~7; 1701 /* 1702 * Determine the size of the resident part of the now non-resident 1703 * attribute record. 1704 */ 1705 old_arec_size = le32_to_cpu(al_a->length); 1706 arec_size = (mp_ofs + mp_size + 7) & ~7; 1707 /* 1708 * Resize the resident part of the attribute record. 1709 * 1710 * This cannot fail because the attribute list attribute must already 1711 * contain at least three entries, one for the compulsory standard 1712 * information attribute, one for the compulsory filename attribute, 1713 * and one for the compulsory data or index root attribute and a 1714 * resident attribute record containing three attribute list attribute 1715 * entries in its attribute value is larger than the number of bytes 1716 * needed to create a maximum length non-resident attribute record that 1717 * can possibly be created here. And if the inode is corrupt we would 1718 * never have gotten here as this case would be detected when the inode 1719 * is read in. 1720 */ 1721 err = ntfs_attr_record_resize(base_m, al_a, arec_size); 1722 if (err) 1723 panic("%s(): err (ntfs_attr_record_resize())\n", __FUNCTION__); 1724 /* 1725 * Convert the resident part of the attribute record to describe a 1726 * non-resident attribute. 1727 */ 1728 al_a->non_resident = 1; 1729 al_a->name_offset = cpu_to_le16(name_ofs); 1730 /* The flags should be zero already but re-set them anyway. */ 1731 al_a->flags = 0; 1732 /* Setup the fields specific to non-resident attributes. */ 1733 al_a->lowest_vcn = 0; 1734 al_a->mapping_pairs_offset = cpu_to_le16(mp_ofs); 1735 al_a->compression_unit = 0; 1736 memset(&al_a->reservedN, 0, sizeof(al_a->reservedN)); 1737 /* We need to write the whole attribute list attribute. */ 1738 al_ofs = 0; 1739 goto write_non_resident; 1740non_resident: 1741 /* The attribute list attribute is non-resident. */ 1742 lck_rw_lock_exclusive(&base_ni->attr_list_rl.lock); 1743 if (!al_a->non_resident) 1744 panic("%s(): !al_a->non_resident\n", __FUNCTION__); 1745 /* Allocate more disk space if needed. */ 1746 if (base_ni->attr_list_size <= sle64_to_cpu(al_a->allocated_size)) 1747 goto skip_alloc; 1748 /* Work out the new allocated size we need. */ 1749 alloc_size = (base_ni->attr_list_size + vol->cluster_size_mask) & 1750 ~vol->cluster_size_mask; 1751 if (!alloc_size) 1752 panic("%s(): !alloc_size\n", __FUNCTION__); 1753 /* Find the last allocated cluster of the existing runlist. */ 1754 lcn = -1; 1755 if (al_a->allocated_size) { 1756 ntfs_rl_element *rl; 1757 1758 if (!base_ni->attr_list_rl.elements) 1759 panic("%s(): !base_ni->attr_list_rl.elements\n", 1760 __FUNCTION__); 1761 rl = &base_ni->attr_list_rl.rl[base_ni->attr_list_rl.elements - 1762 1]; 1763 while (rl->lcn < 0 && rl > base_ni->attr_list_rl.rl) 1764 rl--; 1765 if (rl->lcn >= 0) 1766 lcn = rl->lcn + rl->length; 1767 } 1768 /* 1769 * Allocate clusters for the extension of the attribute list attribute 1770 * value. 1771 */ 1772 runlist.rl = NULL; 1773 runlist.alloc = runlist.elements = 0; 1774 err = ntfs_cluster_alloc(vol, sle64_to_cpu(al_a->allocated_size) >> 1775 vol->cluster_size_shift, (alloc_size - 1776 sle64_to_cpu(al_a->allocated_size)) >> 1777 vol->cluster_size_shift, lcn, DATA_ZONE, TRUE, 1778 &runlist); 1779 if (err) { 1780 ntfs_error(vol->mp, "Failed to allocate cluster%s to extend " 1781 "non-resident attribute list attribute in " 1782 "base mft record 0x%llx (error %d).", 1783 ((alloc_size - 1784 sle64_to_cpu(al_a->allocated_size)) >> 1785 vol->cluster_size_shift) > 1 ? "s" : "", 1786 (unsigned long long)base_ni->mft_no, err); 1787 goto unl_done; 1788 } 1789 err = ntfs_rl_merge(&base_ni->attr_list_rl, &runlist); 1790 if (err) { 1791 ntfs_error(vol->mp, "Failed to extend attribute list " 1792 "attribute in base mft record 0x%llx because " 1793 "the runlist merge failed (error %d).", 1794 (unsigned long long)base_ni->mft_no, err); 1795 err2 = ntfs_cluster_free_from_rl(vol, runlist.rl, 0, -1, NULL); 1796 if (err2) { 1797 ntfs_warning(vol->mp, "Failed to release allocated " 1798 "cluster(s) in error code path (error " 1799 "%d). Run chkdsk to recover the lost " 1800 "cluster(s).", err2); 1801 NVolSetErrors(vol); 1802 } 1803 OSFree(runlist.rl, runlist.alloc, ntfs_malloc_tag); 1804 goto unl_done; 1805 } 1806 /* Determine the size of the mapping pairs array. */ 1807 err = ntfs_get_size_for_mapping_pairs(vol, base_ni->attr_list_rl.rl, 0, 1808 -1, &mp_size); 1809 if (err) 1810 panic("%s(): err (ntfs_get_size_for_mapping_pairs(), " 1811 "non-resident)\n", __FUNCTION__); 1812 mp_ofs = le16_to_cpu(al_a->mapping_pairs_offset); 1813 old_arec_size = le32_to_cpu(al_a->length); 1814 /* Extend the attribute record to fit the bigger mapping pairs array. */ 1815 err = ntfs_attr_record_resize(base_m, al_a, mp_ofs + mp_size); 1816 if (!err) 1817 goto write_non_resident; 1818 if (err != ENOSPC) 1819 panic("%s(): err != ENOSPC\n", __FUNCTION__); 1820 /* 1821 * Need to unmap the extent mft record for now which means we have to 1822 * mark it dirty first. 1823 */ 1824 if (ctx->ni != base_ni) { 1825 NInoSetMrecNeedsDirtying(ctx->ni); 1826 ntfs_extent_mft_record_unmap(ctx->ni); 1827 remap_needed = TRUE; 1828 } 1829 bytes_needed = ((mp_ofs + mp_size + 7) & ~7) - old_arec_size; 1830 type = AT_UNUSED; 1831next_pass: 1832 ntfs_attr_search_ctx_init(&actx, base_ni, base_m); 1833 actx.is_iteration = 1; 1834 while (bytes_needed > le32_to_cpu(base_m->bytes_allocated) - 1835 le32_to_cpu(base_m->bytes_in_use)) { 1836 ntfschar *a_name; 1837 1838 /* Get the next attribute in the mft record. */ 1839 err = ntfs_attr_find_in_mft_record(type, NULL, 0, NULL, 0, 1840 &actx); 1841 if (err) { 1842 if (err == ENOENT) { 1843 /* 1844 * If we have more passes to go do the next 1845 * pass which will try harder to move things 1846 * out of the way. 1847 */ 1848 if (type == AT_UNUSED) { 1849 type = AT_DATA; 1850 goto next_pass; 1851 } 1852 /* 1853 * TODO: Need to get these cases triggerred and 1854 * then need to run chkdsk to check for 1855 * validity of moving these attributes out of 1856 * the base mft record. 1857 */ 1858 if (type == AT_DATA) { 1859 type = AT_INDEX_ROOT; 1860 goto next_pass; 1861 } 1862 if (type == AT_INDEX_ROOT) { 1863 type = AT_STANDARD_INFORMATION; 1864 goto next_pass; 1865 } 1866 /* 1867 * We moved all attributes out of the base mft 1868 * record and we still do not have enough space 1869 * to extend the attribute list attribute. 1870 * 1871 * TODO: The only thing that can help is to 1872 * defragment the attribute list attribute 1873 * and/or other fragmented attributes. The 1874 * former would make the runlist of the 1875 * attribute list attribute directly smaller 1876 * thus it may then fit and the latter would 1877 * reduce the number of extent attributes and 1878 * thus the number of attribute list attribute 1879 * entries which would indirectly make the 1880 * runlist of the attribute list attribute 1881 * smaller. For now we do not implement 1882 * defragmentation so there is nothing we can 1883 * do when this case occurs. It should be 1884 * very, very hard to trigger this case though 1885 * and I doubt even the Windows NTFS driver 1886 * deals with it so we are not doing any worse 1887 * than Windows so I think leaving things as 1888 * they are is acceptable. 1889 * 1890 * The caller will hopefully undo what they did 1891 * thus shrinking the attribute list attribute 1892 * again which will then fit and they will then 1893 * rewrite it which will fix everything we have 1894 * failed to do nicely. 1895 */ 1896 ntfs_error(vol->mp, "The runlist of the " 1897 "attribute list attribute of " 1898 "mft_no 0x%llx is too large to " 1899 "fit in the base mft record. " 1900 "You need to defragment your " 1901 "volume and then try again.%s", 1902 (unsigned long long) 1903 base_ni->mft_no, dirty_mft ? 1904 " Run chkdsk." : ""); 1905 if (dirty_mft) 1906 NVolSetErrors(vol); 1907 err = ENOSPC; 1908 goto unl_done; 1909 } 1910 /* 1911 * The base mft record is corrupt. There is nothing we 1912 * can do just bail out. Note we are leaving the 1913 * in-memory attribute list attribute out of sync with 1914 * the on-disk attribute list attribute after possibly 1915 * having moved some attributes out of the base mft 1916 * record. We hope the caller will manage to undo the 1917 * extension it did in memory and then write out the 1918 * attribute list attribute to disk. This would bring 1919 * back in sync any changes we just made and if it 1920 * fails the caller will then display appropriate 1921 * corruption announcing error messages. 1922 */ 1923 ntfs_error(vol->mp, "Failed to iterate over attribute " 1924 "records in base mft record 0x%llx " 1925 "(error %d).%s", 1926 (unsigned long long)base_ni->mft_no, 1927 err, dirty_mft ? " Run chkdsk." : ""); 1928 if (dirty_mft) 1929 NVolSetErrors(vol); 1930 goto unl_done; 1931 } 1932 a = actx.a; 1933 if (type == AT_UNUSED) { 1934 /* 1935 * Skip the attribute list attribute itself as that is 1936 * not represented inside itself and we cannot move it 1937 * out anyway. 1938 * 1939 * Also, do not touch standard information, index root, 1940 * and unnamed $DATA attributes. They will be moved 1941 * out to extent mft records in later passes if really 1942 * necessary. 1943 */ 1944 if (a->type == AT_ATTRIBUTE_LIST || 1945 a->type == AT_STANDARD_INFORMATION || 1946 a->type == AT_INDEX_ROOT || 1947 (a->type == AT_DATA && 1948 !a->name_length)) 1949 continue; 1950 } 1951 /* 1952 * If the attribute is resident and we can expect the 1953 * non-resident form to be smaller than the resident form 1954 * switch the attribute to non-resident now. 1955 * 1956 * FIXME: We cannot do this at present unless the attribute is 1957 * the attribute being resized as there could be an ntfs inode 1958 * matching this attribute in memory and it would become out of 1959 * date with its metadata if we touch its attribute record. 1960 * 1961 * FIXME: We do not need to do this if this is the attribute 1962 * being resized as the caller will have already tried to make 1963 * the attribute non-resident and this will not have worked or 1964 * we would never have gotten here in the first place. 1965 */ 1966 /* 1967 * Move the attribute out to an extent mft record and update 1968 * its attribute list entry. If it is the attribute to be 1969 * resized, also update the attribute search context to match 1970 * the new attribute. If it is not the attribute to be resized 1971 * but it is in front of the attribute to be resized update the 1972 * attribute search context to account for the removed 1973 * attribute record. 1974 * 1975 * But first find the attribute list entry matching the 1976 * attribute record so it can be updated. 1977 */ 1978 a_name = (ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)); 1979 al_entry = (ATTR_LIST_ENTRY*)base_ni->attr_list; 1980 al_end = base_ni->attr_list + base_ni->attr_list_size; 1981 do { 1982 /* 1983 * The attribute must be present in the attribute list 1984 * attribute or something is corrupt. 1985 */ 1986 if ((u8*)al_entry >= al_end || !al_entry->length) { 1987 ntfs_error(vol->mp, "Attribute type 0x%x not " 1988 "found in attribute list " 1989 "attribute of base mft record " 1990 "0x%llx. Run chkdsk.", 1991 (unsigned)le32_to_cpu(a->type), 1992 (unsigned long long) 1993 base_ni->mft_no); 1994 NVolSetErrors(vol); 1995 err = EIO; 1996 goto unl_done; 1997 } 1998 if (al_entry->mft_reference == mref && 1999 al_entry->instance == a->instance) { 2000 /* 2001 * We found the entry, stop looking but first 2002 * perform a quick sanity check that we really 2003 * do have the correct attribute record. 2004 */ 2005 if (al_entry->type == a->type && 2006 ntfs_are_names_equal( 2007 (ntfschar*)((u8*)al_entry + 2008 al_entry->name_offset), 2009 al_entry->name_length, a_name, 2010 a->name_length, TRUE, 2011 vol->upcase, vol->upcase_len)) 2012 break; 2013 ntfs_error(vol->mp, "Found corrupt attribute " 2014 "list attribute when looking " 2015 "for attribute type 0x%x in " 2016 "attribute list attribute of " 2017 "base mft record 0x%llx. Run " 2018 "chkdsk.", 2019 (unsigned)le32_to_cpu(a->type), 2020 (unsigned long long) 2021 base_ni->mft_no); 2022 NVolSetErrors(vol); 2023 err = EIO; 2024 goto unl_done; 2025 } 2026 /* Go to the next attribute list entry. */ 2027 al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry + 2028 le16_to_cpu(al_entry->length)); 2029 } while (1); 2030 err = ntfs_attr_record_move_for_attr_list_attribute(&actx, 2031 al_entry, ctx, &remap_needed); 2032 if (err) { 2033 ntfs_error(vol->mp, "Failed to move attribute type " 2034 "0x%x out of base mft record 0x%llx " 2035 "and into an extent mft record (error " 2036 "%d).%s", 2037 (unsigned)le32_to_cpu(a->type), 2038 (unsigned long long)base_ni->mft_no, 2039 err, dirty_mft ? " Run chkdsk." : ""); 2040 if (dirty_mft) 2041 NVolSetErrors(vol); 2042 goto unl_done; 2043 } 2044 /* We modified the base mft record. */ 2045 dirty_mft = TRUE; 2046 /* 2047 * If the modified attribute list entry is before the current 2048 * start of attribute list modification we need to sync this 2049 * entry as well. For simplicity we just set @al_ofs to the 2050 * new value thus syncing everything starting at that offset. 2051 */ 2052 if ((u8*)al_entry - base_ni->attr_list < (long)al_ofs) 2053 al_ofs = (u8*)al_entry - base_ni->attr_list; 2054 } 2055 /* 2056 * Find the attribute list attribute record in the base mft record 2057 * again in case it has moved. This cannot fail as we looked it up 2058 * successfully above. 2059 */ 2060 ntfs_attr_search_ctx_reinit(&al_ctx); 2061 err = ntfs_attr_find_in_mft_record(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 2062 NULL, 0, &al_ctx); 2063 if (err) 2064 panic("%s(): err (attribute list attribute not found 2)\n", 2065 __FUNCTION__); 2066 al_a = al_ctx.a; 2067 /* 2068 * Extend the attribute record to fit the bigger mapping pairs array. 2069 * This cannot fail as we only get here if we managed to create enough 2070 * space. 2071 */ 2072 err = ntfs_attr_record_resize(base_m, al_a, mp_ofs + mp_size); 2073 if (err) 2074 panic("%s(): err (ntfs_attr_record_resize())\n", __FUNCTION__); 2075write_non_resident: 2076 dirty_mft = TRUE; 2077 /* 2078 * Update the pointer in @ctx because the attribute has now moved 2079 * inside the mft record. 2080 */ 2081 if (ctx->ni == base_ni && (u8*)al_a <= (u8*)ctx->a) 2082 ctx->a = (ATTR_RECORD*)((u8*)ctx->a + 2083 (signed)((signed)le32_to_cpu(al_a->length) - 2084 (signed)old_arec_size)); 2085 /* 2086 * Generate the mapping pairs array in place. This cannot fail as we 2087 * determined the amount of space we need already and have ensured that 2088 * we have enough space available. 2089 */ 2090 err = ntfs_mapping_pairs_build(vol, (s8*)al_a + mp_ofs, 2091 le32_to_cpu(al_a->length) - mp_ofs, 2092 base_ni->attr_list_rl.rl, 0, -1, NULL); 2093 if (err) 2094 panic("%s(): err (ntfs_mapping_pairs_build())\n", __FUNCTION__); 2095 /* Update the highest_vcn. */ 2096 al_a->highest_vcn = cpu_to_sle64((alloc_size - 1) >> 2097 vol->cluster_size_shift); 2098 al_a->allocated_size = cpu_to_sle64(alloc_size); 2099skip_alloc: 2100 /* Update the data size. */ 2101 dirty_mft = TRUE; 2102 al_a->data_size = cpu_to_sle64(base_ni->attr_list_size); 2103update_non_resident: 2104 /* 2105 * Write the modified part of the attribute list attribute to disk. 2106 * 2107 * ntfs_rl_write() will mark the volume dirty and ask the user to run 2108 * chkdsk. 2109 */ 2110 err = ntfs_rl_write(vol, base_ni->attr_list, base_ni->attr_list_size, 2111 &base_ni->attr_list_rl, al_ofs, 0); 2112 if (err) 2113 ntfs_error(vol->mp, "Failed to update on-disk attribute list " 2114 "attribute of mft_no 0x%llx (error %d).", 2115 (unsigned long long)base_ni->mft_no, err); 2116 /* Update the initialized size. */ 2117 if (al_a->initialized_size != al_a->data_size) { 2118 dirty_mft = TRUE; 2119 al_a->initialized_size = al_a->data_size; 2120 } 2121unl_done: 2122 lck_rw_unlock_exclusive(&base_ni->attr_list_rl.lock); 2123done: 2124 /* Make sure the modified base mft record is written out. */ 2125 if (dirty_mft) 2126 NInoSetMrecNeedsDirtying(base_ni); 2127 if (remap_needed && ctx->ni != base_ni) { 2128 MFT_RECORD *em; 2129 2130retry_map: 2131 err2 = ntfs_mft_record_map(ctx->ni, &em); 2132 if (err2) { 2133 /* 2134 * Something bad has happened. If out of memory retry 2135 * till it succeeds. Any other errors are fatal and we 2136 * return the error code in @ctx->m. 2137 * 2138 * We do not need to undo anything as the extension of 2139 * the attribute list attribute has already been done 2140 * and if it failed the failure has already been dealt 2141 * with. 2142 * 2143 * We just need to fudge things so the caller can 2144 * reinit and/or put the search context safely. 2145 */ 2146 if (err2 == ENOMEM) { 2147 (void)thread_block(THREAD_CONTINUE_NULL); 2148 goto retry_map; 2149 } 2150 ctx->is_error = 1; 2151 ctx->error = err2; 2152 ctx->ni = base_ni; 2153 } 2154 if (!ctx->is_error && em != ctx->m) { 2155 ctx->a = (ATTR_RECORD*)((u8*)em + 2156 ((u8*)ctx->a - (u8*)ctx->m)); 2157 ctx->m = em; 2158 } 2159 } 2160 return err; 2161} 2162 2163/** 2164 * ntfs_attr_list_entries_delete - delete one or more attribute list entries 2165 * @ni: base ntfs inode whose attribute list to delete from 2166 * @start_entry: first attribute list entry to be deleted 2167 * @end_entry: attribute list entry at which to stop deleting 2168 * 2169 * Delete the attribute list attribute entries starting at @start_entry and 2170 * finishing at @end_entry (@end_entry itself is not deleted) from the 2171 * attribute list attribute belonging to the base ntfs inode @ni. 2172 * 2173 * This function cannot fail. 2174 */ 2175void ntfs_attr_list_entries_delete(ntfs_inode *ni, 2176 ATTR_LIST_ENTRY *start_entry, ATTR_LIST_ENTRY *end_entry) 2177{ 2178 unsigned to_delete, to_copy, new_alloc; 2179 2180 /* 2181 * Determine the number of bytes to be deleted from the attribute list 2182 * attribute. 2183 */ 2184 to_delete = (u8*)end_entry - (u8*)start_entry; 2185 ntfs_debug("Entering for base mft_no 0x%llx, attr type 0x%x, " 2186 "start_entry length 0x%x, start_entry offset 0x%lx, " 2187 "end_entry offset 0x%lx, bytes to_delete 0x%x.", 2188 (unsigned long long)ni->mft_no, 2189 le32_to_cpu(start_entry->type), 2190 (unsigned)le16_to_cpu(start_entry->length), 2191 (unsigned long)((u8*)start_entry - ni->attr_list), 2192 (unsigned long)((u8*)end_entry - ni->attr_list), 2193 to_delete); 2194 /* 2195 * Determine the number of bytes in the attribute list attribute 2196 * following the entries to be deleted. 2197 */ 2198 to_copy = ni->attr_list_size - ((u8*)end_entry - ni->attr_list); 2199 /* 2200 * Determine the new size and allocated size for the attribute list 2201 * attribute. 2202 */ 2203 ni->attr_list_size -= to_delete; 2204 new_alloc = (ni->attr_list_size + NTFS_ALLOC_BLOCK - 1) & 2205 ~(NTFS_ALLOC_BLOCK - 1); 2206 /* 2207 * @new_alloc cannot reach zero because the attribute list has to at 2208 * least contain the standard information attribute. 2209 */ 2210 if (!new_alloc) 2211 panic("%s(): !new_alloc\n", __FUNCTION__); 2212 /* 2213 * Remove the attribute list entries to be deleted from the in memory 2214 * copy of the attribute list attribute and reallocate the attribute 2215 * list buffer if it shrinks past an NTFS_ALLOC_BLOCK byte boundary. 2216 */ 2217 if (new_alloc >= ni->attr_list_alloc) { 2218 if (new_alloc > ni->attr_list_alloc) 2219 panic("%s(): (new_alloc > ni->attr_list_alloc\n", 2220 __FUNCTION__); 2221cut: 2222 /* 2223 * If the end entry is not the last entry, move all following 2224 * entries forward on top of the entries to be deleted. 2225 */ 2226 if (to_copy > 0) 2227 memmove(start_entry, end_entry, to_copy); 2228 } else { 2229 u8 *tmp; 2230 unsigned entry_ofs; 2231 2232 tmp = OSMalloc(new_alloc, ntfs_malloc_tag); 2233 /* 2234 * If the allocation fails then do not shrink the buffer and 2235 * just cut out the entries to be deleted which will waste some 2236 * memory but is otherwise ok. 2237 */ 2238 if (!tmp) 2239 goto cut; 2240 entry_ofs = (u8*)start_entry - ni->attr_list; 2241 memcpy(tmp, ni->attr_list, entry_ofs); 2242 if (to_copy > 0) 2243 memcpy(tmp + entry_ofs, end_entry, to_copy); 2244 OSFree(ni->attr_list, ni->attr_list_alloc, ntfs_malloc_tag); 2245 ni->attr_list_alloc = new_alloc; 2246 ni->attr_list = tmp; 2247 } 2248 ntfs_debug("Done."); 2249} 2250