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
hfs_effect_move_extent(PedFileSystem * fs,unsigned int * ptr_fblock,unsigned int * ptr_to_fblock,unsigned int size)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
hfs_update_mdb(PedFileSystem * fs)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
hfs_do_move(PedFileSystem * fs,unsigned int * ptr_src,unsigned int * ptr_dest,HfsCPrivateCache * cache,HfsCPrivateExtent * ref)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
hfs_save_allocation(PedFileSystem * fs)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
hfs_move_extent_starting_at(PedFileSystem * fs,unsigned int * ptr_fblock,unsigned int * ptr_to_fblock,HfsCPrivateCache * cache)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
hfs_cache_from_mdb(HfsCPrivateCache * cache,PedFileSystem * fs,PedTimer * timer)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
hfs_cache_from_catalog(HfsCPrivateCache * cache,PedFileSystem * fs,PedTimer * timer)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
hfs_cache_from_extent(HfsCPrivateCache * cache,PedFileSystem * fs,PedTimer * timer)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*
hfs_cache_extents(PedFileSystem * fs,PedTimer * timer)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
hfs_pack_free_space_from_block(PedFileSystem * fs,unsigned int fblock,PedTimer * timer,unsigned int to_free)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 */
671