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.h" 37 #include "advfs.h" 38 #include "cache.h" 39 40 #include "reloc.h" 41 42 /* This function moves data of size blocks starting 43 at block *ptr_fblock to block *ptr_to_fblock */ 44 /* return new start or -1 on failure */ 45 static int 46 hfs_effect_move_extent (PedFileSystem *fs, unsigned int *ptr_fblock, 47 unsigned int *ptr_to_fblock, unsigned int size) 48 { 49 HfsPrivateFSData* priv_data = (HfsPrivateFSData*) 50 fs->type_specific; 51 unsigned int i, ok = 0; 52 unsigned int next_to_fblock; 53 unsigned int start, stop; 54 55 PED_ASSERT (hfs_block != NULL, return -1); 56 PED_ASSERT (*ptr_to_fblock <= *ptr_fblock, return -1); 57 /* quiet gcc */ 58 next_to_fblock = start = stop = 0; 59 60 /* 61 Try to fit the extent AT or _BEFORE_ the wanted place, 62 or then in the gap between dest and source. 63 If failed try to fit the extent after source, for 2 pass relocation 64 The extent is always copied in a non overlapping way 65 */ 66 67 /* Backward search */ 68 /* 1 pass relocation AT or BEFORE *ptr_to_fblock */ 69 if (*ptr_to_fblock != *ptr_fblock) { 70 start = stop = *ptr_fblock < *ptr_to_fblock+size ? 71 *ptr_fblock : *ptr_to_fblock+size; 72 while (start && stop-start != size) { 73 --start; 74 if (TST_BLOC_OCCUPATION(priv_data->alloc_map,start)) 75 stop = start; 76 } 77 ok = (stop-start == size); 78 } 79 80 /* Forward search */ 81 /* 1 pass relocation in the gap merged with 2 pass reloc after source */ 82 if (!ok && *ptr_to_fblock != *ptr_fblock) { 83 start = stop = *ptr_to_fblock+1; 84 while (stop < PED_BE16_TO_CPU(priv_data->mdb->total_blocks) 85 && stop-start != size) { 86 if (TST_BLOC_OCCUPATION(priv_data->alloc_map,stop)) 87 start = stop + 1; 88 ++stop; 89 } 90 ok = (stop-start == size); 91 } 92 93 /* new non overlapping room has been found ? */ 94 if (ok) { 95 /* enough room */ 96 unsigned int j; 97 unsigned int start_block = 98 PED_BE16_TO_CPU (priv_data->mdb->start_block ); 99 unsigned int block_sz = 100 (PED_BE32_TO_CPU (priv_data->mdb->block_size) 101 / PED_SECTOR_SIZE_DEFAULT); 102 103 if (stop > *ptr_to_fblock && stop <= *ptr_fblock) 104 /* Fit in the gap */ 105 next_to_fblock = stop; 106 else 107 /* Before or after the gap */ 108 next_to_fblock = *ptr_to_fblock; 109 110 /* move blocks */ 111 for (i = 0; i < size; /*i+=j*/) { 112 PedSector abs_sector; 113 unsigned int ai; 114 115 j = size - i; j = (j < hfs_block_count) ? 116 j : hfs_block_count ; 117 118 abs_sector = start_block 119 + (PedSector) (*ptr_fblock + i) * block_sz; 120 if (!ped_geometry_read (fs->geom, hfs_block, abs_sector, 121 block_sz * j)) 122 return -1; 123 124 abs_sector = start_block 125 + (PedSector) (start + i) * block_sz; 126 if (!ped_geometry_write (fs->geom,hfs_block,abs_sector, 127 block_sz * j)) 128 return -1; 129 130 for (ai = i+j; i < ai; i++) { 131 /* free source block */ 132 CLR_BLOC_OCCUPATION(priv_data->alloc_map, 133 *ptr_fblock + i); 134 135 /* set dest block */ 136 SET_BLOC_OCCUPATION(priv_data->alloc_map, 137 start + i); 138 } 139 } 140 if (!ped_geometry_sync_fast (fs->geom)) 141 return -1; 142 143 *ptr_fblock += size; 144 *ptr_to_fblock = next_to_fblock; 145 } else { 146 if (*ptr_fblock != *ptr_to_fblock) 147 /* not enough room, but try to continue */ 148 ped_exception_throw (PED_EXCEPTION_WARNING, 149 PED_EXCEPTION_IGNORE, 150 _("An extent has not been relocated.")); 151 start = *ptr_fblock; 152 *ptr_fblock = *ptr_to_fblock = start + size; 153 } 154 155 return start; 156 } 157 158 /* Update MDB */ 159 /* Return 0 if an error occurred */ 160 /* Return 1 if everything ok */ 161 int 162 hfs_update_mdb (PedFileSystem *fs) 163 { 164 HfsPrivateFSData* priv_data = (HfsPrivateFSData*) 165 fs->type_specific; 166 uint8_t node[PED_SECTOR_SIZE_DEFAULT]; 167 168 if (!ped_geometry_read (fs->geom, node, 2, 1)) 169 return 0; 170 memcpy (node, priv_data->mdb, sizeof (HfsMasterDirectoryBlock)); 171 if ( !ped_geometry_write (fs->geom, node, 2, 1) 172 || !ped_geometry_write (fs->geom, node, fs->geom->length - 2, 1) 173 || !ped_geometry_sync_fast (fs->geom)) 174 return 0; 175 return 1; 176 } 177 178 /* Generic relocator */ 179 /* replace previous hfs_do_move_* */ 180 static int 181 hfs_do_move (PedFileSystem* fs, unsigned int *ptr_src, 182 unsigned int *ptr_dest, HfsCPrivateCache* cache, 183 HfsCPrivateExtent* ref) 184 { 185 uint8_t node[PED_SECTOR_SIZE_DEFAULT]; 186 HfsPrivateFSData* priv_data = (HfsPrivateFSData*) 187 fs->type_specific; 188 HfsPrivateFile* file; 189 HfsExtDescriptor* extent; 190 HfsCPrivateExtent* move; 191 int new_start; 192 193 new_start = hfs_effect_move_extent (fs, ptr_src, ptr_dest, 194 ref->ext_length); 195 if (new_start == -1) return -1; 196 197 if (ref->ext_start != (unsigned) new_start) { 198 /* Load, modify & save */ 199 switch (ref->where) { 200 /******** MDB *********/ 201 case CR_PRIM_CAT : 202 priv_data->catalog_file 203 ->first[ref->ref_index].start_block = 204 PED_CPU_TO_BE16(new_start); 205 goto CR_PRIM; 206 case CR_PRIM_EXT : 207 priv_data->extent_file 208 ->first[ref->ref_index].start_block = 209 PED_CPU_TO_BE16(new_start); 210 CR_PRIM : 211 extent = ( HfsExtDescriptor* ) 212 ( (uint8_t*)priv_data->mdb + ref->ref_offset ); 213 extent[ref->ref_index].start_block = 214 PED_CPU_TO_BE16(new_start); 215 if (!hfs_update_mdb(fs)) return -1; 216 break; 217 218 /********* BTREE *******/ 219 case CR_BTREE_EXT_CAT : 220 if (priv_data->catalog_file 221 ->cache[ref->ref_index].start_block 222 == PED_CPU_TO_BE16(ref->ext_start)) 223 priv_data->catalog_file 224 ->cache[ref->ref_index].start_block = 225 PED_CPU_TO_BE16(new_start); 226 case CR_BTREE_EXT_0 : 227 file = priv_data->extent_file; 228 goto CR_BTREE; 229 case CR_BTREE_CAT : 230 file = priv_data->catalog_file; 231 CR_BTREE: 232 PED_ASSERT(ref->sect_by_block == 1 233 && ref->ref_offset < PED_SECTOR_SIZE_DEFAULT, 234 return -1); 235 if (!hfs_file_read_sector(file, node, ref->ref_block)) 236 return -1; 237 extent = ( HfsExtDescriptor* ) (node + ref->ref_offset); 238 extent[ref->ref_index].start_block = 239 PED_CPU_TO_BE16(new_start); 240 if (!hfs_file_write_sector(file, node, ref->ref_block) 241 || !ped_geometry_sync_fast (fs->geom)) 242 return -1; 243 break; 244 245 /********** BUG ********/ 246 default : 247 ped_exception_throw ( 248 PED_EXCEPTION_ERROR, 249 PED_EXCEPTION_CANCEL, 250 _("A reference to an extent comes from a place " 251 "it should not. You should check the file " 252 "system!")); 253 return -1; 254 break; 255 } 256 257 /* Update the cache */ 258 move = hfsc_cache_move_extent(cache, ref->ext_start, new_start); 259 if (!move) return -1; /* "cleanly" fail */ 260 PED_ASSERT(move == ref, return -1); /* generate a bug */ 261 } 262 263 return new_start; 264 } 265 266 /* 0 error, 1 ok */ 267 static int 268 hfs_save_allocation(PedFileSystem* fs) 269 { 270 HfsPrivateFSData* priv_data = (HfsPrivateFSData*) 271 fs->type_specific; 272 unsigned int map_sectors; 273 274 map_sectors = ( PED_BE16_TO_CPU (priv_data->mdb->total_blocks) 275 + PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) 276 / (PED_SECTOR_SIZE_DEFAULT * 8); 277 return ( ped_geometry_write (fs->geom, priv_data->alloc_map, 278 PED_BE16_TO_CPU (priv_data->mdb->volume_bitmap_block), 279 map_sectors) ); 280 } 281 282 /* This function moves an extent starting at block fblock to block to_fblock 283 if there's enough room */ 284 /* Return 1 if everything was fine */ 285 /* Return -1 if an error occurred */ 286 /* Return 0 if no extent was found */ 287 /* Generic search thanks to the file system cache */ 288 static int 289 hfs_move_extent_starting_at (PedFileSystem *fs, unsigned int *ptr_fblock, 290 unsigned int *ptr_to_fblock, 291 HfsCPrivateCache* cache) 292 { 293 HfsCPrivateExtent* ref; 294 unsigned int old_start, new_start; 295 296 /* Reference search powered by the cache... */ 297 /* This is the optimisation secret :) */ 298 ref = hfsc_cache_search_extent(cache, *ptr_fblock); 299 if (!ref) return 0; /* not found */ 300 301 old_start = *ptr_fblock; 302 new_start = hfs_do_move(fs, ptr_fblock, ptr_to_fblock, cache, ref); 303 if (new_start == (unsigned int) -1) return -1; 304 if (new_start > old_start) { /* detect 2 pass reloc */ 305 new_start = hfs_do_move(fs,&new_start,ptr_to_fblock,cache,ref); 306 if (new_start == (unsigned int) -1 || new_start > old_start) 307 return -1; 308 } 309 310 /* allocation bitmap save is not atomic with data relocation */ 311 /* so we only do it a few times, and without syncing */ 312 /* The unmounted bit protect us anyway */ 313 hfs_save_allocation(fs); 314 return 1; 315 } 316 317 static int 318 hfs_cache_from_mdb(HfsCPrivateCache* cache, PedFileSystem* fs, 319 PedTimer* timer) 320 { 321 HfsPrivateFSData* priv_data = (HfsPrivateFSData*) 322 fs->type_specific; 323 HfsExtDescriptor* extent; 324 unsigned int j; 325 326 extent = priv_data->mdb->extents_file_rec; 327 for (j = 0; j < HFS_EXT_NB; ++j) { 328 if (!extent[j].block_count) break; 329 if (!hfsc_cache_add_extent( 330 cache, 331 PED_BE16_TO_CPU(extent[j].start_block), 332 PED_BE16_TO_CPU(extent[j].block_count), 333 0, /* unused for mdb */ 334 ((uint8_t*)extent) - ((uint8_t*)priv_data->mdb), 335 1, /* load/save only 1 sector */ 336 CR_PRIM_EXT, 337 j ) 338 ) 339 return 0; 340 } 341 342 extent = priv_data->mdb->catalog_file_rec; 343 for (j = 0; j < HFS_EXT_NB; ++j) { 344 if (!extent[j].block_count) break; 345 if (!hfsc_cache_add_extent( 346 cache, 347 PED_BE16_TO_CPU(extent[j].start_block), 348 PED_BE16_TO_CPU(extent[j].block_count), 349 0, 350 ((uint8_t*)extent) - ((uint8_t*)priv_data->mdb), 351 1, 352 CR_PRIM_CAT, 353 j ) 354 ) 355 return 0; 356 } 357 358 return 1; 359 } 360 361 static int 362 hfs_cache_from_catalog(HfsCPrivateCache* cache, PedFileSystem* fs, 363 PedTimer* timer) 364 { 365 HfsPrivateFSData* priv_data = (HfsPrivateFSData*) 366 fs->type_specific; 367 uint8_t node[PED_SECTOR_SIZE_DEFAULT]; 368 HfsHeaderRecord* header; 369 HfsNodeDescriptor* desc = (HfsNodeDescriptor*) node; 370 HfsCatalogKey* catalog_key; 371 HfsCatalog* catalog_data; 372 HfsExtDescriptor* extent; 373 unsigned int leaf_node, record_number; 374 unsigned int i, j; 375 376 if (!priv_data->catalog_file->sect_nb) { 377 ped_exception_throw ( 378 PED_EXCEPTION_INFORMATION, 379 PED_EXCEPTION_OK, 380 _("This HFS volume has no catalog file. " 381 "This is very unusual!")); 382 return 1; 383 } 384 385 if (!hfs_file_read_sector (priv_data->catalog_file, node, 0)) 386 return 0; 387 header = (HfsHeaderRecord*)(node + PED_BE16_TO_CPU(*((uint16_t*) 388 (node+(PED_SECTOR_SIZE_DEFAULT-2))))); 389 390 for (leaf_node = PED_BE32_TO_CPU (header->first_leaf_node); 391 leaf_node; 392 leaf_node = PED_BE32_TO_CPU (desc->next)) { 393 if (!hfs_file_read_sector (priv_data->catalog_file, 394 node, leaf_node)) 395 return 0; 396 record_number = PED_BE16_TO_CPU (desc->rec_nb); 397 for (i = 1; i <= record_number; ++i) { 398 /* undocumented alignement */ 399 unsigned int skip; 400 catalog_key = (HfsCatalogKey*) (node + PED_BE16_TO_CPU( 401 *((uint16_t*)(node+(PED_SECTOR_SIZE_DEFAULT - 2*i))))); 402 skip = (1 + catalog_key->key_length + 1) & ~1; 403 catalog_data = (HfsCatalog*)( ((uint8_t*)catalog_key) 404 + skip ); 405 /* check for obvious error in FS */ 406 if (((uint8_t*)catalog_key - node < HFS_FIRST_REC) 407 || ((uint8_t*)catalog_data - node 408 >= PED_SECTOR_SIZE_DEFAULT 409 - 2 * (signed)(record_number+1))) { 410 ped_exception_throw ( 411 PED_EXCEPTION_ERROR, 412 PED_EXCEPTION_CANCEL, 413 _("The file system contains errors.")); 414 return 0; 415 } 416 417 if (catalog_data->type != HFS_CAT_FILE) continue; 418 419 extent = catalog_data->sel.file.extents_data; 420 for (j = 0; j < HFS_EXT_NB; ++j) { 421 if (!extent[j].block_count) break; 422 if (!hfsc_cache_add_extent( 423 cache, 424 PED_BE16_TO_CPU(extent[j].start_block), 425 PED_BE16_TO_CPU(extent[j].block_count), 426 leaf_node, 427 (uint8_t*)extent - node, 428 1, /* hfs => btree block = 512 b */ 429 CR_BTREE_CAT, 430 j ) 431 ) 432 return 0; 433 } 434 435 extent = catalog_data->sel.file.extents_res; 436 for (j = 0; j < HFS_EXT_NB; ++j) { 437 if (!extent[j].block_count) break; 438 if (!hfsc_cache_add_extent( 439 cache, 440 PED_BE16_TO_CPU(extent[j].start_block), 441 PED_BE16_TO_CPU(extent[j].block_count), 442 leaf_node, 443 (uint8_t*)extent - node, 444 1, /* hfs => btree block = 512 b */ 445 CR_BTREE_CAT, 446 j ) 447 ) 448 return 0; 449 } 450 } 451 } 452 453 return 1; 454 } 455 456 static int 457 hfs_cache_from_extent(HfsCPrivateCache* cache, PedFileSystem* fs, 458 PedTimer* timer) 459 { 460 HfsPrivateFSData* priv_data = (HfsPrivateFSData*) 461 fs->type_specific; 462 uint8_t node[PED_SECTOR_SIZE_DEFAULT]; 463 HfsHeaderRecord* header; 464 HfsNodeDescriptor* desc = (HfsNodeDescriptor*) node; 465 HfsExtentKey* extent_key; 466 HfsExtDescriptor* extent; 467 unsigned int leaf_node, record_number; 468 unsigned int i, j; 469 470 if (!priv_data->extent_file->sect_nb) { 471 ped_exception_throw ( 472 PED_EXCEPTION_INFORMATION, 473 PED_EXCEPTION_OK, 474 _("This HFS volume has no extents overflow " 475 "file. This is quite unusual!")); 476 return 1; 477 } 478 479 if (!hfs_file_read_sector (priv_data->extent_file, node, 0)) 480 return 0; 481 header = ((HfsHeaderRecord*) (node + PED_BE16_TO_CPU(*((uint16_t *) 482 (node+(PED_SECTOR_SIZE_DEFAULT-2)))))); 483 484 for (leaf_node = PED_BE32_TO_CPU (header->first_leaf_node); 485 leaf_node; 486 leaf_node = PED_BE32_TO_CPU (desc->next)) { 487 if (!hfs_file_read_sector (priv_data->extent_file, node, 488 leaf_node)) 489 return 0; 490 record_number = PED_BE16_TO_CPU (desc->rec_nb); 491 for (i = 1; i <= record_number; i++) { 492 uint8_t where; 493 extent_key = (HfsExtentKey*) 494 (node + PED_BE16_TO_CPU(*((uint16_t *) 495 (node+(PED_SECTOR_SIZE_DEFAULT - 2*i))))); 496 /* size is cst */ 497 extent = (HfsExtDescriptor*)(((uint8_t*)extent_key) 498 + sizeof (HfsExtentKey)); 499 /* check for obvious error in FS */ 500 if (((uint8_t*)extent_key - node < HFS_FIRST_REC) 501 || ((uint8_t*)extent - node 502 >= PED_SECTOR_SIZE_DEFAULT 503 - 2 * (signed)(record_number+1))) { 504 ped_exception_throw ( 505 PED_EXCEPTION_ERROR, 506 PED_EXCEPTION_CANCEL, 507 _("The file system contains errors.")); 508 return 0; 509 } 510 511 switch (extent_key->file_ID) { 512 case PED_CPU_TO_BE32 (HFS_XTENT_ID) : 513 if (ped_exception_throw ( 514 PED_EXCEPTION_WARNING, 515 PED_EXCEPTION_IGNORE_CANCEL, 516 _("The extents overflow file should not" 517 " contain its own extents! You " 518 "should check the file system.")) 519 != PED_EXCEPTION_IGNORE) 520 return 0; 521 where = CR_BTREE_EXT_EXT; 522 break; 523 case PED_CPU_TO_BE32 (HFS_CATALOG_ID) : 524 where = CR_BTREE_EXT_CAT; 525 break; 526 default : 527 where = CR_BTREE_EXT_0; 528 break; 529 } 530 531 for (j = 0; j < HFS_EXT_NB; ++j) { 532 if (!extent[j].block_count) break; 533 if (!hfsc_cache_add_extent( 534 cache, 535 PED_BE16_TO_CPU(extent[j].start_block), 536 PED_BE16_TO_CPU(extent[j].block_count), 537 leaf_node, 538 (uint8_t*)extent - node, 539 1, /* hfs => btree block = 512 b */ 540 where, 541 j ) 542 ) 543 return 0; 544 } 545 } 546 } 547 548 return 1; 549 } 550 551 /* This function cache every extents start and length stored in any 552 fs structure into the adt defined in cache.[ch] 553 Returns NULL on failure */ 554 static HfsCPrivateCache* 555 hfs_cache_extents(PedFileSystem *fs, PedTimer* timer) 556 { 557 HfsPrivateFSData* priv_data = (HfsPrivateFSData*) 558 fs->type_specific; 559 HfsCPrivateCache* ret; 560 unsigned int file_number, block_number; 561 562 file_number = PED_BE32_TO_CPU(priv_data->mdb->file_count); 563 block_number = PED_BE16_TO_CPU(priv_data->mdb->total_blocks); 564 ret = hfsc_new_cache(block_number, file_number); 565 if (!ret) return NULL; 566 567 if (!hfs_cache_from_mdb(ret, fs, timer) || 568 !hfs_cache_from_catalog(ret, fs, timer) || 569 !hfs_cache_from_extent(ret, fs, timer)) { 570 ped_exception_throw( 571 PED_EXCEPTION_ERROR, 572 PED_EXCEPTION_CANCEL, 573 _("Could not cache the file system in memory.")); 574 hfsc_delete_cache(ret); 575 return NULL; 576 } 577 578 return ret; 579 } 580 581 /* This function moves file's data to compact used and free space, 582 starting at fblock block */ 583 /* return 0 on error */ 584 int 585 hfs_pack_free_space_from_block (PedFileSystem *fs, unsigned int fblock, 586 PedTimer* timer, unsigned int to_free) 587 { 588 PedSector bytes_buff; 589 HfsPrivateFSData* priv_data = (HfsPrivateFSData*) 590 fs->type_specific; 591 HfsMasterDirectoryBlock* mdb = priv_data->mdb; 592 HfsCPrivateCache* cache; 593 unsigned int to_fblock = fblock; 594 unsigned int start = fblock; 595 unsigned int divisor = PED_BE16_TO_CPU (mdb->total_blocks) 596 + 1 - start - to_free; 597 int ret; 598 599 PED_ASSERT (!hfs_block, return 0); 600 601 cache = hfs_cache_extents (fs, timer); 602 if (!cache) 603 return 0; 604 605 /* Calculate the size of the copy buffer : 606 * Takes BLOCK_MAX_BUFF HFS blocks, but if > BYTES_MAX_BUFF 607 * takes the maximum number of HFS blocks so that the buffer 608 * will remain smaller than or equal to BYTES_MAX_BUFF, with 609 * a minimum of 1 HFS block */ 610 bytes_buff = PED_BE32_TO_CPU (priv_data->mdb->block_size) 611 * (PedSector) BLOCK_MAX_BUFF; 612 if (bytes_buff > BYTES_MAX_BUFF) { 613 hfs_block_count = BYTES_MAX_BUFF 614 / PED_BE32_TO_CPU (priv_data->mdb->block_size); 615 if (!hfs_block_count) 616 hfs_block_count = 1; 617 bytes_buff = (PedSector) hfs_block_count 618 * PED_BE32_TO_CPU (priv_data->mdb->block_size); 619 } else 620 hfs_block_count = BLOCK_MAX_BUFF; 621 622 /* If the cache code requests more space, give it to him */ 623 if (bytes_buff < hfsc_cache_needed_buffer (cache)) 624 bytes_buff = hfsc_cache_needed_buffer (cache); 625 626 hfs_block = (uint8_t*) ped_malloc (bytes_buff); 627 if (!hfs_block) 628 goto error_cache; 629 630 if (!hfs_read_bad_blocks (fs)) { 631 ped_exception_throw ( 632 PED_EXCEPTION_ERROR, 633 PED_EXCEPTION_CANCEL, 634 _("Bad blocks list could not be loaded.")); 635 goto error_alloc; 636 } 637 638 while (fblock < PED_BE16_TO_CPU (mdb->total_blocks)) { 639 if (TST_BLOC_OCCUPATION(priv_data->alloc_map,fblock) 640 && (!hfs_is_bad_block (fs, fblock))) { 641 if (!(ret = hfs_move_extent_starting_at (fs, &fblock, 642 &to_fblock, cache))) 643 to_fblock = ++fblock; 644 else if (ret == -1) { 645 ped_exception_throw ( 646 PED_EXCEPTION_ERROR, 647 PED_EXCEPTION_CANCEL, 648 _("An error occurred during extent " 649 "relocation.")); 650 goto error_alloc; 651 } 652 } else { 653 fblock++; 654 } 655 656 ped_timer_update(timer, (float)(to_fblock - start)/divisor); 657 } 658 659 ped_free (hfs_block); hfs_block = NULL; hfs_block_count = 0; 660 hfsc_delete_cache (cache); 661 return 1; 662 663 error_alloc: 664 ped_free (hfs_block); hfs_block = NULL; hfs_block_count = 0; 665 error_cache: 666 hfsc_delete_cache (cache); 667 return 0; 668 } 669 670 #endif /* !DISCOVER_ONLY */