1 /* 2 libparted - a library for manipulating disk partitions 3 Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #ifndef DISCOVER_ONLY 20 21 #include <config.h> 22 23 #include <parted/parted.h> 24 #include <parted/endian.h> 25 #include <parted/debug.h> 26 #include <stdint.h> 27 28 #if ENABLE_NLS 29 # include <libintl.h> 30 # define _(String) dgettext (PACKAGE, String) 31 #else 32 # define _(String) (String) 33 #endif /* ENABLE_NLS */ 34 35 #include "hfs.h" 36 #include "file_plus.h" 37 #include "advfs_plus.h" 38 #include "cache.h" 39 #include "journal.h" 40 41 #include "reloc_plus.h" 42 43 /* This function moves data of size blocks starting at block *ptr_fblock 44 to block *ptr_to_fblock */ 45 /* return new start or -1 on failure */ 46 /* -1 is ok because there can only be 2^32-1 blocks, so the max possible 47 last one is 2^32-2 (and anyway it contains Alternate VH), so 48 -1 (== 2^32-1[2^32]) never represent a valid block */ 49 static int 50 hfsplus_effect_move_extent (PedFileSystem *fs, unsigned int *ptr_fblock, 51 unsigned int *ptr_to_fblock, unsigned int size) 52 { 53 HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) 54 fs->type_specific; 55 unsigned int i, ok = 0; 56 unsigned int next_to_fblock; 57 unsigned int start, stop; 58 59 PED_ASSERT (hfsp_block != NULL, return -1); 60 PED_ASSERT (*ptr_to_fblock <= *ptr_fblock, return -1); 61 /* quiet GCC */ 62 next_to_fblock = start = stop = 0; 63 64 /* 65 Try to fit the extent AT or _BEFORE_ the wanted place, 66 or then in the gap between dest and source. 67 If failed try to fit the extent after source, for 2 pass relocation 68 The extent is always copied in a non overlapping way 69 */ 70 71 /* Backward search */ 72 /* 1 pass relocation AT or BEFORE *ptr_to_fblock */ 73 if (*ptr_to_fblock != *ptr_fblock) { 74 start = stop = *ptr_fblock < *ptr_to_fblock+size ? 75 *ptr_fblock : *ptr_to_fblock+size; 76 while (start && stop-start != size) { 77 --start; 78 if (TST_BLOC_OCCUPATION(priv_data->alloc_map,start)) 79 stop = start; 80 } 81 ok = (stop-start == size); 82 } 83 84 /* Forward search */ 85 /* 1 pass relocation in the gap merged with 2 pass reloc after source */ 86 if (!ok && *ptr_to_fblock != *ptr_fblock) { 87 start = stop = *ptr_to_fblock+1; 88 while (stop < PED_BE32_TO_CPU(priv_data->vh->total_blocks) 89 && stop-start != size) { 90 if (TST_BLOC_OCCUPATION(priv_data->alloc_map,stop)) 91 start = stop + 1; 92 ++stop; 93 } 94 ok = (stop-start == size); 95 } 96 97 /* new non overlapping room has been found ? */ 98 if (ok) { 99 /* enough room */ 100 PedSector abs_sector; 101 unsigned int ai, j, block; 102 unsigned int block_sz = (PED_BE32_TO_CPU ( 103 priv_data->vh->block_size) 104 / PED_SECTOR_SIZE_DEFAULT); 105 106 if (stop > *ptr_to_fblock && stop <= *ptr_fblock) 107 /* Fit in the gap */ 108 next_to_fblock = stop; 109 else 110 /* Before or after the gap */ 111 next_to_fblock = *ptr_to_fblock; 112 113 /* move blocks */ 114 for (i = 0; i < size; /*i++*/) { 115 j = size - i; j = (j < hfsp_block_count) ? 116 j : hfsp_block_count ; 117 118 abs_sector = (PedSector) (*ptr_fblock + i) * block_sz; 119 if (!ped_geometry_read (priv_data->plus_geom, 120 hfsp_block, abs_sector, 121 block_sz * j)) 122 return -1; 123 124 abs_sector = (PedSector) (start + i) * block_sz; 125 if (!ped_geometry_write (priv_data->plus_geom, 126 hfsp_block, abs_sector, 127 block_sz * j)) 128 return -1; 129 130 for (ai = i+j; i < ai; i++) { 131 /* free source block */ 132 block = *ptr_fblock + i; 133 CLR_BLOC_OCCUPATION(priv_data->alloc_map,block); 134 SET_BLOC_OCCUPATION(priv_data->dirty_alloc_map, 135 block/(PED_SECTOR_SIZE_DEFAULT*8)); 136 137 /* set dest block */ 138 block = start + i; 139 SET_BLOC_OCCUPATION(priv_data->alloc_map,block); 140 SET_BLOC_OCCUPATION(priv_data->dirty_alloc_map, 141 block/(PED_SECTOR_SIZE_DEFAULT*8)); 142 } 143 } 144 if (!ped_geometry_sync_fast (priv_data->plus_geom)) 145 return -1; 146 147 *ptr_fblock += size; 148 *ptr_to_fblock = next_to_fblock; 149 } else { 150 if (*ptr_fblock != *ptr_to_fblock) 151 /* not enough room */ 152 ped_exception_throw (PED_EXCEPTION_WARNING, 153 PED_EXCEPTION_IGNORE, 154 _("An extent has not been relocated.")); 155 start = *ptr_fblock; 156 *ptr_fblock = *ptr_to_fblock = start + size; 157 } 158 159 return start; 160 } 161 162 /* Returns 0 on error */ 163 /* 1 on succes */ 164 int 165 hfsplus_update_vh (PedFileSystem *fs) 166 { 167 HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) 168 fs->type_specific; 169 uint8_t node[PED_SECTOR_SIZE_DEFAULT]; 170 171 if (!ped_geometry_read (priv_data->plus_geom, node, 2, 1)) 172 return 0; 173 memcpy (node, priv_data->vh, sizeof (HfsPVolumeHeader)); 174 if (!ped_geometry_write (priv_data->plus_geom, node, 2, 1) 175 || !ped_geometry_write (priv_data->plus_geom, node, 176 priv_data->plus_geom->length - 2, 1) 177 || !ped_geometry_sync_fast (priv_data->plus_geom)) 178 return 0; 179 return 1; 180 } 181 182 static int 183 hfsplus_do_move (PedFileSystem* fs, unsigned int *ptr_src, 184 unsigned int *ptr_dest, HfsCPrivateCache* cache, 185 HfsCPrivateExtent* ref) 186 { 187 HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) 188 fs->type_specific; 189 HfsPPrivateFile* file; 190 HfsPExtDescriptor* extent; 191 HfsCPrivateExtent* move; 192 int new_start; 193 194 new_start = hfsplus_effect_move_extent (fs, ptr_src, ptr_dest, 195 ref->ext_length); 196 197 if (new_start == -1) return -1; 198 199 if (ref->ext_start != (unsigned) new_start) { 200 switch (ref->where) { 201 /************ VH ************/ 202 case CR_PRIM_CAT : 203 priv_data->catalog_file 204 ->first[ref->ref_index].start_block = 205 PED_CPU_TO_BE32(new_start); 206 goto CR_PRIM; 207 case CR_PRIM_EXT : 208 priv_data->extents_file 209 ->first[ref->ref_index].start_block = 210 PED_CPU_TO_BE32(new_start); 211 goto CR_PRIM; 212 case CR_PRIM_ATTR : 213 priv_data->attributes_file 214 ->first[ref->ref_index].start_block = 215 PED_CPU_TO_BE32(new_start); 216 goto CR_PRIM; 217 case CR_PRIM_ALLOC : 218 priv_data->allocation_file 219 ->first[ref->ref_index].start_block = 220 PED_CPU_TO_BE32(new_start); 221 goto CR_PRIM; 222 case CR_PRIM_START : 223 /* No startup file opened */ 224 CR_PRIM : 225 extent = ( HfsPExtDescriptor* ) 226 ( (uint8_t*)priv_data->vh + ref->ref_offset ); 227 extent[ref->ref_index].start_block = 228 PED_CPU_TO_BE32(new_start); 229 if (!hfsplus_update_vh(fs)) 230 return -1; 231 break; 232 233 /************** BTREE *************/ 234 case CR_BTREE_CAT_JIB : 235 if (!hfsj_update_jib(fs, new_start)) 236 return -1; 237 goto BTREE_CAT; 238 239 case CR_BTREE_CAT_JL : 240 if (!hfsj_update_jl(fs, new_start)) 241 return -1; 242 goto BTREE_CAT; 243 244 BTREE_CAT: 245 case CR_BTREE_CAT : 246 file = priv_data->catalog_file; 247 goto CR_BTREE; 248 249 case CR_BTREE_ATTR : 250 file = priv_data->attributes_file; 251 goto CR_BTREE; 252 253 case CR_BTREE_EXT_ATTR : 254 if (priv_data->attributes_file 255 ->cache[ref->ref_index].start_block 256 == PED_CPU_TO_BE32(ref->ext_start)) 257 priv_data->attributes_file 258 ->cache[ref->ref_index].start_block = 259 PED_CPU_TO_BE32(new_start); 260 goto CR_BTREE_EXT; 261 case CR_BTREE_EXT_CAT : 262 if (priv_data->catalog_file 263 ->cache[ref->ref_index].start_block 264 == PED_CPU_TO_BE32(ref->ext_start)) 265 priv_data->catalog_file 266 ->cache[ref->ref_index].start_block = 267 PED_CPU_TO_BE32(new_start); 268 goto CR_BTREE_EXT; 269 case CR_BTREE_EXT_ALLOC : 270 if (priv_data->allocation_file 271 ->cache[ref->ref_index].start_block 272 == PED_CPU_TO_BE32(ref->ext_start)) 273 priv_data->allocation_file 274 ->cache[ref->ref_index].start_block = 275 PED_CPU_TO_BE32(new_start); 276 goto CR_BTREE_EXT; 277 case CR_BTREE_EXT_START : 278 /* No startup file opened */ 279 CR_BTREE_EXT : 280 case CR_BTREE_EXT_0 : 281 file = priv_data->extents_file; 282 283 CR_BTREE : 284 PED_ASSERT(PED_SECTOR_SIZE_DEFAULT * ref->sect_by_block 285 > ref->ref_offset, return -1 ); 286 if (!hfsplus_file_read(file, hfsp_block, 287 (PedSector)ref->ref_block * ref->sect_by_block, 288 ref->sect_by_block)) 289 return -1; 290 extent = ( HfsPExtDescriptor* ) 291 ( hfsp_block + ref->ref_offset ); 292 extent[ref->ref_index].start_block = 293 PED_CPU_TO_BE32(new_start); 294 if (!hfsplus_file_write(file, hfsp_block, 295 (PedSector)ref->ref_block * ref->sect_by_block, 296 ref->sect_by_block) 297 || !ped_geometry_sync_fast (priv_data->plus_geom)) 298 return -1; 299 break; 300 301 /********** BUG *********/ 302 default : 303 ped_exception_throw ( 304 PED_EXCEPTION_ERROR, 305 PED_EXCEPTION_CANCEL, 306 _("A reference to an extent comes from a place " 307 "it should not. You should check the file " 308 "system!")); 309 return -1; 310 break; 311 } 312 313 move = hfsc_cache_move_extent(cache, ref->ext_start, new_start); 314 if (!move) return -1; 315 PED_ASSERT(move == ref, return -1); 316 } 317 318 return new_start; 319 } 320 321 /* save any dirty sector of the allocation bitmap file */ 322 static int 323 hfsplus_save_allocation(PedFileSystem *fs) 324 { 325 HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) 326 fs->type_specific; 327 unsigned int map_sectors, i, j; 328 int ret = 1; 329 330 map_sectors = ( PED_BE32_TO_CPU (priv_data->vh->total_blocks) 331 + PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) / (PED_SECTOR_SIZE_DEFAULT * 8); 332 333 for (i = 0; i < map_sectors;) { 334 for (j = i; 335 (TST_BLOC_OCCUPATION(priv_data->dirty_alloc_map,j)); 336 ++j) 337 CLR_BLOC_OCCUPATION(priv_data->dirty_alloc_map,j); 338 if (j-i) { 339 ret = hfsplus_file_write(priv_data->allocation_file, 340 priv_data->alloc_map + i * PED_SECTOR_SIZE_DEFAULT, 341 i, j-i) && ret; 342 i = j; 343 } else 344 ++i; 345 } 346 347 return ret; 348 } 349 350 /* This function moves an extent starting at block fblock 351 to block to_fblock if there's enough room */ 352 /* Return 1 if everything was fine */ 353 /* Return -1 if an error occurred */ 354 /* Return 0 if no extent was found */ 355 static int 356 hfsplus_move_extent_starting_at (PedFileSystem *fs, unsigned int *ptr_fblock, 357 unsigned int *ptr_to_fblock, 358 HfsCPrivateCache* cache) 359 { 360 HfsCPrivateExtent* ref; 361 unsigned int old_start, new_start; 362 363 ref = hfsc_cache_search_extent(cache, *ptr_fblock); 364 if (!ref) return 0; 365 366 old_start = *ptr_fblock; 367 new_start = hfsplus_do_move(fs, ptr_fblock, ptr_to_fblock, cache, ref); 368 if (new_start == (unsigned)-1) return -1; 369 if (new_start > old_start) { 370 new_start = hfsplus_do_move(fs, &new_start, ptr_to_fblock, 371 cache, ref); 372 if (new_start == (unsigned)-1 || new_start > old_start) 373 return -1; 374 } 375 376 hfsplus_save_allocation(fs); 377 return 1; 378 } 379 380 static int 381 hfsplus_cache_from_vh(HfsCPrivateCache* cache, PedFileSystem* fs, 382 PedTimer* timer) 383 { 384 HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) 385 fs->type_specific; 386 HfsPExtDescriptor* extent; 387 unsigned int j; 388 389 extent = priv_data->vh->allocation_file.extents; 390 for (j = 0; j < HFSP_EXT_NB; ++j) { 391 if (!extent[j].block_count) break; 392 if (!hfsc_cache_add_extent( 393 cache, 394 PED_BE32_TO_CPU(extent[j].start_block), 395 PED_BE32_TO_CPU(extent[j].block_count), 396 0, /* unused for vh */ 397 ((uint8_t*)extent) - ((uint8_t*)priv_data->vh), 398 1, /* load / save 1 sector */ 399 CR_PRIM_ALLOC, 400 j ) 401 ) 402 return 0; 403 } 404 405 extent = priv_data->vh->extents_file.extents; 406 for (j = 0; j < HFSP_EXT_NB; ++j) { 407 if (!extent[j].block_count) break; 408 if (!hfsc_cache_add_extent( 409 cache, 410 PED_BE32_TO_CPU(extent[j].start_block), 411 PED_BE32_TO_CPU(extent[j].block_count), 412 0, /* unused for vh */ 413 ((uint8_t*)extent) - ((uint8_t*)priv_data->vh), 414 1, /* load / save 1 sector */ 415 CR_PRIM_EXT, 416 j ) 417 ) 418 return 0; 419 } 420 421 extent = priv_data->vh->catalog_file.extents; 422 for (j = 0; j < HFSP_EXT_NB; ++j) { 423 if (!extent[j].block_count) break; 424 if (!hfsc_cache_add_extent( 425 cache, 426 PED_BE32_TO_CPU(extent[j].start_block), 427 PED_BE32_TO_CPU(extent[j].block_count), 428 0, /* unused for vh */ 429 ((uint8_t*)extent) - ((uint8_t*)priv_data->vh), 430 1, /* load / save 1 sector */ 431 CR_PRIM_CAT, 432 j ) 433 ) 434 return 0; 435 } 436 437 extent = priv_data->vh->attributes_file.extents; 438 for (j = 0; j < HFSP_EXT_NB; ++j) { 439 if (!extent[j].block_count) break; 440 if (!hfsc_cache_add_extent( 441 cache, 442 PED_BE32_TO_CPU(extent[j].start_block), 443 PED_BE32_TO_CPU(extent[j].block_count), 444 0, /* unused for vh */ 445 ((uint8_t*)extent) - ((uint8_t*)priv_data->vh), 446 1, /* load / save 1 sector */ 447 CR_PRIM_ATTR, 448 j ) 449 ) 450 return 0; 451 } 452 453 extent = priv_data->vh->startup_file.extents; 454 for (j = 0; j < HFSP_EXT_NB; ++j) { 455 if (!extent[j].block_count) break; 456 if (!hfsc_cache_add_extent( 457 cache, 458 PED_BE32_TO_CPU(extent[j].start_block), 459 PED_BE32_TO_CPU(extent[j].block_count), 460 0, /* unused for vh */ 461 ((uint8_t*)extent) - ((uint8_t*)priv_data->vh), 462 1, /* load / save 1 sector */ 463 CR_PRIM_START, 464 j ) 465 ) 466 return 0; 467 } 468 469 return 1; 470 } 471 472 static int 473 hfsplus_cache_from_catalog(HfsCPrivateCache* cache, PedFileSystem* fs, 474 PedTimer* timer) 475 { 476 HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) 477 fs->type_specific; 478 uint8_t node_1[PED_SECTOR_SIZE_DEFAULT]; 479 uint8_t* node; 480 HfsPHeaderRecord* header; 481 HfsPNodeDescriptor* desc = (HfsPNodeDescriptor*) node_1; 482 HfsPCatalogKey* catalog_key; 483 HfsPCatalog* catalog_data; 484 HfsPExtDescriptor* extent; 485 unsigned int leaf_node, record_number; 486 unsigned int i, j, size, bsize; 487 uint32_t jib = priv_data->jib_start_block, 488 jl = priv_data->jl_start_block; 489 490 if (!priv_data->catalog_file->sect_nb) { 491 ped_exception_throw ( 492 PED_EXCEPTION_INFORMATION, 493 PED_EXCEPTION_OK, 494 _("This HFS+ volume has no catalog file. " 495 "This is very unusual!")); 496 return 1; 497 } 498 499 /* Search the extent starting at *ptr_block in the catalog file */ 500 if (!hfsplus_file_read_sector (priv_data->catalog_file, node_1, 0)) 501 return 0; 502 header = (HfsPHeaderRecord*) (node_1 + HFS_FIRST_REC); 503 leaf_node = PED_BE32_TO_CPU (header->first_leaf_node); 504 bsize = PED_BE16_TO_CPU (header->node_size); 505 size = bsize / PED_SECTOR_SIZE_DEFAULT; 506 PED_ASSERT(size < 256, return 0); 507 508 node = (uint8_t*) ped_malloc(bsize); 509 if (!node) return 0; 510 desc = (HfsPNodeDescriptor*) node; 511 512 for (; leaf_node; leaf_node = PED_BE32_TO_CPU (desc->next)) { 513 if (!hfsplus_file_read (priv_data->catalog_file, node, 514 (PedSector) leaf_node * size, size)) { 515 ped_free (node); 516 return 0; 517 } 518 record_number = PED_BE16_TO_CPU (desc->rec_nb); 519 for (i = 1; i <= record_number; i++) { 520 unsigned int skip; 521 uint8_t where; 522 523 catalog_key = (HfsPCatalogKey*) 524 ( node + PED_BE16_TO_CPU (*((uint16_t *) 525 (node+(bsize - 2*i)))) ); 526 skip = ( 2 + PED_BE16_TO_CPU (catalog_key->key_length) 527 + 1) & ~1; 528 catalog_data = (HfsPCatalog*) 529 (((uint8_t*)catalog_key) + skip); 530 /* check for obvious error in FS */ 531 if (((uint8_t*)catalog_key - node < HFS_FIRST_REC) 532 || ((uint8_t*)catalog_data - node 533 >= (signed) bsize 534 - 2 * (signed)(record_number+1))) { 535 ped_exception_throw ( 536 PED_EXCEPTION_ERROR, 537 PED_EXCEPTION_CANCEL, 538 _("The file system contains errors.")); 539 ped_free (node); 540 return 0; 541 } 542 543 if (PED_BE16_TO_CPU(catalog_data->type)!=HFS_CAT_FILE) 544 continue; 545 546 extent = catalog_data->sel.file.data_fork.extents; 547 for (j = 0; j < HFSP_EXT_NB; ++j) { 548 if (!extent[j].block_count) break; 549 where = CR_BTREE_CAT; 550 if ( PED_BE32_TO_CPU(extent[j].start_block) 551 == jib ) { 552 jib = 0; 553 where = CR_BTREE_CAT_JIB; 554 } else 555 if ( PED_BE32_TO_CPU(extent[j].start_block) 556 == jl ) { 557 jl = 0; 558 where = CR_BTREE_CAT_JL; 559 } 560 if (!hfsc_cache_add_extent( 561 cache, 562 PED_BE32_TO_CPU(extent[j].start_block), 563 PED_BE32_TO_CPU(extent[j].block_count), 564 leaf_node, 565 (uint8_t*)extent - node, 566 size, 567 where, 568 j ) 569 ) { 570 ped_free (node); 571 return 0; 572 } 573 } 574 575 extent = catalog_data->sel.file.res_fork.extents; 576 for (j = 0; j < HFSP_EXT_NB; ++j) { 577 if (!extent[j].block_count) break; 578 if (!hfsc_cache_add_extent( 579 cache, 580 PED_BE32_TO_CPU(extent[j].start_block), 581 PED_BE32_TO_CPU(extent[j].block_count), 582 leaf_node, 583 (uint8_t*)extent - node, 584 size, 585 CR_BTREE_CAT, 586 j ) 587 ) { 588 ped_free (node); 589 return 0; 590 } 591 } 592 } 593 } 594 595 ped_free (node); 596 return 1; 597 } 598 599 static int 600 hfsplus_cache_from_extent(HfsCPrivateCache* cache, PedFileSystem* fs, 601 PedTimer* timer) 602 { 603 HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) 604 fs->type_specific; 605 uint8_t node_1[PED_SECTOR_SIZE_DEFAULT]; 606 uint8_t* node; 607 HfsPHeaderRecord* header; 608 HfsPNodeDescriptor* desc = (HfsPNodeDescriptor*) node_1; 609 HfsPExtentKey* extent_key; 610 HfsPExtDescriptor* extent; 611 unsigned int leaf_node, record_number; 612 unsigned int i, j, size, bsize; 613 614 if (!priv_data->extents_file->sect_nb) { 615 ped_exception_throw ( 616 PED_EXCEPTION_INFORMATION, 617 PED_EXCEPTION_OK, 618 _("This HFS+ volume has no extents overflow " 619 "file. This is quite unusual!")); 620 return 1; 621 } 622 623 if (!hfsplus_file_read_sector (priv_data->extents_file, node_1, 0)) 624 return 0; 625 header = ((HfsPHeaderRecord*) (node_1 + HFS_FIRST_REC)); 626 leaf_node = PED_BE32_TO_CPU (header->first_leaf_node); 627 bsize = PED_BE16_TO_CPU (header->node_size); 628 size = bsize / PED_SECTOR_SIZE_DEFAULT; 629 PED_ASSERT(size < 256, return 0); 630 631 node = (uint8_t*) ped_malloc (bsize); 632 if (!node) return -1; 633 desc = (HfsPNodeDescriptor*) node; 634 635 for (; leaf_node; leaf_node = PED_BE32_TO_CPU (desc->next)) { 636 if (!hfsplus_file_read (priv_data->extents_file, node, 637 (PedSector) leaf_node * size, size)) { 638 ped_free (node); 639 return 0; 640 } 641 record_number = PED_BE16_TO_CPU (desc->rec_nb); 642 for (i = 1; i <= record_number; i++) { 643 uint8_t where; 644 extent_key = (HfsPExtentKey*) 645 (node + PED_BE16_TO_CPU(*((uint16_t *) 646 (node+(bsize - 2*i))))); 647 extent = (HfsPExtDescriptor*) 648 (((uint8_t*)extent_key) + sizeof (HfsPExtentKey)); 649 /* check for obvious error in FS */ 650 if (((uint8_t*)extent_key - node < HFS_FIRST_REC) 651 || ((uint8_t*)extent - node 652 >= (signed)bsize 653 - 2 * (signed)(record_number+1))) { 654 ped_exception_throw ( 655 PED_EXCEPTION_ERROR, 656 PED_EXCEPTION_CANCEL, 657 _("The file system contains errors.")); 658 ped_free (node); 659 return -1; 660 } 661 662 switch (extent_key->file_ID) { 663 case PED_CPU_TO_BE32 (HFS_XTENT_ID) : 664 if (ped_exception_throw ( 665 PED_EXCEPTION_WARNING, 666 PED_EXCEPTION_IGNORE_CANCEL, 667 _("The extents overflow file should not" 668 " contain its own extents! You should " 669 "check the file system.")) 670 != PED_EXCEPTION_IGNORE) 671 return 0; 672 where = CR_BTREE_EXT_EXT; 673 break; 674 case PED_CPU_TO_BE32 (HFS_CATALOG_ID) : 675 where = CR_BTREE_EXT_CAT; 676 break; 677 case PED_CPU_TO_BE32 (HFSP_ALLOC_ID) : 678 where = CR_BTREE_EXT_ALLOC; 679 break; 680 case PED_CPU_TO_BE32 (HFSP_STARTUP_ID) : 681 where = CR_BTREE_EXT_START; 682 break; 683 case PED_CPU_TO_BE32 (HFSP_ATTRIB_ID) : 684 where = CR_BTREE_EXT_ATTR; 685 break; 686 default : 687 where = CR_BTREE_EXT_0; 688 break; 689 } 690 691 for (j = 0; j < HFSP_EXT_NB; ++j) { 692 if (!extent[j].block_count) break; 693 if (!hfsc_cache_add_extent( 694 cache, 695 PED_BE32_TO_CPU(extent[j].start_block), 696 PED_BE32_TO_CPU(extent[j].block_count), 697 leaf_node, 698 (uint8_t*)extent - node, 699 size, 700 where, 701 j ) 702 ) { 703 ped_free (node); 704 return 0; 705 } 706 } 707 } 708 } 709 710 ped_free (node); 711 return 1; 712 } 713 714 static int 715 hfsplus_cache_from_attributes(HfsCPrivateCache* cache, PedFileSystem* fs, 716 PedTimer* timer) 717 { 718 HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) 719 fs->type_specific; 720 uint8_t node_1[PED_SECTOR_SIZE_DEFAULT]; 721 uint8_t* node; 722 HfsPHeaderRecord* header; 723 HfsPNodeDescriptor* desc = (HfsPNodeDescriptor*) node_1; 724 HfsPPrivateGenericKey* generic_key; 725 HfsPForkDataAttr* fork_ext_data; 726 HfsPExtDescriptor* extent; 727 unsigned int leaf_node, record_number; 728 unsigned int i, j, size, bsize; 729 730 /* attributes file is facultative */ 731 if (!priv_data->attributes_file->sect_nb) 732 return 1; 733 734 /* Search the extent starting at *ptr_block in the catalog file */ 735 if (!hfsplus_file_read_sector (priv_data->attributes_file, node_1, 0)) 736 return 0; 737 header = ((HfsPHeaderRecord*) (node_1 + HFS_FIRST_REC)); 738 leaf_node = PED_BE32_TO_CPU (header->first_leaf_node); 739 bsize = PED_BE16_TO_CPU (header->node_size); 740 size = bsize / PED_SECTOR_SIZE_DEFAULT; 741 PED_ASSERT(size < 256, return 0); 742 743 node = (uint8_t*) ped_malloc(bsize); 744 if (!node) return 0; 745 desc = (HfsPNodeDescriptor*) node; 746 747 for (; leaf_node; leaf_node = PED_BE32_TO_CPU (desc->next)) { 748 if (!hfsplus_file_read (priv_data->attributes_file, node, 749 (PedSector) leaf_node * size, size)) { 750 ped_free (node); 751 return 0; 752 } 753 record_number = PED_BE16_TO_CPU (desc->rec_nb); 754 for (i = 1; i <= record_number; i++) { 755 unsigned int skip; 756 generic_key = (HfsPPrivateGenericKey*) 757 (node + PED_BE16_TO_CPU(*((uint16_t *) 758 (node+(bsize - 2*i))))); 759 skip = ( 2 + PED_BE16_TO_CPU (generic_key->key_length) 760 + 1 ) & ~1; 761 fork_ext_data = (HfsPForkDataAttr*) 762 (((uint8_t*)generic_key) + skip); 763 /* check for obvious error in FS */ 764 if (((uint8_t*)generic_key - node < HFS_FIRST_REC) 765 || ((uint8_t*)fork_ext_data - node 766 >= (signed) bsize 767 - 2 * (signed)(record_number+1))) { 768 ped_exception_throw ( 769 PED_EXCEPTION_ERROR, 770 PED_EXCEPTION_CANCEL, 771 _("The file system contains errors.")); 772 ped_free (node); 773 return 0; 774 } 775 776 if (fork_ext_data->record_type 777 == PED_CPU_TO_BE32 ( HFSP_ATTR_FORK ) ) { 778 extent = fork_ext_data->fork_res.fork.extents; 779 for (j = 0; j < HFSP_EXT_NB; ++j) { 780 if (!extent[j].block_count) break; 781 if (!hfsc_cache_add_extent( 782 cache, 783 PED_BE32_TO_CPU ( 784 extent[j].start_block ), 785 PED_BE32_TO_CPU ( 786 extent[j].block_count ), 787 leaf_node, 788 (uint8_t*)extent-node, 789 size, 790 CR_BTREE_ATTR, 791 j ) 792 ) { 793 ped_free(node); 794 return 0; 795 } 796 } 797 } else if (fork_ext_data->record_type 798 == PED_CPU_TO_BE32 ( HFSP_ATTR_EXTENTS ) ) { 799 extent = fork_ext_data->fork_res.extents; 800 for (j = 0; j < HFSP_EXT_NB; ++j) { 801 if (!extent[j].block_count) break; 802 if (!hfsc_cache_add_extent( 803 cache, 804 PED_BE32_TO_CPU ( 805 extent[j].start_block ), 806 PED_BE32_TO_CPU ( 807 extent[j].block_count ), 808 leaf_node, 809 (uint8_t*)extent-node, 810 size, 811 CR_BTREE_ATTR, 812 j ) 813 ) { 814 ped_free(node); 815 return 0; 816 } 817 } 818 } else continue; 819 } 820 } 821 822 ped_free (node); 823 return 1; 824 } 825 826 static HfsCPrivateCache* 827 hfsplus_cache_extents(PedFileSystem* fs, PedTimer* timer) 828 { 829 HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) 830 fs->type_specific; 831 HfsCPrivateCache* ret; 832 unsigned int file_number, block_number; 833 834 file_number = PED_BE32_TO_CPU(priv_data->vh->file_count); 835 block_number = PED_BE32_TO_CPU(priv_data->vh->total_blocks); 836 ret = hfsc_new_cache(block_number, file_number); 837 if (!ret) return NULL; 838 839 if (!hfsplus_cache_from_vh(ret, fs, timer) || 840 !hfsplus_cache_from_catalog(ret, fs, timer) || 841 !hfsplus_cache_from_extent(ret, fs, timer) || 842 !hfsplus_cache_from_attributes(ret, fs, timer)) { 843 ped_exception_throw( 844 PED_EXCEPTION_ERROR, 845 PED_EXCEPTION_CANCEL, 846 _("Could not cache the file system in memory.")); 847 hfsc_delete_cache(ret); 848 return NULL; 849 } 850 851 return ret; 852 } 853 854 /* This function moves file's data to compact used and free space, 855 starting at fblock block */ 856 /* return 0 on error */ 857 int 858 hfsplus_pack_free_space_from_block (PedFileSystem *fs, unsigned int fblock, 859 PedTimer* timer, unsigned int to_free) 860 { 861 PedSector bytes_buff; 862 HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) 863 fs->type_specific; 864 HfsPVolumeHeader* vh = priv_data->vh; 865 HfsCPrivateCache* cache; 866 unsigned int to_fblock = fblock; 867 unsigned int start = fblock; 868 unsigned int divisor = PED_BE32_TO_CPU (vh->total_blocks) 869 + 1 - start - to_free; 870 int ret; 871 872 PED_ASSERT (!hfsp_block, return 0); 873 874 cache = hfsplus_cache_extents (fs, timer); 875 if (!cache) 876 return 0; 877 878 /* Calculate the size of the copy buffer : 879 * Takes BLOCK_MAX_BUFF HFS blocks, but if > BYTES_MAX_BUFF 880 * takes the maximum number of HFS blocks so that the buffer 881 * will remain smaller than or equal to BYTES_MAX_BUFF, with 882 * a minimum of 1 HFS block */ 883 bytes_buff = PED_BE32_TO_CPU (priv_data->vh->block_size) 884 * (PedSector) BLOCK_MAX_BUFF; 885 if (bytes_buff > BYTES_MAX_BUFF) { 886 hfsp_block_count = BYTES_MAX_BUFF 887 / PED_BE32_TO_CPU (priv_data->vh->block_size); 888 if (!hfsp_block_count) 889 hfsp_block_count = 1; 890 bytes_buff = (PedSector) hfsp_block_count 891 * PED_BE32_TO_CPU (priv_data->vh->block_size); 892 } else 893 hfsp_block_count = BLOCK_MAX_BUFF; 894 895 /* If the cache code requests more space, give it to him */ 896 if (bytes_buff < hfsc_cache_needed_buffer (cache)) 897 bytes_buff = hfsc_cache_needed_buffer (cache); 898 899 hfsp_block = (uint8_t*) ped_malloc (bytes_buff); 900 if (!hfsp_block) 901 goto error_cache; 902 903 if (!hfsplus_read_bad_blocks (fs)) { 904 ped_exception_throw ( 905 PED_EXCEPTION_ERROR, 906 PED_EXCEPTION_CANCEL, 907 _("Bad blocks list could not be loaded.")); 908 goto error_alloc; 909 } 910 911 while ( fblock < ( priv_data->plus_geom->length - 2 ) 912 / ( PED_BE32_TO_CPU (vh->block_size) 913 / PED_SECTOR_SIZE_DEFAULT ) ) { 914 if (TST_BLOC_OCCUPATION (priv_data->alloc_map, fblock) 915 && (!hfsplus_is_bad_block (fs, fblock))) { 916 if (!(ret = hfsplus_move_extent_starting_at (fs, 917 &fblock, &to_fblock, cache))) 918 to_fblock = ++fblock; 919 else if (ret == -1) { 920 ped_exception_throw ( 921 PED_EXCEPTION_ERROR, 922 PED_EXCEPTION_CANCEL, 923 _("An error occurred during extent " 924 "relocation.")); 925 goto error_alloc; 926 } 927 } else { 928 fblock++; 929 } 930 931 ped_timer_update(timer, (float)(to_fblock - start) / divisor); 932 } 933 934 ped_free (hfsp_block); hfsp_block = NULL; hfsp_block_count = 0; 935 hfsc_delete_cache (cache); 936 return 1; 937 938 error_alloc: 939 ped_free (hfsp_block); hfsp_block = NULL; hfsp_block_count = 0; 940 error_cache: 941 hfsc_delete_cache (cache); 942 return 0; 943 } 944 945 #endif /* !DISCOVER_ONLY */