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