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 */