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