2
libparted - a library for manipulating disk partitions
3
Copyright (C) 2000, 2003-2005, 2007, 2009-2012 Free Software Foundation,
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 3 of the License, or
9
(at your option) any later version.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program. If not, see <http://www.gnu.org/licenses/>.
21
Author : Guillaume Knispel <k_guillaume@libertysurf.fr>
22
Report bug to <bug-parted@gnu.org>
27
#include <parted/parted.h>
28
#include <parted/endian.h>
29
#include <parted/debug.h>
34
# define _(String) dgettext (PACKAGE, String)
36
# define _(String) (String)
37
#endif /* ENABLE_NLS */
42
uint8_t* hfs_block = NULL;
43
uint8_t* hfsp_block = NULL;
44
unsigned hfs_block_count;
45
unsigned hfsp_block_count;
47
#define HFS_BLOCK_SIZES ((int[2]){512, 0})
48
#define HFSP_BLOCK_SIZES ((int[2]){512, 0})
49
#define HFSX_BLOCK_SIZES ((int[2]){512, 0})
56
static PedFileSystemType hfs_type;
57
static PedFileSystemType hfsplus_type;
62
/* This is a very unundoable operation */
63
/* Maybe I shouldn't touch the alternate MDB ? */
64
/* Anyway clobber is call before other fs creation */
65
/* So this is a non-issue */
67
hfs_clobber (PedGeometry* geom)
69
uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
71
memset (buf, 0, PED_SECTOR_SIZE_DEFAULT);
73
/* destroy boot blocks, mdb, alternate mdb ... */
74
return (!!ped_geometry_write (geom, buf, 0, 1)) &
75
(!!ped_geometry_write (geom, buf, 1, 1)) &
76
(!!ped_geometry_write (geom, buf, 2, 1)) &
77
(!!ped_geometry_write (geom, buf, geom->length - 2, 1)) &
78
(!!ped_geometry_write (geom, buf, geom->length - 1, 1)) &
79
(!!ped_geometry_sync (geom));
83
hfs_open (PedGeometry* geom)
85
uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
87
HfsMasterDirectoryBlock* mdb;
88
HfsPrivateFSData* priv_data;
90
if (!hfsc_can_use_geom (geom))
94
if (!ped_geometry_read (geom, buf, 2, 1))
98
fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
100
mdb = (HfsMasterDirectoryBlock*)
101
ped_malloc (sizeof (HfsMasterDirectoryBlock));
102
if (!mdb) goto ho_fs;
103
priv_data = (HfsPrivateFSData*)
104
ped_malloc (sizeof (HfsPrivateFSData));
105
if (!priv_data) goto ho_mdb;
107
memcpy (mdb, buf, sizeof (HfsMasterDirectoryBlock));
109
/* init structures */
110
priv_data->mdb = mdb;
111
priv_data->bad_blocks_loaded = 0;
112
priv_data->bad_blocks_xtent_nb = 0;
113
priv_data->bad_blocks_xtent_list = NULL;
114
priv_data->extent_file =
115
hfs_file_open (fs, PED_CPU_TO_BE32 (HFS_XTENT_ID),
116
mdb->extents_file_rec,
117
PED_CPU_TO_BE32 (mdb->extents_file_size)
118
/ PED_SECTOR_SIZE_DEFAULT);
119
if (!priv_data->extent_file) goto ho_pd;
120
priv_data->catalog_file =
121
hfs_file_open (fs, PED_CPU_TO_BE32 (HFS_CATALOG_ID),
122
mdb->catalog_file_rec,
123
PED_CPU_TO_BE32 (mdb->catalog_file_size)
124
/ PED_SECTOR_SIZE_DEFAULT);
125
if (!priv_data->catalog_file) goto ho_ce;
126
/* Read allocation blocks */
127
if (!ped_geometry_read(geom, priv_data->alloc_map,
128
PED_BE16_TO_CPU (mdb->volume_bitmap_block),
129
( PED_BE16_TO_CPU (mdb->total_blocks)
130
+ PED_SECTOR_SIZE_DEFAULT * 8 - 1 )
131
/ (PED_SECTOR_SIZE_DEFAULT * 8) ) )
134
fs->type = &hfs_type;
135
fs->geom = ped_geometry_duplicate (geom);
136
if (!fs->geom) goto ho_cf;
137
fs->type_specific = (void*) priv_data;
138
fs->checked = ( PED_BE16_TO_CPU (mdb->volume_attributes)
139
>> HFS_UNMOUNTED ) & 1;
143
/*--- clean error handling ---*/
144
ho_cf: hfs_file_close(priv_data->catalog_file);
145
ho_ce: hfs_file_close(priv_data->extent_file);
146
ho_pd: free(priv_data);
153
hfs_close (PedFileSystem *fs)
155
HfsPrivateFSData* priv_data = (HfsPrivateFSData*) fs->type_specific;
157
hfs_file_close (priv_data->extent_file);
158
hfs_file_close (priv_data->catalog_file);
159
if (priv_data->bad_blocks_loaded)
160
hfs_free_bad_blocks_list (priv_data->bad_blocks_xtent_list);
161
free (priv_data->mdb);
163
ped_geometry_destroy (fs->geom);
170
hfs_get_resize_constraint (const PedFileSystem *fs)
172
PedDevice* dev = fs->geom->dev;
173
PedAlignment start_align;
174
PedGeometry start_sector;
175
PedGeometry full_dev;
178
if (!ped_alignment_init (&start_align, fs->geom->start, 0))
180
if (!ped_geometry_init (&start_sector, dev, fs->geom->start, 1))
182
if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
184
/* 2 = last two sectors (alternate MDB and unused sector) */
185
min_size = hfs_get_empty_end(fs) + 2;
186
if (min_size == 2) return NULL;
188
return ped_constraint_new (&start_align, ped_alignment_any,
189
&start_sector, &full_dev, min_size,
194
hfs_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
196
uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
197
unsigned int nblock, nfree;
198
unsigned int block, to_free;
199
HfsPrivateFSData* priv_data;
200
HfsMasterDirectoryBlock* mdb;
202
unsigned int hfs_sect_block;
205
/* check preconditions */
206
PED_ASSERT (fs != NULL);
207
PED_ASSERT (fs->geom != NULL);
208
PED_ASSERT (geom != NULL);
210
PED_ASSERT ((hgee = hfs_get_empty_end(fs)) != 0);
212
if ((hgee = hfs_get_empty_end(fs)) == 0)
216
PED_ASSERT ((hgee = hfs_get_empty_end(fs)) != 0);
218
if (ped_geometry_test_equal(fs->geom, geom))
221
priv_data = (HfsPrivateFSData*) fs->type_specific;
222
mdb = priv_data->mdb;
223
hfs_sect_block = PED_BE32_TO_CPU (mdb->block_size)
224
/ PED_SECTOR_SIZE_DEFAULT;
226
if (fs->geom->start != geom->start
227
|| geom->length > fs->geom->length
228
|| geom->length < hgee + 2) {
229
ped_exception_throw (
230
PED_EXCEPTION_NO_FEATURE,
231
PED_EXCEPTION_CANCEL,
232
_("Sorry, HFS cannot be resized that way yet."));
237
if (!ped_geometry_sync(fs->geom))
240
/* Clear the unmounted bit */
241
mdb->volume_attributes &= PED_CPU_TO_BE16 (~( 1 << HFS_UNMOUNTED ));
242
if (!ped_geometry_read (fs->geom, buf, 2, 1))
244
memcpy (buf, mdb, sizeof (HfsMasterDirectoryBlock));
245
if ( !ped_geometry_write (fs->geom, buf, 2, 1)
246
|| !ped_geometry_sync (fs->geom))
249
ped_timer_reset (timer);
250
ped_timer_set_state_name(timer, _("shrinking"));
251
ped_timer_update(timer, 0.0);
253
to_free = ( fs->geom->length - geom->length
254
+ hfs_sect_block - 1 )
256
block = hfs_find_start_pack (fs, to_free);
257
if (!hfs_pack_free_space_from_block (fs, block, timer, to_free)) {
259
ped_exception_throw (
261
PED_EXCEPTION_CANCEL,
262
_("Data relocation has failed."));
266
/* Calculate new block number and other MDB field */
267
nblock = ( geom->length - (PED_BE16_TO_CPU (mdb->start_block) + 2) )
269
nfree = PED_BE16_TO_CPU (mdb->free_blocks)
270
- ( PED_BE16_TO_CPU (mdb->total_blocks) - nblock );
272
/* Check that all block after future end are really free */
274
block < PED_BE16_TO_CPU (mdb->total_blocks);
276
if (TST_BLOC_OCCUPATION(priv_data->alloc_map,block)) {
278
ped_exception_throw (
280
PED_EXCEPTION_CANCEL,
281
_("Data relocation left some data in the end "
287
/* Mark out of volume blocks as used
288
(broken implementations compatibility) */
289
for ( block = nblock; block < (1 << 16); ++block)
290
SET_BLOC_OCCUPATION(priv_data->alloc_map,block);
292
/* save the allocation map
293
I do not write until start of allocation blocks
294
but only until pre-resize end of bitmap blocks
295
because the specifications do _not_ assert that everything
296
until allocation blocks is boot, mdb and alloc */
297
ped_geometry_write(fs->geom, priv_data->alloc_map,
298
PED_BE16_TO_CPU (priv_data->mdb->volume_bitmap_block),
299
( PED_BE16_TO_CPU (priv_data->mdb->total_blocks)
300
+ PED_SECTOR_SIZE_DEFAULT * 8 - 1)
301
/ (PED_SECTOR_SIZE_DEFAULT * 8));
303
/* Update geometry */
305
/* update in fs structure */
306
if (PED_BE16_TO_CPU (mdb->next_allocation) >= nblock)
307
mdb->next_allocation = PED_CPU_TO_BE16 (0);
308
mdb->total_blocks = PED_CPU_TO_BE16 (nblock);
309
mdb->free_blocks = PED_CPU_TO_BE16 (nfree);
310
/* update parted structure */
311
fs->geom->length = geom->length;
312
fs->geom->end = fs->geom->start + geom->length - 1;
315
/* Set the unmounted bit */
316
mdb->volume_attributes |= PED_CPU_TO_BE16 ( 1 << HFS_UNMOUNTED );
318
/* Effective write */
320
ped_timer_set_state_name(timer,_("writing HFS Master Directory Block"));
322
if (!hfs_update_mdb(fs)) {
323
ped_geometry_sync(geom);
327
if (!ped_geometry_sync(geom))
330
ped_timer_update(timer, 1.0);
335
/* ----- HFS+ ----- */
337
#include "file_plus.h"
338
#include "advfs_plus.h"
339
#include "reloc_plus.h"
343
hfsplus_clobber (PedGeometry* geom)
346
uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
347
HfsMasterDirectoryBlock *mdb;
349
mdb = (HfsMasterDirectoryBlock *) buf;
351
if (!ped_geometry_read (geom, buf, 2, 1))
354
if (PED_BE16_TO_CPU (mdb->signature) == HFS_SIGNATURE) {
356
PedGeometry *embedded;
358
i = PED_BE32_TO_CPU(mdb->block_size) / PED_SECTOR_SIZE_DEFAULT;
359
embedded = ped_geometry_new (
361
(PedSector) geom->start
362
+ PED_BE16_TO_CPU (mdb->start_block)
363
+ (PedSector) PED_BE16_TO_CPU (
364
mdb->old_new.embedded.location.start_block ) * i,
365
(PedSector) PED_BE16_TO_CPU (
366
mdb->old_new.embedded.location.block_count ) * i );
367
if (!embedded) i = 0;
369
i = hfs_clobber (embedded);
370
ped_geometry_destroy (embedded);
374
/* non-embedded or envelop destroy as hfs */
375
return ( hfs_clobber (geom) && i );
379
hfsplus_close (PedFileSystem *fs)
381
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
384
if (priv_data->bad_blocks_loaded)
385
hfsplus_free_bad_blocks_list(priv_data->bad_blocks_xtent_list);
386
free(priv_data->alloc_map);
387
free(priv_data->dirty_alloc_map);
388
hfsplus_file_close (priv_data->allocation_file);
389
hfsplus_file_close (priv_data->attributes_file);
390
hfsplus_file_close (priv_data->catalog_file);
391
hfsplus_file_close (priv_data->extents_file);
392
if (priv_data->free_geom) ped_geometry_destroy (priv_data->plus_geom);
393
if (priv_data->wrapper) hfs_close(priv_data->wrapper);
394
ped_geometry_destroy (fs->geom);
403
hfsplus_open (PedGeometry* geom)
405
uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
407
HfsPVolumeHeader* vh;
408
HfsPPrivateFSData* priv_data;
409
PedGeometry* wrapper_geom;
410
unsigned int map_sectors;
412
if (!hfsc_can_use_geom (geom))
415
fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
417
vh = (HfsPVolumeHeader*) ped_malloc (sizeof (HfsPVolumeHeader));
418
if (!vh) goto hpo_fs;
419
priv_data = (HfsPPrivateFSData*)ped_malloc (sizeof (HfsPPrivateFSData));
420
if (!priv_data) goto hpo_vh;
422
fs->geom = ped_geometry_duplicate (geom);
423
if (!fs->geom) goto hpo_pd;
424
fs->type_specific = (void*) priv_data;
426
if ((wrapper_geom = hfs_and_wrapper_probe (geom))) {
427
HfsPrivateFSData* hfs_priv_data;
428
PedSector abs_sect, length;
431
ped_geometry_destroy (wrapper_geom);
432
priv_data->wrapper = hfs_open(geom);
433
if (!priv_data->wrapper) goto hpo_gm;
434
hfs_priv_data = (HfsPrivateFSData*)
435
priv_data->wrapper->type_specific;
436
bs = PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size)
437
/ PED_SECTOR_SIZE_DEFAULT;
438
abs_sect = (PedSector) geom->start
439
+ (PedSector) PED_BE16_TO_CPU (
440
hfs_priv_data->mdb->start_block)
441
+ (PedSector) PED_BE16_TO_CPU (
442
hfs_priv_data->mdb->old_new
443
.embedded.location.start_block )
445
length = (PedSector) PED_BE16_TO_CPU (
446
hfs_priv_data->mdb->old_new
447
.embedded.location.block_count)
449
priv_data->plus_geom = ped_geometry_new (geom->dev, abs_sect,
451
if (!priv_data->plus_geom) goto hpo_wr;
452
priv_data->free_geom = 1;
454
priv_data->wrapper = NULL;
455
priv_data->plus_geom = fs->geom;
456
priv_data->free_geom = 0;
459
if (!ped_geometry_read (priv_data->plus_geom, buf, 2, 1)) goto hpo_pg;
460
memcpy (vh, buf, sizeof (HfsPVolumeHeader));
463
if (vh->signature != PED_CPU_TO_BE16(HFSP_SIGNATURE)
464
&& vh->signature != PED_CPU_TO_BE16(HFSX_SIGNATURE)) {
465
ped_exception_throw (
467
PED_EXCEPTION_CANCEL,
468
_("No valid HFS[+X] signature has been found while "
473
if (vh->signature == PED_CPU_TO_BE16(HFSP_SIGNATURE)
474
&& vh->version != PED_CPU_TO_BE16(HFSP_VERSION)) {
475
if (ped_exception_throw (
476
PED_EXCEPTION_NO_FEATURE,
477
PED_EXCEPTION_IGNORE_CANCEL,
478
_("Version %d of HFS+ isn't supported."),
479
PED_BE16_TO_CPU(vh->version))
480
!= PED_EXCEPTION_IGNORE)
484
if (vh->signature == PED_CPU_TO_BE16(HFSX_SIGNATURE)
485
&& vh->version != PED_CPU_TO_BE16(HFSX_VERSION)) {
486
if (ped_exception_throw (
487
PED_EXCEPTION_NO_FEATURE,
488
PED_EXCEPTION_IGNORE_CANCEL,
489
_("Version %d of HFSX isn't supported."),
490
PED_BE16_TO_CPU(vh->version))
491
!= PED_EXCEPTION_IGNORE)
495
priv_data->jib_start_block = 0;
496
priv_data->jl_start_block = 0;
497
if (vh->attributes & PED_CPU_TO_BE32(1<<HFSP_JOURNALED)) {
498
if (!hfsj_replay_journal(fs))
502
priv_data->bad_blocks_loaded = 0;
503
priv_data->bad_blocks_xtent_nb = 0;
504
priv_data->bad_blocks_xtent_list = NULL;
505
priv_data->extents_file =
506
hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFS_XTENT_ID),
507
vh->extents_file.extents,
509
vh->extents_file.logical_size )
510
/ PED_SECTOR_SIZE_DEFAULT);
511
if (!priv_data->extents_file) goto hpo_pg;
512
priv_data->catalog_file =
513
hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFS_CATALOG_ID),
514
vh->catalog_file.extents,
516
vh->catalog_file.logical_size )
517
/ PED_SECTOR_SIZE_DEFAULT);
518
if (!priv_data->catalog_file) goto hpo_ce;
519
priv_data->attributes_file =
520
hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFSP_ATTRIB_ID),
521
vh->attributes_file.extents,
523
vh->attributes_file.logical_size)
524
/ PED_SECTOR_SIZE_DEFAULT);
525
if (!priv_data->attributes_file) goto hpo_cc;
527
map_sectors = ( PED_BE32_TO_CPU (vh->total_blocks)
528
+ PED_SECTOR_SIZE_DEFAULT * 8 - 1 )
529
/ (PED_SECTOR_SIZE_DEFAULT * 8);
530
priv_data->dirty_alloc_map = (uint8_t*)
531
ped_malloc ((map_sectors + 7) / 8);
532
if (!priv_data->dirty_alloc_map) goto hpo_cl;
533
memset(priv_data->dirty_alloc_map, 0, (map_sectors + 7) / 8);
534
priv_data->alloc_map = (uint8_t*)
535
ped_malloc (map_sectors * PED_SECTOR_SIZE_DEFAULT);
536
if (!priv_data->alloc_map) goto hpo_dm;
538
priv_data->allocation_file =
539
hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFSP_ALLOC_ID),
540
vh->allocation_file.extents,
542
vh->allocation_file.logical_size)
543
/ PED_SECTOR_SIZE_DEFAULT);
544
if (!priv_data->allocation_file) goto hpo_am;
545
if (!hfsplus_file_read (priv_data->allocation_file,
546
priv_data->alloc_map, 0, map_sectors)) {
551
fs->type = &hfsplus_type;
552
fs->checked = ((PED_BE32_TO_CPU (vh->attributes) >> HFS_UNMOUNTED) & 1)
553
&& !((PED_BE32_TO_CPU (vh->attributes) >> HFSP_INCONSISTENT) & 1);
557
/*--- clean error handling ---*/
558
hpo_am: free(priv_data->alloc_map);
559
hpo_dm: free(priv_data->dirty_alloc_map);
560
hpo_cl: hfsplus_file_close (priv_data->attributes_file);
561
hpo_cc: hfsplus_file_close (priv_data->catalog_file);
562
hpo_ce: hfsplus_file_close (priv_data->extents_file);
563
hpo_pg: if (priv_data->free_geom) ped_geometry_destroy (priv_data->plus_geom);
564
hpo_wr: if (priv_data->wrapper) hfs_close(priv_data->wrapper);
565
hpo_gm: ped_geometry_destroy (fs->geom);
566
hpo_pd: free(priv_data);
573
hfsplus_get_resize_constraint (const PedFileSystem *fs)
575
PedDevice* dev = fs->geom->dev;
576
PedAlignment start_align;
577
PedGeometry start_sector;
578
PedGeometry full_dev;
581
if (!ped_alignment_init (&start_align, fs->geom->start, 0))
583
if (!ped_geometry_init (&start_sector, dev, fs->geom->start, 1))
585
if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
588
min_size = hfsplus_get_min_size (fs);
589
if (!min_size) return NULL;
591
return ped_constraint_new (&start_align, ped_alignment_any,
592
&start_sector, &full_dev, min_size,
597
hfsplus_volume_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
599
uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
600
unsigned int nblock, nfree, mblock;
601
unsigned int block, to_free, old_blocks;
602
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
604
HfsPVolumeHeader* vh = priv_data->vh;
606
unsigned int hfsp_sect_block =
607
( PED_BE32_TO_CPU (vh->block_size)
608
/ PED_SECTOR_SIZE_DEFAULT );
609
unsigned int map_sectors;
611
old_blocks = PED_BE32_TO_CPU (vh->total_blocks);
614
if (!ped_geometry_sync(priv_data->plus_geom))
617
/* Clear the unmounted bit */
618
/* and set the implementation code (Apple Creator Code) */
619
vh->attributes &= PED_CPU_TO_BE32 (~( 1 << HFS_UNMOUNTED ));
620
vh->last_mounted_version = PED_CPU_TO_BE32(HFSP_IMPL_Shnk);
621
if (!ped_geometry_read (priv_data->plus_geom, buf, 2, 1))
623
memcpy (buf, vh, sizeof (HfsPVolumeHeader));
624
if ( !ped_geometry_write (priv_data->plus_geom, buf, 2, 1)
625
|| !ped_geometry_sync (priv_data->plus_geom))
628
ped_timer_reset (timer);
629
ped_timer_set_state_name(timer, _("shrinking"));
630
ped_timer_update(timer, 0.0);
632
to_free = ( priv_data->plus_geom->length
633
- geom->length + hfsp_sect_block
634
- 1 ) / hfsp_sect_block;
635
block = hfsplus_find_start_pack (fs, to_free);
636
if (!hfsplus_pack_free_space_from_block (fs, block, timer, to_free)) {
638
ped_exception_throw (
640
PED_EXCEPTION_CANCEL,
641
_("Data relocation has failed."));
645
/* Calculate new block number and other VH field */
646
/* nblock must be rounded _down_ */
647
nblock = geom->length / hfsp_sect_block;
648
nfree = PED_BE32_TO_CPU (vh->free_blocks)
649
- (old_blocks - nblock);
650
/* free block readjustement is only needed when incorrect nblock
651
was used by my previous implementation, so detect the case */
652
if (priv_data->plus_geom->length < old_blocks
653
* ( PED_BE32_TO_CPU (vh->block_size)
654
/ PED_SECTOR_SIZE_DEFAULT) ) {
655
if (priv_data->plus_geom->length % hfsp_sect_block == 1)
659
/* Check that all block after future end are really free */
660
mblock = ( priv_data->plus_geom->length - 2 )
662
if (mblock > old_blocks - 1)
663
mblock = old_blocks - 1;
664
for ( block = nblock;
667
if (TST_BLOC_OCCUPATION(priv_data->alloc_map,block)) {
669
ped_exception_throw (
671
PED_EXCEPTION_CANCEL,
672
_("Data relocation left some data at the end "
678
/* Mark out of volume blocks as used */
679
map_sectors = ( ( old_blocks + PED_SECTOR_SIZE_DEFAULT * 8 - 1 )
680
/ (PED_SECTOR_SIZE_DEFAULT * 8) )
681
* (PED_SECTOR_SIZE_DEFAULT * 8);
682
for ( block = nblock; block < map_sectors; ++block)
683
SET_BLOC_OCCUPATION(priv_data->alloc_map, block);
685
/* Update geometry */
687
/* update in fs structure */
688
if (PED_BE32_TO_CPU (vh->next_allocation) >= nblock)
689
vh->next_allocation = PED_CPU_TO_BE32 (0);
690
vh->total_blocks = PED_CPU_TO_BE32 (nblock);
691
vh->free_blocks = PED_CPU_TO_BE32 (nfree);
692
/* update parted structure */
693
priv_data->plus_geom->length = geom->length;
694
priv_data->plus_geom->end = priv_data->plus_geom->start
698
/* Effective write */
700
/* lasts two sectors are allocated by the alternate VH
701
and a reserved sector, and last block is always reserved */
702
block = (priv_data->plus_geom->length - 1) / hfsp_sect_block;
703
if (block < PED_BE32_TO_CPU (vh->total_blocks))
704
SET_BLOC_OCCUPATION(priv_data->alloc_map, block);
705
block = (priv_data->plus_geom->length - 2) / hfsp_sect_block;
706
if (block < PED_BE32_TO_CPU (vh->total_blocks))
707
SET_BLOC_OCCUPATION(priv_data->alloc_map, block);
708
SET_BLOC_OCCUPATION(priv_data->alloc_map,
709
PED_BE32_TO_CPU (vh->total_blocks) - 1);
711
/* Write the _old_ area to set out of volume blocks as used */
712
map_sectors = ( old_blocks + PED_SECTOR_SIZE_DEFAULT * 8 - 1 )
713
/ (PED_SECTOR_SIZE_DEFAULT * 8);
714
if (!hfsplus_file_write (priv_data->allocation_file,
715
priv_data->alloc_map, 0, map_sectors)) {
717
ped_exception_throw (
719
PED_EXCEPTION_CANCEL,
720
_("Error while writing the allocation file."));
722
/* Write remaining part of allocation bitmap */
723
/* This is necessary to handle pre patch-11 and third party */
724
/* implementations */
725
memset(buf, 0xFF, PED_SECTOR_SIZE_DEFAULT);
726
for (block = map_sectors;
727
block < priv_data->allocation_file->sect_nb;
729
if (!hfsplus_file_write_sector (
730
priv_data->allocation_file,
732
ped_exception_throw (
733
PED_EXCEPTION_WARNING,
734
PED_EXCEPTION_IGNORE,
735
_("Error while writing the "
736
"compatibility part of the "
737
"allocation file."));
742
ped_geometry_sync (priv_data->plus_geom);
745
/* Set the unmounted bit and clear the inconsistent bit */
746
vh->attributes |= PED_CPU_TO_BE32 ( 1 << HFS_UNMOUNTED );
747
vh->attributes &= ~ PED_CPU_TO_BE32 ( 1 << HFSP_INCONSISTENT );
750
ped_timer_set_state_name(timer, _("writing HFS+ Volume Header"));
751
if (!hfsplus_update_vh(fs)) {
752
ped_geometry_sync(priv_data->plus_geom);
756
if (!ped_geometry_sync(priv_data->plus_geom))
759
ped_timer_update(timer, 1.0);
764
/* Update the HFS wrapper mdb and bad blocks file to reflect
765
the new geometry of the embedded HFS+ volume */
767
hfsplus_wrapper_update (PedFileSystem* fs)
769
uint8_t node[PED_SECTOR_SIZE_DEFAULT];
770
HfsCPrivateLeafRec ref;
772
HfsNodeDescriptor* node_desc = (HfsNodeDescriptor*) node;
773
HfsExtentKey* ret_key;
774
HfsExtDescriptor* ret_data;
776
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
778
HfsPrivateFSData* hfs_priv_data = (HfsPrivateFSData*)
779
priv_data->wrapper->type_specific;
780
unsigned int hfs_sect_block =
781
PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size)
782
/ PED_SECTOR_SIZE_DEFAULT ;
783
PedSector hfsplus_sect = (PedSector)
784
PED_BE32_TO_CPU (priv_data->vh->total_blocks)
785
* ( PED_BE32_TO_CPU (priv_data->vh->block_size)
786
/ PED_SECTOR_SIZE_DEFAULT );
787
unsigned int hfs_blocks_embedded =
788
(hfsplus_sect + hfs_sect_block - 1)
790
unsigned int hfs_blocks_embedded_old;
792
/* update HFS wrapper MDB */
793
hfs_blocks_embedded_old = PED_BE16_TO_CPU (
794
hfs_priv_data->mdb->old_new
795
.embedded.location.block_count );
796
hfs_priv_data->mdb->old_new.embedded.location.block_count =
797
PED_CPU_TO_BE16 (hfs_blocks_embedded);
798
/* maybe macOS will boot with this */
799
/* update : yes it does \o/ :) */
800
hfs_priv_data->mdb->free_blocks =
801
PED_CPU_TO_BE16 ( PED_BE16_TO_CPU (hfs_priv_data->mdb->free_blocks)
802
+ hfs_blocks_embedded_old
803
- hfs_blocks_embedded );
805
if (!hfs_update_mdb(priv_data->wrapper))
808
/* force reload bad block list */
809
if (hfs_priv_data->bad_blocks_loaded) {
810
hfs_free_bad_blocks_list (hfs_priv_data->bad_blocks_xtent_list);
811
hfs_priv_data->bad_blocks_xtent_list = NULL;
812
hfs_priv_data->bad_blocks_xtent_nb = 0;
813
hfs_priv_data->bad_blocks_loaded = 0;
816
/* clean HFS wrapper allocation map */
817
for (i = PED_BE16_TO_CPU (
818
hfs_priv_data->mdb->old_new.embedded
819
.location.start_block )
820
+ hfs_blocks_embedded;
821
i < PED_BE16_TO_CPU (
822
hfs_priv_data->mdb->old_new.embedded
823
.location.start_block )
824
+ hfs_blocks_embedded_old;
826
CLR_BLOC_OCCUPATION(hfs_priv_data->alloc_map, i);
829
if (!ped_geometry_write (fs->geom, hfs_priv_data->alloc_map,
831
hfs_priv_data->mdb->volume_bitmap_block ),
833
hfs_priv_data->mdb->total_blocks )
834
+ PED_SECTOR_SIZE_DEFAULT * 8 - 1 )
835
/ (PED_SECTOR_SIZE_DEFAULT * 8)))
837
if (!ped_geometry_sync (fs->geom))
840
/* search and update the bad blocks file */
841
key.key_length = sizeof(key) - 1;
842
key.type = HFS_DATA_FORK;
843
key.file_ID = PED_CPU_TO_BE32 (HFS_BAD_BLOCK_ID);
845
if (!hfs_btree_search (hfs_priv_data->extent_file,
846
(HfsPrivateGenericKey*) &key, NULL, 0, &ref)) {
847
ped_exception_throw (
849
PED_EXCEPTION_CANCEL,
850
_("An error occurred while looking for the mandatory "
851
"bad blocks file."));
854
if (!hfs_file_read_sector (hfs_priv_data->extent_file, node,
857
ret_key = (HfsExtentKey*) (node + ref.record_pos);
858
ret_data = (HfsExtDescriptor*) ( node + ref.record_pos
859
+ sizeof (HfsExtentKey) );
861
while (ret_key->type == key.type && ret_key->file_ID == key.file_ID) {
862
for (i = 0; i < HFS_EXT_NB; i++) {
863
if ( ret_data[i].start_block
864
== hfs_priv_data->mdb->old_new
865
.embedded.location.start_block) {
866
ret_data[i].block_count =
867
hfs_priv_data->mdb->old_new
868
.embedded.location.block_count;
869
/* found ! : update */
870
if (!hfs_file_write_sector (
871
hfs_priv_data->extent_file,
872
node, ref.node_number)
873
|| !ped_geometry_sync(fs->geom))
879
if (ref.record_number < PED_BE16_TO_CPU (node_desc->rec_nb)) {
882
ref.node_number = PED_BE32_TO_CPU (node_desc->next);
884
|| !hfs_file_read_sector(hfs_priv_data->extent_file,
885
node, ref.node_number))
887
ref.record_number = 1;
891
PED_BE16_TO_CPU (*((uint16_t *)
892
(node + (PED_SECTOR_SIZE_DEFAULT
893
- 2*ref.record_number))));
894
ret_key = (HfsExtentKey*) (node + ref.record_pos);
895
ret_data = (HfsExtDescriptor*) ( node + ref.record_pos
896
+ sizeof (HfsExtentKey) );
900
/* not found : not a valid hfs+ wrapper : failure */
901
ped_exception_throw (
903
PED_EXCEPTION_CANCEL,
904
_("It seems there is an error in the HFS wrapper: the bad "
905
"blocks file doesn't contain the embedded HFS+ volume."));
910
hfsplus_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
912
HfsPPrivateFSData* priv_data;
913
PedTimer* timer_plus;
914
PedGeometry* embedded_geom;
917
/* check preconditions */
918
PED_ASSERT (fs != NULL);
919
PED_ASSERT (fs->geom != NULL);
920
PED_ASSERT (geom != NULL);
921
PED_ASSERT (fs->geom->dev == geom->dev);
923
PED_ASSERT ((hgms = hfsplus_get_min_size (fs)) != 0);
925
if ((hgms = hfsplus_get_min_size (fs)) == 0)
929
if (ped_geometry_test_equal(fs->geom, geom))
932
priv_data = (HfsPPrivateFSData*) fs->type_specific;
934
if (fs->geom->start != geom->start
935
|| geom->length > fs->geom->length
936
|| geom->length < hgms) {
937
ped_exception_throw (
938
PED_EXCEPTION_NO_FEATURE,
939
PED_EXCEPTION_CANCEL,
940
_("Sorry, HFS+ cannot be resized that way yet."));
944
if (priv_data->wrapper) {
946
HfsPrivateFSData* hfs_priv_data = (HfsPrivateFSData*)
947
priv_data->wrapper->type_specific;
948
unsigned int hfs_sect_block =
949
PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size)
950
/ PED_SECTOR_SIZE_DEFAULT;
952
/* There is a wrapper so we must calculate the new geometry
953
of the embedded HFS+ volume */
954
red = ( (fs->geom->length - geom->length + hfs_sect_block - 1)
955
/ hfs_sect_block ) * hfs_sect_block;
956
/* Can't we shrink the hfs+ volume by the desired size ? */
957
hgee = hfsplus_get_empty_end (fs);
959
if (red > priv_data->plus_geom->length - hgee) {
960
/* No, shrink hfs+ by the greatest possible value */
961
hgee = ((hgee + hfs_sect_block - 1) / hfs_sect_block)
963
red = priv_data->plus_geom->length - hgee;
965
embedded_geom = ped_geometry_new (geom->dev,
966
priv_data->plus_geom->start,
967
priv_data->plus_geom->length
970
/* There is a wrapper so the resize process is a two stages
971
process (embedded resizing then wrapper resizing) :
972
we create a sub timer */
973
ped_timer_reset (timer);
974
ped_timer_set_state_name (timer,
975
_("shrinking embedded HFS+ volume"));
976
ped_timer_update(timer, 0.0);
977
timer_plus = ped_timer_new_nested (timer, 0.98);
979
/* No wrapper : the desired geometry is the desired
980
HFS+ volume geometry */
981
embedded_geom = geom;
985
/* Resize the HFS+ volume */
986
if (!hfsplus_volume_resize (fs, embedded_geom, timer_plus)) {
987
if (timer_plus != timer) ped_timer_destroy_nested (timer_plus);
988
ped_exception_throw (
990
PED_EXCEPTION_CANCEL,
991
_("Resizing the HFS+ volume has failed."));
995
if (priv_data->wrapper) {
996
ped_geometry_destroy (embedded_geom);
997
ped_timer_destroy_nested (timer_plus);
998
ped_timer_set_state_name(timer, _("shrinking HFS wrapper"));
999
timer_plus = ped_timer_new_nested (timer, 0.02);
1000
/* There's a wrapper : second stage = resizing it */
1001
if (!hfsplus_wrapper_update (fs)
1002
|| !hfs_resize (priv_data->wrapper, geom, timer_plus)) {
1003
ped_timer_destroy_nested (timer_plus);
1004
ped_exception_throw (
1005
PED_EXCEPTION_ERROR,
1006
PED_EXCEPTION_CANCEL,
1007
_("Updating the HFS wrapper has failed."));
1010
ped_timer_destroy_nested (timer_plus);
1012
ped_timer_update(timer, 1.0);
1017
#ifdef HFS_EXTRACT_FS
1018
/* The following is for debugging purpose only, NOT for packaging */
1022
uint8_t* extract_buffer = NULL;
1025
hfs_extract_file(const char* filename, HfsPrivateFile* hfs_file)
1030
fout = fopen(filename, "w");
1031
if (!fout) return 0;
1033
for (sect = 0; sect < hfs_file->sect_nb; ++sect) {
1034
if (!hfs_file_read_sector(hfs_file, extract_buffer, sect))
1036
if (!fwrite(extract_buffer, PED_SECTOR_SIZE_DEFAULT, 1, fout))
1040
return (fclose(fout) == 0 ? 1 : 0);
1048
hfs_extract_bitmap(const char* filename, PedFileSystem* fs)
1050
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
1052
HfsMasterDirectoryBlock* mdb = priv_data->mdb;
1057
fout = fopen(filename, "w");
1058
if (!fout) return 0;
1060
for (sect = PED_BE16_TO_CPU(mdb->volume_bitmap_block);
1061
sect < PED_BE16_TO_CPU(mdb->start_block);
1063
uint16_t st_block = PED_BE16_TO_CPU(mdb->start_block);
1064
count = (st_block-sect) < BLOCK_MAX_BUFF ?
1065
(st_block-sect) : BLOCK_MAX_BUFF;
1066
if (!ped_geometry_read(fs->geom, extract_buffer, sect, count))
1068
if (!fwrite (extract_buffer, count * PED_SECTOR_SIZE_DEFAULT,
1073
return (fclose(fout) == 0 ? 1 : 0);
1081
hfs_extract_mdb (const char* filename, PedFileSystem* fs)
1085
fout = fopen(filename, "w");
1086
if (!fout) return 0;
1088
if (!ped_geometry_read(fs->geom, extract_buffer, 2, 1))
1090
if (!fwrite(extract_buffer, PED_SECTOR_SIZE_DEFAULT, 1, fout))
1093
return (fclose(fout) == 0 ? 1 : 0);
1101
hfs_extract (PedFileSystem* fs, PedTimer* timer)
1103
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
1106
ped_exception_throw (
1107
PED_EXCEPTION_INFORMATION,
1109
_("This is not a real %s check. This is going to extract "
1110
"special low level files for debugging purposes."),
1113
extract_buffer = ped_malloc(BLOCK_MAX_BUFF * PED_SECTOR_SIZE_DEFAULT);
1114
if (!extract_buffer) return 0;
1116
hfs_extract_mdb(HFS_MDB_FILENAME, fs);
1117
hfs_extract_file(HFS_CATALOG_FILENAME, priv_data->catalog_file);
1118
hfs_extract_file(HFS_EXTENTS_FILENAME, priv_data->extent_file);
1119
hfs_extract_bitmap(HFS_BITMAP_FILENAME, fs);
1121
free(extract_buffer); extract_buffer = NULL;
1122
return 0; /* nothing has been fixed by us ! */
1126
hfsplus_extract_file(const char* filename, HfsPPrivateFile* hfsp_file)
1129
unsigned int cp_sect;
1132
fout = fopen(filename, "w");
1133
if (!fout) return 0;
1135
for (rem_sect = hfsp_file->sect_nb; rem_sect; rem_sect -= cp_sect) {
1136
cp_sect = rem_sect < BLOCK_MAX_BUFF ? rem_sect : BLOCK_MAX_BUFF;
1137
if (!hfsplus_file_read(hfsp_file, extract_buffer,
1138
hfsp_file->sect_nb - rem_sect, cp_sect))
1140
if (!fwrite (extract_buffer, cp_sect * PED_SECTOR_SIZE_DEFAULT,
1145
return (fclose(fout) == 0 ? 1 : 0);
1153
hfsplus_extract_vh (const char* filename, PedFileSystem* fs)
1155
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
1158
PedGeometry* geom = priv_data->plus_geom;
1161
fout = fopen(filename, "w");
1162
if (!fout) return 0;
1164
if (!ped_geometry_read(geom, extract_buffer, 2, 1))
1166
if (!fwrite(extract_buffer, PED_SECTOR_SIZE_DEFAULT, 1, fout))
1169
return (fclose(fout) == 0 ? 1 : 0);
1176
/* TODO : use the timer to report what is happening */
1177
/* TODO : use exceptions to report errors */
1179
hfsplus_extract (PedFileSystem* fs, PedTimer* timer)
1181
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
1183
HfsPVolumeHeader* vh = priv_data->vh;
1184
HfsPPrivateFile* startup_file;
1186
if (priv_data->wrapper) {
1187
/* TODO : create nested timer */
1188
hfs_extract (priv_data->wrapper, timer);
1191
ped_exception_throw (
1192
PED_EXCEPTION_INFORMATION,
1194
_("This is not a real %s check. This is going to extract "
1195
"special low level files for debugging purposes."),
1198
extract_buffer = ped_malloc(BLOCK_MAX_BUFF * PED_SECTOR_SIZE_DEFAULT);
1199
if (!extract_buffer) return 0;
1201
hfsplus_extract_vh(HFSP_VH_FILENAME, fs);
1202
hfsplus_extract_file(HFSP_CATALOG_FILENAME, priv_data->catalog_file);
1203
hfsplus_extract_file(HFSP_EXTENTS_FILENAME, priv_data->extents_file);
1204
hfsplus_extract_file(HFSP_ATTRIB_FILENAME, priv_data->attributes_file);
1205
hfsplus_extract_file(HFSP_BITMAP_FILENAME, priv_data->allocation_file);
1207
startup_file = hfsplus_file_open(fs, PED_CPU_TO_BE32(HFSP_STARTUP_ID),
1208
vh->startup_file.extents,
1210
vh->startup_file.logical_size)
1211
/ PED_SECTOR_SIZE_DEFAULT);
1213
hfsplus_extract_file(HFSP_STARTUP_FILENAME, startup_file);
1214
hfsplus_file_close(startup_file); startup_file = NULL;
1217
free(extract_buffer); extract_buffer = NULL;
1218
return 0; /* nothing has been fixed by us ! */
1220
#endif /* HFS_EXTRACT_FS */
1222
#endif /* !DISCOVER_ONLY */
1225
static PedFileSystemOps hfs_ops = {
1227
#ifndef DISCOVER_ONLY
1228
clobber: hfs_clobber,
1232
#ifndef HFS_EXTRACT_FS
1239
get_create_constraint: NULL,
1240
get_resize_constraint: hfs_get_resize_constraint,
1241
get_copy_constraint: NULL,
1242
#else /* DISCOVER_ONLY */
1250
get_create_constraint: NULL,
1251
get_resize_constraint: NULL,
1252
get_copy_constraint: NULL,
1253
#endif /* DISCOVER_ONLY */
1256
static PedFileSystemOps hfsplus_ops = {
1257
probe: hfsplus_probe,
1258
#ifndef DISCOVER_ONLY
1259
clobber: hfsplus_clobber,
1262
close: hfsplus_close,
1263
#ifndef HFS_EXTRACT_FS
1266
check: hfsplus_extract,
1269
resize: hfsplus_resize,
1270
get_create_constraint: NULL,
1271
get_resize_constraint: hfsplus_get_resize_constraint,
1272
get_copy_constraint: NULL,
1273
#else /* DISCOVER_ONLY */
1281
get_create_constraint: NULL,
1282
get_resize_constraint: NULL,
1283
get_copy_constraint: NULL,
1284
#endif /* DISCOVER_ONLY */
1287
static PedFileSystemOps hfsx_ops = {
1289
#ifndef DISCOVER_ONLY
1290
clobber: hfs_clobber, /* NOT hfsplus_clobber !
1291
HFSX can't be embedded */
1294
close: hfsplus_close,
1295
#ifndef HFS_EXTRACT_FS
1298
check: hfsplus_extract,
1301
resize: hfsplus_resize,
1302
get_create_constraint: NULL,
1303
get_resize_constraint: hfsplus_get_resize_constraint,
1304
get_copy_constraint: NULL,
1305
#else /* DISCOVER_ONLY */
1313
get_create_constraint: NULL,
1314
get_resize_constraint: NULL,
1315
get_copy_constraint: NULL,
1316
#endif /* DISCOVER_ONLY */
1320
static PedFileSystemType hfs_type = {
1324
block_sizes: HFS_BLOCK_SIZES
1327
static PedFileSystemType hfsplus_type = {
1331
block_sizes: HFSP_BLOCK_SIZES
1334
static PedFileSystemType hfsx_type = {
1338
block_sizes: HFSX_BLOCK_SIZES
1342
ped_file_system_hfs_init ()
1344
ped_file_system_type_register (&hfs_type);
1345
ped_file_system_type_register (&hfsplus_type);
1346
ped_file_system_type_register (&hfsx_type);
1350
ped_file_system_hfs_done ()
1352
ped_file_system_type_unregister (&hfs_type);
1353
ped_file_system_type_unregister (&hfsplus_type);
1354
ped_file_system_type_unregister (&hfsx_type);