1 /* 2 libparted - a library for manipulating disk partitions 3 Copyright (C) 2000, 2003, 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 /* 20 Author : Guillaume Knispel <k_guillaume@libertysurf.fr> 21 Report bug to <bug-parted@gnu.org> 22 */ 23 24 #include <config.h> 25 26 #include <parted/parted.h> 27 #include <parted/endian.h> 28 #include <parted/debug.h> 29 #include <stdint.h> 30 31 #if ENABLE_NLS 32 # include <libintl.h> 33 # define _(String) dgettext (PACKAGE, String) 34 #else 35 # define _(String) (String) 36 #endif /* ENABLE_NLS */ 37 38 #include "hfs.h" 39 #include "probe.h" 40 41 uint8_t* hfs_block = NULL; 42 uint8_t* hfsp_block = NULL; 43 unsigned hfs_block_count; 44 unsigned hfsp_block_count; 45 46 #define HFS_BLOCK_SIZES ((int[2]){512, 0}) 47 #define HFSP_BLOCK_SIZES ((int[2]){512, 0}) 48 #define HFSX_BLOCK_SIZES ((int[2]){512, 0}) 49 50 #ifndef DISCOVER_ONLY 51 #include "file.h" 52 #include "reloc.h" 53 #include "advfs.h" 54 55 static PedFileSystemType hfs_type; 56 static PedFileSystemType hfsplus_type; 57 58 59 /* ----- HFS ----- */ 60 61 /* This is a very unundoable operation */ 62 /* Maybe I shouldn't touch the alternate MDB ? */ 63 /* Anyway clobber is call before other fs creation */ 64 /* So this is a non-issue */ 65 static int 66 hfs_clobber (PedGeometry* geom) 67 { 68 uint8_t buf[PED_SECTOR_SIZE_DEFAULT]; 69 70 memset (buf, 0, PED_SECTOR_SIZE_DEFAULT); 71 72 /* destroy boot blocks, mdb, alternate mdb ... */ 73 return (!!ped_geometry_write (geom, buf, 0, 1)) & 74 (!!ped_geometry_write (geom, buf, 1, 1)) & 75 (!!ped_geometry_write (geom, buf, 2, 1)) & 76 (!!ped_geometry_write (geom, buf, geom->length - 2, 1)) & 77 (!!ped_geometry_write (geom, buf, geom->length - 1, 1)) & 78 (!!ped_geometry_sync (geom)); 79 } 80 81 static PedFileSystem* 82 hfs_open (PedGeometry* geom) 83 { 84 uint8_t buf[PED_SECTOR_SIZE_DEFAULT]; 85 PedFileSystem* fs; 86 HfsMasterDirectoryBlock* mdb; 87 HfsPrivateFSData* priv_data; 88 89 if (!hfsc_can_use_geom (geom)) 90 return NULL; 91 92 /* Read MDB */ 93 if (!ped_geometry_read (geom, buf, 2, 1)) 94 return NULL; 95 96 /* Allocate memory */ 97 fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem)); 98 if (!fs) goto ho; 99 mdb = (HfsMasterDirectoryBlock*) 100 ped_malloc (sizeof (HfsMasterDirectoryBlock)); 101 if (!mdb) goto ho_fs; 102 priv_data = (HfsPrivateFSData*) 103 ped_malloc (sizeof (HfsPrivateFSData)); 104 if (!priv_data) goto ho_mdb; 105 106 memcpy (mdb, buf, sizeof (HfsMasterDirectoryBlock)); 107 108 /* init structures */ 109 priv_data->mdb = mdb; 110 priv_data->bad_blocks_loaded = 0; 111 priv_data->bad_blocks_xtent_nb = 0; 112 priv_data->bad_blocks_xtent_list = NULL; 113 priv_data->extent_file = 114 hfs_file_open (fs, PED_CPU_TO_BE32 (HFS_XTENT_ID), 115 mdb->extents_file_rec, 116 PED_CPU_TO_BE32 (mdb->extents_file_size) 117 / PED_SECTOR_SIZE_DEFAULT); 118 if (!priv_data->extent_file) goto ho_pd; 119 priv_data->catalog_file = 120 hfs_file_open (fs, PED_CPU_TO_BE32 (HFS_CATALOG_ID), 121 mdb->catalog_file_rec, 122 PED_CPU_TO_BE32 (mdb->catalog_file_size) 123 / PED_SECTOR_SIZE_DEFAULT); 124 if (!priv_data->catalog_file) goto ho_ce; 125 /* Read allocation blocks */ 126 if (!ped_geometry_read(geom, priv_data->alloc_map, 127 PED_BE16_TO_CPU (mdb->volume_bitmap_block), 128 ( PED_BE16_TO_CPU (mdb->total_blocks) 129 + PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) 130 / (PED_SECTOR_SIZE_DEFAULT * 8) ) ) 131 goto ho_cf; 132 133 fs->type = &hfs_type; 134 fs->geom = ped_geometry_duplicate (geom); 135 if (!fs->geom) goto ho_cf; 136 fs->type_specific = (void*) priv_data; 137 fs->checked = ( PED_BE16_TO_CPU (mdb->volume_attributes) 138 >> HFS_UNMOUNTED ) & 1; 139 140 return fs; 141 142 /*--- clean error handling ---*/ 143 ho_cf: hfs_file_close(priv_data->catalog_file); 144 ho_ce: hfs_file_close(priv_data->extent_file); 145 ho_pd: ped_free(priv_data); 146 ho_mdb: ped_free(mdb); 147 ho_fs: ped_free(fs); 148 ho: return NULL; 149 } 150 151 static int 152 hfs_close (PedFileSystem *fs) 153 { 154 HfsPrivateFSData* priv_data = (HfsPrivateFSData*) fs->type_specific; 155 156 hfs_file_close (priv_data->extent_file); 157 hfs_file_close (priv_data->catalog_file); 158 if (priv_data->bad_blocks_loaded) 159 hfs_free_bad_blocks_list (priv_data->bad_blocks_xtent_list); 160 ped_free (priv_data->mdb); 161 ped_free (priv_data); 162 ped_geometry_destroy (fs->geom); 163 ped_free (fs); 164 165 return 1; 166 } 167 168 static PedConstraint* 169 hfs_get_resize_constraint (const PedFileSystem *fs) 170 { 171 PedDevice* dev = fs->geom->dev; 172 PedAlignment start_align; 173 PedGeometry start_sector; 174 PedGeometry full_dev; 175 PedSector min_size; 176 177 if (!ped_alignment_init (&start_align, fs->geom->start, 0)) 178 return NULL; 179 if (!ped_geometry_init (&start_sector, dev, fs->geom->start, 1)) 180 return NULL; 181 if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1)) 182 return NULL; 183 /* 2 = last two sectors (alternate MDB and unused sector) */ 184 min_size = hfs_get_empty_end(fs) + 2; 185 if (min_size == 2) return NULL; 186 187 return ped_constraint_new (&start_align, ped_alignment_any, 188 &start_sector, &full_dev, min_size, 189 fs->geom->length); 190 } 191 192 static int 193 hfs_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer) 194 { 195 uint8_t buf[PED_SECTOR_SIZE_DEFAULT]; 196 unsigned int nblock, nfree; 197 unsigned int block, to_free; 198 HfsPrivateFSData* priv_data; 199 HfsMasterDirectoryBlock* mdb; 200 int resize = 1; 201 unsigned int hfs_sect_block; 202 PedSector hgee; 203 204 /* check preconditions */ 205 PED_ASSERT (fs != NULL, return 0); 206 PED_ASSERT (fs->geom != NULL, return 0); 207 PED_ASSERT (geom != NULL, return 0); 208 #ifdef DEBUG 209 PED_ASSERT ((hgee = hfs_get_empty_end(fs)) != 0, return 0); 210 #else 211 if ((hgee = hfs_get_empty_end(fs)) == 0) 212 return 0; 213 #endif 214 215 PED_ASSERT ((hgee = hfs_get_empty_end(fs)) != 0, return 0); 216 217 if (ped_geometry_test_equal(fs->geom, geom)) 218 return 1; 219 220 priv_data = (HfsPrivateFSData*) fs->type_specific; 221 mdb = priv_data->mdb; 222 hfs_sect_block = PED_BE32_TO_CPU (mdb->block_size) 223 / PED_SECTOR_SIZE_DEFAULT; 224 225 if (fs->geom->start != geom->start 226 || geom->length > fs->geom->length 227 || geom->length < hgee + 2) { 228 ped_exception_throw ( 229 PED_EXCEPTION_NO_FEATURE, 230 PED_EXCEPTION_CANCEL, 231 _("Sorry, HFS cannot be resized that way yet.")); 232 return 0; 233 } 234 235 /* Flush caches */ 236 if (!ped_geometry_sync(fs->geom)) 237 return 0; 238 239 /* Clear the unmounted bit */ 240 mdb->volume_attributes &= PED_CPU_TO_BE16 (~( 1 << HFS_UNMOUNTED )); 241 if (!ped_geometry_read (fs->geom, buf, 2, 1)) 242 return 0; 243 memcpy (buf, mdb, sizeof (HfsMasterDirectoryBlock)); 244 if ( !ped_geometry_write (fs->geom, buf, 2, 1) 245 || !ped_geometry_sync (fs->geom)) 246 return 0; 247 248 ped_timer_reset (timer); 249 ped_timer_set_state_name(timer, _("shrinking")); 250 ped_timer_update(timer, 0.0); 251 /* relocate data */ 252 to_free = ( fs->geom->length - geom->length 253 + hfs_sect_block - 1 ) 254 / hfs_sect_block ; 255 block = hfs_find_start_pack (fs, to_free); 256 if (!hfs_pack_free_space_from_block (fs, block, timer, to_free)) { 257 resize = 0; 258 ped_exception_throw ( 259 PED_EXCEPTION_ERROR, 260 PED_EXCEPTION_CANCEL, 261 _("Data relocation has failed.")); 262 goto write_MDB; 263 } 264 265 /* Calculate new block number and other MDB field */ 266 nblock = ( geom->length - (PED_BE16_TO_CPU (mdb->start_block) + 2) ) 267 / hfs_sect_block; 268 nfree = PED_BE16_TO_CPU (mdb->free_blocks) 269 - ( PED_BE16_TO_CPU (mdb->total_blocks) - nblock ); 270 271 /* Check that all block after future end are really free */ 272 for (block = nblock; 273 block < PED_BE16_TO_CPU (mdb->total_blocks); 274 block++) { 275 if (TST_BLOC_OCCUPATION(priv_data->alloc_map,block)) { 276 resize = 0; 277 ped_exception_throw ( 278 PED_EXCEPTION_ERROR, 279 PED_EXCEPTION_CANCEL, 280 _("Data relocation left some data in the end " 281 "of the volume.")); 282 goto write_MDB; 283 } 284 } 285 286 /* Mark out of volume blocks as used 287 (broken implementations compatibility) */ 288 for ( block = nblock; block < (1 << 16); ++block) 289 SET_BLOC_OCCUPATION(priv_data->alloc_map,block); 290 291 /* save the allocation map 292 I do not write until start of allocation blocks 293 but only until pre-resize end of bitmap blocks 294 because the specifications do _not_ assert that everything 295 until allocation blocks is boot, mdb and alloc */ 296 ped_geometry_write(fs->geom, priv_data->alloc_map, 297 PED_BE16_TO_CPU (priv_data->mdb->volume_bitmap_block), 298 ( PED_BE16_TO_CPU (priv_data->mdb->total_blocks) 299 + PED_SECTOR_SIZE_DEFAULT * 8 - 1) 300 / (PED_SECTOR_SIZE_DEFAULT * 8)); 301 302 /* Update geometry */ 303 if (resize) { 304 /* update in fs structure */ 305 if (PED_BE16_TO_CPU (mdb->next_allocation) >= nblock) 306 mdb->next_allocation = PED_CPU_TO_BE16 (0); 307 mdb->total_blocks = PED_CPU_TO_BE16 (nblock); 308 mdb->free_blocks = PED_CPU_TO_BE16 (nfree); 309 /* update parted structure */ 310 fs->geom->length = geom->length; 311 fs->geom->end = fs->geom->start + geom->length - 1; 312 } 313 314 /* Set the unmounted bit */ 315 mdb->volume_attributes |= PED_CPU_TO_BE16 ( 1 << HFS_UNMOUNTED ); 316 317 /* Effective write */ 318 write_MDB: 319 ped_timer_set_state_name(timer,_("writing HFS Master Directory Block")); 320 321 if (!hfs_update_mdb(fs)) { 322 ped_geometry_sync(geom); 323 return 0; 324 } 325 326 if (!ped_geometry_sync(geom)) 327 return 0; 328 329 ped_timer_update(timer, 1.0); 330 331 return (resize); 332 } 333 334 /* ----- HFS+ ----- */ 335 336 #include "file_plus.h" 337 #include "advfs_plus.h" 338 #include "reloc_plus.h" 339 #include "journal.h" 340 341 static int 342 hfsplus_clobber (PedGeometry* geom) 343 { 344 unsigned int i = 1; 345 uint8_t buf[PED_SECTOR_SIZE_DEFAULT]; 346 HfsMasterDirectoryBlock *mdb; 347 348 mdb = (HfsMasterDirectoryBlock *) buf; 349 350 if (!ped_geometry_read (geom, buf, 2, 1)) 351 return 0; 352 353 if (PED_BE16_TO_CPU (mdb->signature) == HFS_SIGNATURE) { 354 /* embedded hfs+ */ 355 PedGeometry *embedded; 356 357 i = PED_BE32_TO_CPU(mdb->block_size) / PED_SECTOR_SIZE_DEFAULT; 358 embedded = ped_geometry_new ( 359 geom->dev, 360 (PedSector) geom->start 361 + PED_BE16_TO_CPU (mdb->start_block) 362 + (PedSector) PED_BE16_TO_CPU ( 363 mdb->old_new.embedded.location.start_block ) * i, 364 (PedSector) PED_BE16_TO_CPU ( 365 mdb->old_new.embedded.location.block_count ) * i ); 366 if (!embedded) i = 0; 367 else { 368 i = hfs_clobber (embedded); 369 ped_geometry_destroy (embedded); 370 } 371 } 372 373 /* non-embedded or envelop destroy as hfs */ 374 return ( hfs_clobber (geom) && i ); 375 } 376 377 static int 378 hfsplus_close (PedFileSystem *fs) 379 { 380 HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) 381 fs->type_specific; 382 383 if (priv_data->bad_blocks_loaded) 384 hfsplus_free_bad_blocks_list(priv_data->bad_blocks_xtent_list); 385 ped_free(priv_data->alloc_map); 386 ped_free(priv_data->dirty_alloc_map); 387 hfsplus_file_close (priv_data->allocation_file); 388 hfsplus_file_close (priv_data->attributes_file); 389 hfsplus_file_close (priv_data->catalog_file); 390 hfsplus_file_close (priv_data->extents_file); 391 if (priv_data->free_geom) ped_geometry_destroy (priv_data->plus_geom); 392 if (priv_data->wrapper) hfs_close(priv_data->wrapper); 393 ped_geometry_destroy (fs->geom); 394 ped_free(priv_data->vh); 395 ped_free(priv_data); 396 ped_free(fs); 397 398 return 1; 399 } 400 401 static PedFileSystem* 402 hfsplus_open (PedGeometry* geom) 403 { 404 uint8_t buf[PED_SECTOR_SIZE_DEFAULT]; 405 PedFileSystem* fs; 406 HfsPVolumeHeader* vh; 407 HfsPPrivateFSData* priv_data; 408 PedGeometry* wrapper_geom; 409 unsigned int map_sectors; 410 411 if (!hfsc_can_use_geom (geom)) 412 return NULL; 413 414 fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem)); 415 if (!fs) goto hpo; 416 vh = (HfsPVolumeHeader*) ped_malloc (sizeof (HfsPVolumeHeader)); 417 if (!vh) goto hpo_fs; 418 priv_data = (HfsPPrivateFSData*)ped_malloc (sizeof (HfsPPrivateFSData)); 419 if (!priv_data) goto hpo_vh; 420 421 fs->geom = ped_geometry_duplicate (geom); 422 if (!fs->geom) goto hpo_pd; 423 fs->type_specific = (void*) priv_data; 424 425 if ((wrapper_geom = hfs_and_wrapper_probe (geom))) { 426 HfsPrivateFSData* hfs_priv_data; 427 PedSector abs_sect, length; 428 unsigned int bs; 429 430 ped_geometry_destroy (wrapper_geom); 431 priv_data->wrapper = hfs_open(geom); 432 if (!priv_data->wrapper) goto hpo_gm; 433 hfs_priv_data = (HfsPrivateFSData*) 434 priv_data->wrapper->type_specific; 435 bs = PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size) 436 / PED_SECTOR_SIZE_DEFAULT; 437 abs_sect = (PedSector) geom->start 438 + (PedSector) PED_BE16_TO_CPU ( 439 hfs_priv_data->mdb->start_block) 440 + (PedSector) PED_BE16_TO_CPU ( 441 hfs_priv_data->mdb->old_new 442 .embedded.location.start_block ) 443 * bs; 444 length = (PedSector) PED_BE16_TO_CPU ( 445 hfs_priv_data->mdb->old_new 446 .embedded.location.block_count) 447 * bs; 448 priv_data->plus_geom = ped_geometry_new (geom->dev, abs_sect, 449 length); 450 if (!priv_data->plus_geom) goto hpo_wr; 451 priv_data->free_geom = 1; 452 } else { 453 priv_data->wrapper = NULL; 454 priv_data->plus_geom = fs->geom; 455 priv_data->free_geom = 0; 456 } 457 458 if (!ped_geometry_read (priv_data->plus_geom, buf, 2, 1)) goto hpo_pg; 459 memcpy (vh, buf, sizeof (HfsPVolumeHeader)); 460 priv_data->vh = vh; 461 462 if (vh->signature != PED_CPU_TO_BE16(HFSP_SIGNATURE) 463 && vh->signature != PED_CPU_TO_BE16(HFSX_SIGNATURE)) { 464 ped_exception_throw ( 465 PED_EXCEPTION_BUG, 466 PED_EXCEPTION_CANCEL, 467 _("No valid HFS[+X] signature has been found while " 468 "opening.")); 469 goto hpo_pg; 470 } 471 472 if (vh->signature == PED_CPU_TO_BE16(HFSP_SIGNATURE) 473 && vh->version != PED_CPU_TO_BE16(HFSP_VERSION)) { 474 if (ped_exception_throw ( 475 PED_EXCEPTION_NO_FEATURE, 476 PED_EXCEPTION_IGNORE_CANCEL, 477 _("Version %d of HFS+ isn't supported."), 478 PED_BE16_TO_CPU(vh->version)) 479 != PED_EXCEPTION_IGNORE) 480 goto hpo_pg; 481 } 482 483 if (vh->signature == PED_CPU_TO_BE16(HFSX_SIGNATURE) 484 && vh->version != PED_CPU_TO_BE16(HFSX_VERSION)) { 485 if (ped_exception_throw ( 486 PED_EXCEPTION_NO_FEATURE, 487 PED_EXCEPTION_IGNORE_CANCEL, 488 _("Version %d of HFSX isn't supported."), 489 PED_BE16_TO_CPU(vh->version)) 490 != PED_EXCEPTION_IGNORE) 491 goto hpo_pg; 492 } 493 494 priv_data->jib_start_block = 0; 495 priv_data->jl_start_block = 0; 496 if (vh->attributes & PED_CPU_TO_BE32(1<<HFSP_JOURNALED)) { 497 if (!hfsj_replay_journal(fs)) 498 goto hpo_pg; 499 } 500 501 priv_data->bad_blocks_loaded = 0; 502 priv_data->bad_blocks_xtent_nb = 0; 503 priv_data->bad_blocks_xtent_list = NULL; 504 priv_data->extents_file = 505 hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFS_XTENT_ID), 506 vh->extents_file.extents, 507 PED_BE64_TO_CPU ( 508 vh->extents_file.logical_size ) 509 / PED_SECTOR_SIZE_DEFAULT); 510 if (!priv_data->extents_file) goto hpo_pg; 511 priv_data->catalog_file = 512 hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFS_CATALOG_ID), 513 vh->catalog_file.extents, 514 PED_BE64_TO_CPU ( 515 vh->catalog_file.logical_size ) 516 / PED_SECTOR_SIZE_DEFAULT); 517 if (!priv_data->catalog_file) goto hpo_ce; 518 priv_data->attributes_file = 519 hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFSP_ATTRIB_ID), 520 vh->attributes_file.extents, 521 PED_BE64_TO_CPU ( 522 vh->attributes_file.logical_size) 523 / PED_SECTOR_SIZE_DEFAULT); 524 if (!priv_data->attributes_file) goto hpo_cc; 525 526 map_sectors = ( PED_BE32_TO_CPU (vh->total_blocks) 527 + PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) 528 / (PED_SECTOR_SIZE_DEFAULT * 8); 529 priv_data->dirty_alloc_map = (uint8_t*) 530 ped_malloc ((map_sectors + 7) / 8); 531 if (!priv_data->dirty_alloc_map) goto hpo_cl; 532 memset(priv_data->dirty_alloc_map, 0, (map_sectors + 7) / 8); 533 priv_data->alloc_map = (uint8_t*) 534 ped_malloc (map_sectors * PED_SECTOR_SIZE_DEFAULT); 535 if (!priv_data->alloc_map) goto hpo_dm; 536 537 priv_data->allocation_file = 538 hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFSP_ALLOC_ID), 539 vh->allocation_file.extents, 540 PED_BE64_TO_CPU ( 541 vh->allocation_file.logical_size) 542 / PED_SECTOR_SIZE_DEFAULT); 543 if (!priv_data->allocation_file) goto hpo_am; 544 if (!hfsplus_file_read (priv_data->allocation_file, 545 priv_data->alloc_map, 0, map_sectors)) { 546 hfsplus_close(fs); 547 return NULL; 548 } 549 550 fs->type = &hfsplus_type; 551 fs->checked = ((PED_BE32_TO_CPU (vh->attributes) >> HFS_UNMOUNTED) & 1) 552 && !((PED_BE32_TO_CPU (vh->attributes) >> HFSP_INCONSISTENT) & 1); 553 554 return fs; 555 556 /*--- clean error handling ---*/ 557 hpo_am: ped_free(priv_data->alloc_map); 558 hpo_dm: ped_free(priv_data->dirty_alloc_map); 559 hpo_cl: hfsplus_file_close (priv_data->attributes_file); 560 hpo_cc: hfsplus_file_close (priv_data->catalog_file); 561 hpo_ce: hfsplus_file_close (priv_data->extents_file); 562 hpo_pg: if (priv_data->free_geom) ped_geometry_destroy (priv_data->plus_geom); 563 hpo_wr: if (priv_data->wrapper) hfs_close(priv_data->wrapper); 564 hpo_gm: ped_geometry_destroy (fs->geom); 565 hpo_pd: ped_free(priv_data); 566 hpo_vh: ped_free(vh); 567 hpo_fs: ped_free(fs); 568 hpo: return NULL; 569 } 570 571 static PedConstraint* 572 hfsplus_get_resize_constraint (const PedFileSystem *fs) 573 { 574 PedDevice* dev = fs->geom->dev; 575 PedAlignment start_align; 576 PedGeometry start_sector; 577 PedGeometry full_dev; 578 PedSector min_size; 579 580 if (!ped_alignment_init (&start_align, fs->geom->start, 0)) 581 return NULL; 582 if (!ped_geometry_init (&start_sector, dev, fs->geom->start, 1)) 583 return NULL; 584 if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1)) 585 return NULL; 586 587 min_size = hfsplus_get_min_size (fs); 588 if (!min_size) return NULL; 589 590 return ped_constraint_new (&start_align, ped_alignment_any, 591 &start_sector, &full_dev, min_size, 592 fs->geom->length); 593 } 594 595 static int 596 hfsplus_volume_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer) 597 { 598 uint8_t buf[PED_SECTOR_SIZE_DEFAULT]; 599 unsigned int nblock, nfree, mblock; 600 unsigned int block, to_free, old_blocks; 601 HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) 602 fs->type_specific; 603 HfsPVolumeHeader* vh = priv_data->vh; 604 int resize = 1; 605 unsigned int hfsp_sect_block = 606 ( PED_BE32_TO_CPU (vh->block_size) 607 / PED_SECTOR_SIZE_DEFAULT ); 608 unsigned int map_sectors; 609 610 old_blocks = PED_BE32_TO_CPU (vh->total_blocks); 611 612 /* Flush caches */ 613 if (!ped_geometry_sync(priv_data->plus_geom)) 614 return 0; 615 616 /* Clear the unmounted bit */ 617 /* and set the implementation code (Apple Creator Code) */ 618 vh->attributes &= PED_CPU_TO_BE32 (~( 1 << HFS_UNMOUNTED )); 619 vh->last_mounted_version = PED_CPU_TO_BE32(HFSP_IMPL_Shnk); 620 if (!ped_geometry_read (priv_data->plus_geom, buf, 2, 1)) 621 return 0; 622 memcpy (buf, vh, sizeof (HfsPVolumeHeader)); 623 if ( !ped_geometry_write (priv_data->plus_geom, buf, 2, 1) 624 || !ped_geometry_sync (priv_data->plus_geom)) 625 return 0; 626 627 ped_timer_reset (timer); 628 ped_timer_set_state_name(timer, _("shrinking")); 629 ped_timer_update(timer, 0.0); 630 /* relocate data */ 631 to_free = ( priv_data->plus_geom->length 632 - geom->length + hfsp_sect_block 633 - 1 ) / hfsp_sect_block; 634 block = hfsplus_find_start_pack (fs, to_free); 635 if (!hfsplus_pack_free_space_from_block (fs, block, timer, to_free)) { 636 resize = 0; 637 ped_exception_throw ( 638 PED_EXCEPTION_ERROR, 639 PED_EXCEPTION_CANCEL, 640 _("Data relocation has failed.")); 641 goto write_VH; 642 } 643 644 /* Calculate new block number and other VH field */ 645 /* nblock must be rounded _down_ */ 646 nblock = geom->length / hfsp_sect_block; 647 nfree = PED_BE32_TO_CPU (vh->free_blocks) 648 - (old_blocks - nblock); 649 /* free block readjustement is only needed when incorrect nblock 650 was used by my previous implementation, so detect the case */ 651 if (priv_data->plus_geom->length < old_blocks 652 * ( PED_BE32_TO_CPU (vh->block_size) 653 / PED_SECTOR_SIZE_DEFAULT) ) { 654 if (priv_data->plus_geom->length % hfsp_sect_block == 1) 655 nfree++; 656 } 657 658 /* Check that all block after future end are really free */ 659 mblock = ( priv_data->plus_geom->length - 2 ) 660 / hfsp_sect_block; 661 if (mblock > old_blocks - 1) 662 mblock = old_blocks - 1; 663 for ( block = nblock; 664 block < mblock; 665 block++ ) { 666 if (TST_BLOC_OCCUPATION(priv_data->alloc_map,block)) { 667 resize = 0; 668 ped_exception_throw ( 669 PED_EXCEPTION_ERROR, 670 PED_EXCEPTION_CANCEL, 671 _("Data relocation left some data at the end " 672 "of the volume.")); 673 goto write_VH; 674 } 675 } 676 677 /* Mark out of volume blocks as used */ 678 map_sectors = ( ( old_blocks + PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) 679 / (PED_SECTOR_SIZE_DEFAULT * 8) ) 680 * (PED_SECTOR_SIZE_DEFAULT * 8); 681 for ( block = nblock; block < map_sectors; ++block) 682 SET_BLOC_OCCUPATION(priv_data->alloc_map, block); 683 684 /* Update geometry */ 685 if (resize) { 686 /* update in fs structure */ 687 if (PED_BE32_TO_CPU (vh->next_allocation) >= nblock) 688 vh->next_allocation = PED_CPU_TO_BE32 (0); 689 vh->total_blocks = PED_CPU_TO_BE32 (nblock); 690 vh->free_blocks = PED_CPU_TO_BE32 (nfree); 691 /* update parted structure */ 692 priv_data->plus_geom->length = geom->length; 693 priv_data->plus_geom->end = priv_data->plus_geom->start 694 + geom->length - 1; 695 } 696 697 /* Effective write */ 698 write_VH: 699 /* lasts two sectors are allocated by the alternate VH 700 and a reserved sector, and last block is always reserved */ 701 block = (priv_data->plus_geom->length - 1) / hfsp_sect_block; 702 if (block < PED_BE32_TO_CPU (vh->total_blocks)) 703 SET_BLOC_OCCUPATION(priv_data->alloc_map, block); 704 block = (priv_data->plus_geom->length - 2) / hfsp_sect_block; 705 if (block < PED_BE32_TO_CPU (vh->total_blocks)) 706 SET_BLOC_OCCUPATION(priv_data->alloc_map, block); 707 SET_BLOC_OCCUPATION(priv_data->alloc_map, 708 PED_BE32_TO_CPU (vh->total_blocks) - 1); 709 710 /* Write the _old_ area to set out of volume blocks as used */ 711 map_sectors = ( old_blocks + PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) 712 / (PED_SECTOR_SIZE_DEFAULT * 8); 713 if (!hfsplus_file_write (priv_data->allocation_file, 714 priv_data->alloc_map, 0, map_sectors)) { 715 resize = 0; 716 ped_exception_throw ( 717 PED_EXCEPTION_ERROR, 718 PED_EXCEPTION_CANCEL, 719 _("Error while writing the allocation file.")); 720 } else { 721 /* Write remaining part of allocation bitmap */ 722 /* This is necessary to handle pre patch-11 and third party */ 723 /* implementations */ 724 memset(buf, 0xFF, PED_SECTOR_SIZE_DEFAULT); 725 for (block = map_sectors; 726 block < priv_data->allocation_file->sect_nb; 727 ++block) { 728 if (!hfsplus_file_write_sector ( 729 priv_data->allocation_file, 730 buf, block)) { 731 ped_exception_throw ( 732 PED_EXCEPTION_WARNING, 733 PED_EXCEPTION_IGNORE, 734 _("Error while writing the " 735 "compatibility part of the " 736 "allocation file.")); 737 break; 738 } 739 } 740 } 741 ped_geometry_sync (priv_data->plus_geom); 742 743 if (resize) { 744 /* Set the unmounted bit and clear the inconsistent bit */ 745 vh->attributes |= PED_CPU_TO_BE32 ( 1 << HFS_UNMOUNTED ); 746 vh->attributes &= ~ PED_CPU_TO_BE32 ( 1 << HFSP_INCONSISTENT ); 747 } 748 749 ped_timer_set_state_name(timer, _("writing HFS+ Volume Header")); 750 if (!hfsplus_update_vh(fs)) { 751 ped_geometry_sync(priv_data->plus_geom); 752 return 0; 753 } 754 755 if (!ped_geometry_sync(priv_data->plus_geom)) 756 return 0; 757 758 ped_timer_update(timer, 1.0); 759 760 return (resize); 761 } 762 763 /* Update the HFS wrapper mdb and bad blocks file to reflect 764 the new geometry of the embedded HFS+ volume */ 765 static int 766 hfsplus_wrapper_update (PedFileSystem* fs) 767 { 768 uint8_t node[PED_SECTOR_SIZE_DEFAULT]; 769 HfsCPrivateLeafRec ref; 770 HfsExtentKey key; 771 HfsNodeDescriptor* node_desc = (HfsNodeDescriptor*) node; 772 HfsExtentKey* ret_key; 773 HfsExtDescriptor* ret_data; 774 unsigned int i; 775 HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) 776 fs->type_specific; 777 HfsPrivateFSData* hfs_priv_data = (HfsPrivateFSData*) 778 priv_data->wrapper->type_specific; 779 unsigned int hfs_sect_block = 780 PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size) 781 / PED_SECTOR_SIZE_DEFAULT ; 782 PedSector hfsplus_sect = (PedSector) 783 PED_BE32_TO_CPU (priv_data->vh->total_blocks) 784 * ( PED_BE32_TO_CPU (priv_data->vh->block_size) 785 / PED_SECTOR_SIZE_DEFAULT ); 786 unsigned int hfs_blocks_embedded = 787 (hfsplus_sect + hfs_sect_block - 1) 788 / hfs_sect_block; 789 unsigned int hfs_blocks_embedded_old; 790 791 /* update HFS wrapper MDB */ 792 hfs_blocks_embedded_old = PED_BE16_TO_CPU ( 793 hfs_priv_data->mdb->old_new 794 .embedded.location.block_count ); 795 hfs_priv_data->mdb->old_new.embedded.location.block_count = 796 PED_CPU_TO_BE16 (hfs_blocks_embedded); 797 /* maybe macOS will boot with this */ 798 /* update : yes it does \o/ :) */ 799 hfs_priv_data->mdb->free_blocks = 800 PED_CPU_TO_BE16 ( PED_BE16_TO_CPU (hfs_priv_data->mdb->free_blocks) 801 + hfs_blocks_embedded_old 802 - hfs_blocks_embedded ); 803 804 if (!hfs_update_mdb(priv_data->wrapper)) 805 return 0; 806 807 /* force reload bad block list */ 808 if (hfs_priv_data->bad_blocks_loaded) { 809 hfs_free_bad_blocks_list (hfs_priv_data->bad_blocks_xtent_list); 810 hfs_priv_data->bad_blocks_xtent_list = NULL; 811 hfs_priv_data->bad_blocks_xtent_nb = 0; 812 hfs_priv_data->bad_blocks_loaded = 0; 813 } 814 815 /* clean HFS wrapper allocation map */ 816 for (i = PED_BE16_TO_CPU ( 817 hfs_priv_data->mdb->old_new.embedded 818 .location.start_block ) 819 + hfs_blocks_embedded; 820 i < PED_BE16_TO_CPU ( 821 hfs_priv_data->mdb->old_new.embedded 822 .location.start_block ) 823 + hfs_blocks_embedded_old; 824 i++ ) { 825 CLR_BLOC_OCCUPATION(hfs_priv_data->alloc_map, i); 826 } 827 /* and save it */ 828 if (!ped_geometry_write (fs->geom, hfs_priv_data->alloc_map, 829 PED_BE16_TO_CPU ( 830 hfs_priv_data->mdb->volume_bitmap_block ), 831 ( PED_BE16_TO_CPU ( 832 hfs_priv_data->mdb->total_blocks ) 833 + PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) 834 / (PED_SECTOR_SIZE_DEFAULT * 8))) 835 return 0; 836 if (!ped_geometry_sync (fs->geom)) 837 return 0; 838 839 /* search and update the bad blocks file */ 840 key.key_length = sizeof(key) - 1; 841 key.type = HFS_DATA_FORK; 842 key.file_ID = PED_CPU_TO_BE32 (HFS_BAD_BLOCK_ID); 843 key.start = 0; 844 if (!hfs_btree_search (hfs_priv_data->extent_file, 845 (HfsPrivateGenericKey*) &key, NULL, 0, &ref)) { 846 ped_exception_throw ( 847 PED_EXCEPTION_ERROR, 848 PED_EXCEPTION_CANCEL, 849 _("An error occurred while looking for the mandatory " 850 "bad blocks file.")); 851 return 0; 852 } 853 if (!hfs_file_read_sector (hfs_priv_data->extent_file, node, 854 ref.node_number)) 855 return 0; 856 ret_key = (HfsExtentKey*) (node + ref.record_pos); 857 ret_data = (HfsExtDescriptor*) ( node + ref.record_pos 858 + sizeof (HfsExtentKey) ); 859 860 while (ret_key->type == key.type && ret_key->file_ID == key.file_ID) { 861 for (i = 0; i < HFS_EXT_NB; i++) { 862 if ( ret_data[i].start_block 863 == hfs_priv_data->mdb->old_new 864 .embedded.location.start_block) { 865 ret_data[i].block_count = 866 hfs_priv_data->mdb->old_new 867 .embedded.location.block_count; 868 /* found ! : update */ 869 if (!hfs_file_write_sector ( 870 hfs_priv_data->extent_file, 871 node, ref.node_number) 872 || !ped_geometry_sync(fs->geom)) 873 return 0; 874 return 1; 875 } 876 } 877 878 if (ref.record_number < PED_BE16_TO_CPU (node_desc->rec_nb)) { 879 ref.record_number++; 880 } else { 881 ref.node_number = PED_BE32_TO_CPU (node_desc->next); 882 if (!ref.node_number 883 || !hfs_file_read_sector(hfs_priv_data->extent_file, 884 node, ref.node_number)) 885 goto bb_not_found; 886 ref.record_number = 1; 887 } 888 889 ref.record_pos = 890 PED_BE16_TO_CPU (*((uint16_t *) 891 (node + (PED_SECTOR_SIZE_DEFAULT 892 - 2*ref.record_number)))); 893 ret_key = (HfsExtentKey*) (node + ref.record_pos); 894 ret_data = (HfsExtDescriptor*) ( node + ref.record_pos 895 + sizeof (HfsExtentKey) ); 896 } 897 898 bb_not_found: 899 /* not found : not a valid hfs+ wrapper : failure */ 900 ped_exception_throw ( 901 PED_EXCEPTION_ERROR, 902 PED_EXCEPTION_CANCEL, 903 _("It seems there is an error in the HFS wrapper: the bad " 904 "blocks file doesn't contain the embedded HFS+ volume.")); 905 return 0; 906 } 907 908 static int 909 hfsplus_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer) 910 { 911 HfsPPrivateFSData* priv_data; 912 PedTimer* timer_plus; 913 PedGeometry* embedded_geom; 914 PedSector hgms; 915 916 /* check preconditions */ 917 PED_ASSERT (fs != NULL, return 0); 918 PED_ASSERT (fs->geom != NULL, return 0); 919 PED_ASSERT (geom != NULL, return 0); 920 PED_ASSERT (fs->geom->dev == geom->dev, return 0); 921 #ifdef DEBUG 922 PED_ASSERT ((hgms = hfsplus_get_min_size (fs)) != 0, return 0); 923 #else 924 if ((hgms = hfsplus_get_min_size (fs)) == 0) 925 return 0; 926 #endif 927 928 if (ped_geometry_test_equal(fs->geom, geom)) 929 return 1; 930 931 priv_data = (HfsPPrivateFSData*) fs->type_specific; 932 933 if (fs->geom->start != geom->start 934 || geom->length > fs->geom->length 935 || geom->length < hgms) { 936 ped_exception_throw ( 937 PED_EXCEPTION_NO_FEATURE, 938 PED_EXCEPTION_CANCEL, 939 _("Sorry, HFS+ cannot be resized that way yet.")); 940 return 0; 941 } 942 943 if (priv_data->wrapper) { 944 PedSector red, hgee; 945 HfsPrivateFSData* hfs_priv_data = (HfsPrivateFSData*) 946 priv_data->wrapper->type_specific; 947 unsigned int hfs_sect_block = 948 PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size) 949 / PED_SECTOR_SIZE_DEFAULT; 950 951 /* There is a wrapper so we must calculate the new geometry 952 of the embedded HFS+ volume */ 953 red = ( (fs->geom->length - geom->length + hfs_sect_block - 1) 954 / hfs_sect_block ) * hfs_sect_block; 955 /* Can't we shrink the hfs+ volume by the desired size ? */ 956 hgee = hfsplus_get_empty_end (fs); 957 if (!hgee) return 0; 958 if (red > priv_data->plus_geom->length - hgee) { 959 /* No, shrink hfs+ by the greatest possible value */ 960 hgee = ((hgee + hfs_sect_block - 1) / hfs_sect_block) 961 * hfs_sect_block; 962 red = priv_data->plus_geom->length - hgee; 963 } 964 embedded_geom = ped_geometry_new (geom->dev, 965 priv_data->plus_geom->start, 966 priv_data->plus_geom->length 967 - red); 968 969 /* There is a wrapper so the resize process is a two stages 970 process (embedded resizing then wrapper resizing) : 971 we create a sub timer */ 972 ped_timer_reset (timer); 973 ped_timer_set_state_name (timer, 974 _("shrinking embedded HFS+ volume")); 975 ped_timer_update(timer, 0.0); 976 timer_plus = ped_timer_new_nested (timer, 0.98); 977 } else { 978 /* No wrapper : the desired geometry is the desired 979 HFS+ volume geometry */ 980 embedded_geom = geom; 981 timer_plus = timer; 982 } 983 984 /* Resize the HFS+ volume */ 985 if (!hfsplus_volume_resize (fs, embedded_geom, timer_plus)) { 986 if (timer_plus != timer) ped_timer_destroy_nested (timer_plus); 987 ped_exception_throw ( 988 PED_EXCEPTION_ERROR, 989 PED_EXCEPTION_CANCEL, 990 _("Resizing the HFS+ volume has failed.")); 991 return 0; 992 } 993 994 if (priv_data->wrapper) { 995 ped_geometry_destroy (embedded_geom); 996 ped_timer_destroy_nested (timer_plus); 997 ped_timer_set_state_name(timer, _("shrinking HFS wrapper")); 998 timer_plus = ped_timer_new_nested (timer, 0.02); 999 /* There's a wrapper : second stage = resizing it */ 1000 if (!hfsplus_wrapper_update (fs) 1001 || !hfs_resize (priv_data->wrapper, geom, timer_plus)) { 1002 ped_timer_destroy_nested (timer_plus); 1003 ped_exception_throw ( 1004 PED_EXCEPTION_ERROR, 1005 PED_EXCEPTION_CANCEL, 1006 _("Updating the HFS wrapper has failed.")); 1007 return 0; 1008 } 1009 ped_timer_destroy_nested (timer_plus); 1010 } 1011 ped_timer_update(timer, 1.0); 1012 1013 return 1; 1014 } 1015 1016 #ifdef HFS_EXTRACT_FS 1017 /* The following is for debugging purpose only, NOT for packaging */ 1018 1019 #include <stdio.h> 1020 1021 uint8_t* extract_buffer = NULL; 1022 1023 static int 1024 hfs_extract_file(const char* filename, HfsPrivateFile* hfs_file) 1025 { 1026 FILE* fout; 1027 PedSector sect; 1028 1029 fout = fopen(filename, "w"); 1030 if (!fout) return 0; 1031 1032 for (sect = 0; sect < hfs_file->sect_nb; ++sect) { 1033 if (!hfs_file_read_sector(hfs_file, extract_buffer, sect)) 1034 goto err_close; 1035 if (!fwrite(extract_buffer, PED_SECTOR_SIZE_DEFAULT, 1, fout)) 1036 goto err_close; 1037 } 1038 1039 return (fclose(fout) == 0 ? 1 : 0); 1040 1041 err_close: 1042 fclose(fout); 1043 return 0; 1044 } 1045 1046 static int 1047 hfs_extract_bitmap(const char* filename, PedFileSystem* fs) 1048 { 1049 HfsPrivateFSData* priv_data = (HfsPrivateFSData*) 1050 fs->type_specific; 1051 HfsMasterDirectoryBlock* mdb = priv_data->mdb; 1052 unsigned int count; 1053 FILE* fout; 1054 PedSector sect; 1055 1056 fout = fopen(filename, "w"); 1057 if (!fout) return 0; 1058 1059 for (sect = PED_BE16_TO_CPU(mdb->volume_bitmap_block); 1060 sect < PED_BE16_TO_CPU(mdb->start_block); 1061 sect += count) { 1062 uint16_t st_block = PED_BE16_TO_CPU(mdb->start_block); 1063 count = (st_block-sect) < BLOCK_MAX_BUFF ? 1064 (st_block-sect) : BLOCK_MAX_BUFF; 1065 if (!ped_geometry_read(fs->geom, extract_buffer, sect, count)) 1066 goto err_close; 1067 if (!fwrite (extract_buffer, count * PED_SECTOR_SIZE_DEFAULT, 1068 1, fout)) 1069 goto err_close; 1070 } 1071 1072 return (fclose(fout) == 0 ? 1 : 0); 1073 1074 err_close: 1075 fclose(fout); 1076 return 0; 1077 } 1078 1079 static int 1080 hfs_extract_mdb (const char* filename, PedFileSystem* fs) 1081 { 1082 FILE* fout; 1083 1084 fout = fopen(filename, "w"); 1085 if (!fout) return 0; 1086 1087 if (!ped_geometry_read(fs->geom, extract_buffer, 2, 1)) 1088 goto err_close; 1089 if (!fwrite(extract_buffer, PED_SECTOR_SIZE_DEFAULT, 1, fout)) 1090 goto err_close; 1091 1092 return (fclose(fout) == 0 ? 1 : 0); 1093 1094 err_close: 1095 fclose(fout); 1096 return 0; 1097 } 1098 1099 static int 1100 hfs_extract (PedFileSystem* fs, PedTimer* timer) 1101 { 1102 HfsPrivateFSData* priv_data = (HfsPrivateFSData*) 1103 fs->type_specific; 1104 1105 ped_exception_throw ( 1106 PED_EXCEPTION_INFORMATION, 1107 PED_EXCEPTION_OK, 1108 _("This is not a real %s check. This is going to extract " 1109 "special low level files for debugging purposes."), 1110 "HFS"); 1111 1112 extract_buffer = ped_malloc(BLOCK_MAX_BUFF * PED_SECTOR_SIZE_DEFAULT); 1113 if (!extract_buffer) return 0; 1114 1115 hfs_extract_mdb(HFS_MDB_FILENAME, fs); 1116 hfs_extract_file(HFS_CATALOG_FILENAME, priv_data->catalog_file); 1117 hfs_extract_file(HFS_EXTENTS_FILENAME, priv_data->extent_file); 1118 hfs_extract_bitmap(HFS_BITMAP_FILENAME, fs); 1119 1120 ped_free(extract_buffer); extract_buffer = NULL; 1121 return 0; /* nothing has been fixed by us ! */ 1122 } 1123 1124 static int 1125 hfsplus_extract_file(const char* filename, HfsPPrivateFile* hfsp_file) 1126 { 1127 FILE* fout; 1128 unsigned int cp_sect; 1129 PedSector rem_sect; 1130 1131 fout = fopen(filename, "w"); 1132 if (!fout) return 0; 1133 1134 for (rem_sect = hfsp_file->sect_nb; rem_sect; rem_sect -= cp_sect) { 1135 cp_sect = rem_sect < BLOCK_MAX_BUFF ? rem_sect : BLOCK_MAX_BUFF; 1136 if (!hfsplus_file_read(hfsp_file, extract_buffer, 1137 hfsp_file->sect_nb - rem_sect, cp_sect)) 1138 goto err_close; 1139 if (!fwrite (extract_buffer, cp_sect * PED_SECTOR_SIZE_DEFAULT, 1140 1, fout)) 1141 goto err_close; 1142 } 1143 1144 return (fclose(fout) == 0 ? 1 : 0); 1145 1146 err_close: 1147 fclose(fout); 1148 return 0; 1149 } 1150 1151 static int 1152 hfsplus_extract_vh (const char* filename, PedFileSystem* fs) 1153 { 1154 HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) 1155 fs->type_specific; 1156 FILE* fout; 1157 PedGeometry* geom = priv_data->plus_geom; 1158 1159 1160 fout = fopen(filename, "w"); 1161 if (!fout) return 0; 1162 1163 if (!ped_geometry_read(geom, extract_buffer, 2, 1)) 1164 goto err_close; 1165 if (!fwrite(extract_buffer, PED_SECTOR_SIZE_DEFAULT, 1, fout)) 1166 goto err_close; 1167 1168 return (fclose(fout) == 0 ? 1 : 0); 1169 1170 err_close: 1171 fclose(fout); 1172 return 0; 1173 } 1174 1175 /* TODO : use the timer to report what is happening */ 1176 /* TODO : use exceptions to report errors */ 1177 static int 1178 hfsplus_extract (PedFileSystem* fs, PedTimer* timer) 1179 { 1180 HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) 1181 fs->type_specific; 1182 HfsPVolumeHeader* vh = priv_data->vh; 1183 HfsPPrivateFile* startup_file; 1184 1185 if (priv_data->wrapper) { 1186 /* TODO : create nested timer */ 1187 hfs_extract (priv_data->wrapper, timer); 1188 } 1189 1190 ped_exception_throw ( 1191 PED_EXCEPTION_INFORMATION, 1192 PED_EXCEPTION_OK, 1193 _("This is not a real %s check. This is going to extract " 1194 "special low level files for debugging purposes."), 1195 "HFS+"); 1196 1197 extract_buffer = ped_malloc(BLOCK_MAX_BUFF * PED_SECTOR_SIZE_DEFAULT); 1198 if (!extract_buffer) return 0; 1199 1200 hfsplus_extract_vh(HFSP_VH_FILENAME, fs); 1201 hfsplus_extract_file(HFSP_CATALOG_FILENAME, priv_data->catalog_file); 1202 hfsplus_extract_file(HFSP_EXTENTS_FILENAME, priv_data->extents_file); 1203 hfsplus_extract_file(HFSP_ATTRIB_FILENAME, priv_data->attributes_file); 1204 hfsplus_extract_file(HFSP_BITMAP_FILENAME, priv_data->allocation_file); 1205 1206 startup_file = hfsplus_file_open(fs, PED_CPU_TO_BE32(HFSP_STARTUP_ID), 1207 vh->startup_file.extents, 1208 PED_BE64_TO_CPU ( 1209 vh->startup_file.logical_size) 1210 / PED_SECTOR_SIZE_DEFAULT); 1211 if (startup_file) { 1212 hfsplus_extract_file(HFSP_STARTUP_FILENAME, startup_file); 1213 hfsplus_file_close(startup_file); startup_file = NULL; 1214 } 1215 1216 ped_free(extract_buffer); extract_buffer = NULL; 1217 return 0; /* nothing has been fixed by us ! */ 1218 } 1219 #endif /* HFS_EXTRACT_FS */ 1220 1221 #endif /* !DISCOVER_ONLY */ 1222 1223 static PedFileSystemOps hfs_ops = { 1224 .probe = hfs_probe, 1225 #ifndef DISCOVER_ONLY 1226 .clobber = hfs_clobber, 1227 .open = hfs_open, 1228 .create = NULL, 1229 .close = hfs_close, 1230 #ifndef HFS_EXTRACT_FS 1231 .check = NULL, 1232 #else 1233 .check = hfs_extract, 1234 #endif 1235 .copy = NULL, 1236 .resize = hfs_resize, 1237 .get_create_constraint = NULL, 1238 .get_resize_constraint = hfs_get_resize_constraint, 1239 .get_copy_constraint = NULL, 1240 #else /* DISCOVER_ONLY */ 1241 .clobber = NULL, 1242 .open = NULL, 1243 .create = NULL, 1244 .close = NULL, 1245 .check = NULL, 1246 .copy = NULL, 1247 .resize = NULL, 1248 .get_create_constraint = NULL, 1249 .get_resize_constraint = NULL, 1250 .get_copy_constraint = NULL, 1251 #endif /* DISCOVER_ONLY */ 1252 }; 1253 1254 static PedFileSystemOps hfsplus_ops = { 1255 .probe = hfsplus_probe, 1256 #ifndef DISCOVER_ONLY 1257 .clobber = hfsplus_clobber, 1258 .open = hfsplus_open, 1259 .create = NULL, 1260 .close = hfsplus_close, 1261 #ifndef HFS_EXTRACT_FS 1262 .check = NULL, 1263 #else 1264 .check = hfsplus_extract, 1265 #endif 1266 .copy = NULL, 1267 .resize = hfsplus_resize, 1268 .get_create_constraint = NULL, 1269 .get_resize_constraint = hfsplus_get_resize_constraint, 1270 .get_copy_constraint = NULL, 1271 #else /* DISCOVER_ONLY */ 1272 .clobber = NULL, 1273 .open = NULL, 1274 .create = NULL, 1275 .close = NULL, 1276 .check = NULL, 1277 .copy = NULL, 1278 .resize = NULL, 1279 .get_create_constraint = NULL, 1280 .get_resize_constraint = NULL, 1281 .get_copy_constraint = NULL, 1282 #endif /* DISCOVER_ONLY */ 1283 }; 1284 1285 static PedFileSystemOps hfsx_ops = { 1286 .probe = hfsx_probe, 1287 #ifndef DISCOVER_ONLY 1288 .clobber = hfs_clobber, /* NOT hfsplus_clobber ! 1289 HFSX can't be embedded */ 1290 .open = hfsplus_open, 1291 .create = NULL, 1292 .close = hfsplus_close, 1293 #ifndef HFS_EXTRACT_FS 1294 .check = NULL, 1295 #else 1296 .check = hfsplus_extract, 1297 #endif 1298 .copy = NULL, 1299 .resize = hfsplus_resize, 1300 .get_create_constraint = NULL, 1301 .get_resize_constraint = hfsplus_get_resize_constraint, 1302 .get_copy_constraint = NULL, 1303 #else /* DISCOVER_ONLY */ 1304 .clobber = NULL, 1305 .open = NULL, 1306 .create = NULL, 1307 .close = NULL, 1308 .check = NULL, 1309 .copy = NULL, 1310 .resize = NULL, 1311 .get_create_constraint = NULL, 1312 .get_resize_constraint = NULL, 1313 .get_copy_constraint = NULL, 1314 #endif /* DISCOVER_ONLY */ 1315 }; 1316 1317 1318 static PedFileSystemType hfs_type = { 1319 .next = NULL, 1320 .ops = &hfs_ops, 1321 .name = "hfs", 1322 .block_sizes = HFS_BLOCK_SIZES 1323 }; 1324 1325 static PedFileSystemType hfsplus_type = { 1326 .next = NULL, 1327 .ops = &hfsplus_ops, 1328 .name = "hfs+", 1329 .block_sizes = HFSP_BLOCK_SIZES 1330 }; 1331 1332 static PedFileSystemType hfsx_type = { 1333 .next = NULL, 1334 .ops = &hfsx_ops, 1335 .name = "hfsx", 1336 .block_sizes = HFSX_BLOCK_SIZES 1337 }; 1338 1339 void 1340 ped_file_system_hfs_init () 1341 { 1342 ped_file_system_type_register (&hfs_type); 1343 ped_file_system_type_register (&hfsplus_type); 1344 ped_file_system_type_register (&hfsx_type); 1345 } 1346 1347 void 1348 ped_file_system_hfs_done () 1349 { 1350 ped_file_system_type_unregister (&hfs_type); 1351 ped_file_system_type_unregister (&hfsplus_type); 1352 ped_file_system_type_unregister (&hfsx_type); 1353 }