~ubuntu-branches/ubuntu/vivid/parted/vivid

« back to all changes in this revision

Viewing changes to libparted/fs/r/hfs/hfs.c

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2014-07-21 10:23:16 UTC
  • mfrom: (7.2.32 sid)
  • Revision ID: package-import@ubuntu.com-20140721102316-jsyv3yzmbo8vlde5
Tags: 3.1-3
Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    libparted - a library for manipulating disk partitions
 
3
    Copyright (C) 2000, 2003-2005, 2007, 2009-2012 Free Software Foundation,
 
4
    Inc.
 
5
 
 
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.
 
10
 
 
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.
 
15
 
 
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/>.
 
18
*/
 
19
 
 
20
/*
 
21
   Author : Guillaume Knispel <k_guillaume@libertysurf.fr>
 
22
   Report bug to <bug-parted@gnu.org>
 
23
*/
 
24
 
 
25
#include <config.h>
 
26
 
 
27
#include <parted/parted.h>
 
28
#include <parted/endian.h>
 
29
#include <parted/debug.h>
 
30
#include <stdint.h>
 
31
 
 
32
#if ENABLE_NLS
 
33
#  include <libintl.h>
 
34
#  define _(String) dgettext (PACKAGE, String)
 
35
#else
 
36
#  define _(String) (String)
 
37
#endif /* ENABLE_NLS */
 
38
 
 
39
#include "hfs.h"
 
40
#include "probe.h"
 
41
 
 
42
uint8_t* hfs_block = NULL;
 
43
uint8_t* hfsp_block = NULL;
 
44
unsigned hfs_block_count;
 
45
unsigned hfsp_block_count;
 
46
 
 
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})
 
50
 
 
51
#ifndef DISCOVER_ONLY
 
52
#include "file.h"
 
53
#include "reloc.h"
 
54
#include "advfs.h"
 
55
 
 
56
static PedFileSystemType hfs_type;
 
57
static PedFileSystemType hfsplus_type;
 
58
 
 
59
 
 
60
/* ----- HFS ----- */
 
61
 
 
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 */
 
66
static int
 
67
hfs_clobber (PedGeometry* geom)
 
68
{
 
69
        uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
 
70
 
 
71
        memset (buf, 0, PED_SECTOR_SIZE_DEFAULT);
 
72
 
 
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));
 
80
}
 
81
 
 
82
PedFileSystem *
 
83
hfs_open (PedGeometry* geom)
 
84
{
 
85
        uint8_t                 buf[PED_SECTOR_SIZE_DEFAULT];
 
86
        PedFileSystem*          fs;
 
87
        HfsMasterDirectoryBlock* mdb;
 
88
        HfsPrivateFSData*       priv_data;
 
89
 
 
90
        if (!hfsc_can_use_geom (geom))
 
91
                return NULL;
 
92
 
 
93
        /* Read MDB */
 
94
        if (!ped_geometry_read (geom, buf, 2, 1))
 
95
                return NULL;
 
96
 
 
97
        /* Allocate memory */
 
98
        fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
 
99
        if (!fs) goto ho;
 
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;
 
106
 
 
107
        memcpy (mdb, buf, sizeof (HfsMasterDirectoryBlock));
 
108
 
 
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) ) )
 
132
                goto ho_cf;
 
133
 
 
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;
 
140
 
 
141
        return fs;
 
142
 
 
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);
 
147
ho_mdb: free(mdb);
 
148
ho_fs:  free(fs);
 
149
ho:     return NULL;
 
150
}
 
151
 
 
152
int
 
153
hfs_close (PedFileSystem *fs)
 
154
{
 
155
        HfsPrivateFSData* priv_data = (HfsPrivateFSData*) fs->type_specific;
 
156
 
 
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);
 
162
        free (priv_data);
 
163
        ped_geometry_destroy (fs->geom);
 
164
        free (fs);
 
165
 
 
166
        return 1;
 
167
}
 
168
 
 
169
PedConstraint *
 
170
hfs_get_resize_constraint (const PedFileSystem *fs)
 
171
{
 
172
        PedDevice*      dev = fs->geom->dev;
 
173
        PedAlignment    start_align;
 
174
        PedGeometry     start_sector;
 
175
        PedGeometry     full_dev;
 
176
        PedSector       min_size;
 
177
 
 
178
        if (!ped_alignment_init (&start_align, fs->geom->start, 0))
 
179
                return NULL;
 
180
        if (!ped_geometry_init (&start_sector, dev, fs->geom->start, 1))
 
181
                return NULL;
 
182
        if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
 
183
                return NULL;
 
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;
 
187
 
 
188
        return ped_constraint_new (&start_align, ped_alignment_any,
 
189
                                   &start_sector, &full_dev, min_size,
 
190
                                   fs->geom->length);
 
191
}
 
192
 
 
193
int
 
194
hfs_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
 
195
{
 
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;
 
201
        int                     resize = 1;
 
202
        unsigned int            hfs_sect_block;
 
203
        PedSector               hgee;
 
204
 
 
205
        /* check preconditions */
 
206
        PED_ASSERT (fs != NULL);
 
207
        PED_ASSERT (fs->geom != NULL);
 
208
        PED_ASSERT (geom != NULL);
 
209
#ifdef DEBUG
 
210
        PED_ASSERT ((hgee = hfs_get_empty_end(fs)) != 0);
 
211
#else
 
212
        if ((hgee = hfs_get_empty_end(fs)) == 0)
 
213
                return 0;
 
214
#endif
 
215
 
 
216
        PED_ASSERT ((hgee = hfs_get_empty_end(fs)) != 0);
 
217
 
 
218
        if (ped_geometry_test_equal(fs->geom, geom))
 
219
                return 1;
 
220
 
 
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;
 
225
 
 
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."));
 
233
                return 0;
 
234
        }
 
235
 
 
236
        /* Flush caches */
 
237
        if (!ped_geometry_sync(fs->geom))
 
238
                return 0;
 
239
 
 
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))
 
243
                return 0;
 
244
        memcpy (buf, mdb, sizeof (HfsMasterDirectoryBlock));
 
245
        if (   !ped_geometry_write (fs->geom, buf, 2, 1)
 
246
            || !ped_geometry_sync  (fs->geom))
 
247
                return 0;
 
248
 
 
249
        ped_timer_reset (timer);
 
250
        ped_timer_set_state_name(timer, _("shrinking"));
 
251
        ped_timer_update(timer, 0.0);
 
252
        /* relocate data */
 
253
        to_free = ( fs->geom->length - geom->length
 
254
                    + hfs_sect_block - 1 )
 
255
                  / hfs_sect_block ;
 
256
        block = hfs_find_start_pack (fs, to_free);
 
257
        if (!hfs_pack_free_space_from_block (fs, block, timer, to_free)) {
 
258
                resize = 0;
 
259
                ped_exception_throw (
 
260
                        PED_EXCEPTION_ERROR,
 
261
                        PED_EXCEPTION_CANCEL,
 
262
                        _("Data relocation has failed."));
 
263
                goto write_MDB;
 
264
        }
 
265
 
 
266
        /* Calculate new block number and other MDB field */
 
267
        nblock = ( geom->length - (PED_BE16_TO_CPU (mdb->start_block) + 2) )
 
268
                 / hfs_sect_block;
 
269
        nfree = PED_BE16_TO_CPU (mdb->free_blocks)
 
270
                - ( PED_BE16_TO_CPU (mdb->total_blocks) - nblock );
 
271
 
 
272
        /* Check that all block after future end are really free */
 
273
        for (block = nblock;
 
274
             block < PED_BE16_TO_CPU (mdb->total_blocks);
 
275
             block++) {
 
276
                if (TST_BLOC_OCCUPATION(priv_data->alloc_map,block)) {
 
277
                        resize = 0;
 
278
                        ped_exception_throw (
 
279
                                PED_EXCEPTION_ERROR,
 
280
                                PED_EXCEPTION_CANCEL,
 
281
                                _("Data relocation left some data in the end "
 
282
                                  "of the volume."));
 
283
                        goto write_MDB;
 
284
                }
 
285
        }
 
286
 
 
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);
 
291
 
 
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));
 
302
 
 
303
        /* Update geometry */
 
304
        if (resize) {
 
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;
 
313
        }
 
314
 
 
315
        /* Set the unmounted bit */
 
316
        mdb->volume_attributes |= PED_CPU_TO_BE16 ( 1 << HFS_UNMOUNTED );
 
317
 
 
318
        /* Effective write */
 
319
    write_MDB:
 
320
        ped_timer_set_state_name(timer,_("writing HFS Master Directory Block"));
 
321
 
 
322
        if (!hfs_update_mdb(fs)) {
 
323
                ped_geometry_sync(geom);
 
324
                return 0;
 
325
        }
 
326
 
 
327
        if (!ped_geometry_sync(geom))
 
328
                return 0;
 
329
 
 
330
        ped_timer_update(timer, 1.0);
 
331
 
 
332
        return (resize);
 
333
}
 
334
 
 
335
/* ----- HFS+ ----- */
 
336
 
 
337
#include "file_plus.h"
 
338
#include "advfs_plus.h"
 
339
#include "reloc_plus.h"
 
340
#include "journal.h"
 
341
 
 
342
static int
 
343
hfsplus_clobber (PedGeometry* geom)
 
344
{
 
345
        unsigned int i = 1;
 
346
        uint8_t                         buf[PED_SECTOR_SIZE_DEFAULT];
 
347
        HfsMasterDirectoryBlock         *mdb;
 
348
 
 
349
        mdb = (HfsMasterDirectoryBlock *) buf;
 
350
 
 
351
        if (!ped_geometry_read (geom, buf, 2, 1))
 
352
                return 0;
 
353
 
 
354
        if (PED_BE16_TO_CPU (mdb->signature) == HFS_SIGNATURE) {
 
355
                /* embedded hfs+ */
 
356
                PedGeometry     *embedded;
 
357
 
 
358
                i = PED_BE32_TO_CPU(mdb->block_size) / PED_SECTOR_SIZE_DEFAULT;
 
359
                embedded = ped_geometry_new (
 
360
                    geom->dev,
 
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;
 
368
                else {
 
369
                        i = hfs_clobber (embedded);
 
370
                        ped_geometry_destroy (embedded);
 
371
                }
 
372
        }
 
373
 
 
374
        /* non-embedded or envelop destroy as hfs */
 
375
        return ( hfs_clobber (geom) && i );
 
376
}
 
377
 
 
378
int
 
379
hfsplus_close (PedFileSystem *fs)
 
380
{
 
381
        HfsPPrivateFSData*      priv_data = (HfsPPrivateFSData*)
 
382
                                                fs->type_specific;
 
383
 
 
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);
 
395
        free(priv_data->vh);
 
396
        free(priv_data);
 
397
        free(fs);
 
398
 
 
399
        return 1;
 
400
}
 
401
 
 
402
PedFileSystem*
 
403
hfsplus_open (PedGeometry* geom)
 
404
{
 
405
        uint8_t                 buf[PED_SECTOR_SIZE_DEFAULT];
 
406
        PedFileSystem*          fs;
 
407
        HfsPVolumeHeader*       vh;
 
408
        HfsPPrivateFSData*      priv_data;
 
409
        PedGeometry*            wrapper_geom;
 
410
        unsigned int            map_sectors;
 
411
 
 
412
        if (!hfsc_can_use_geom (geom))
 
413
                return NULL;
 
414
 
 
415
        fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
 
416
        if (!fs) goto hpo;
 
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;
 
421
 
 
422
        fs->geom = ped_geometry_duplicate (geom);
 
423
        if (!fs->geom) goto hpo_pd;
 
424
        fs->type_specific = (void*) priv_data;
 
425
 
 
426
        if ((wrapper_geom = hfs_and_wrapper_probe (geom))) {
 
427
                HfsPrivateFSData*       hfs_priv_data;
 
428
                PedSector               abs_sect, length;
 
429
                unsigned int            bs;
 
430
 
 
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 )
 
444
                                         * bs;
 
445
                length = (PedSector) PED_BE16_TO_CPU (
 
446
                                            hfs_priv_data->mdb->old_new
 
447
                                            .embedded.location.block_count)
 
448
                                     * bs;
 
449
                priv_data->plus_geom = ped_geometry_new (geom->dev, abs_sect,
 
450
                                                         length);
 
451
                if (!priv_data->plus_geom) goto hpo_wr;
 
452
                priv_data->free_geom = 1;
 
453
        } else {
 
454
                priv_data->wrapper = NULL;
 
455
                priv_data->plus_geom = fs->geom;
 
456
                priv_data->free_geom = 0;
 
457
        }
 
458
 
 
459
        if (!ped_geometry_read (priv_data->plus_geom, buf, 2, 1)) goto hpo_pg;
 
460
        memcpy (vh, buf, sizeof (HfsPVolumeHeader));
 
461
        priv_data->vh = vh;
 
462
 
 
463
        if (vh->signature != PED_CPU_TO_BE16(HFSP_SIGNATURE)
 
464
            && vh->signature != PED_CPU_TO_BE16(HFSX_SIGNATURE)) {
 
465
                ped_exception_throw (
 
466
                        PED_EXCEPTION_BUG,
 
467
                        PED_EXCEPTION_CANCEL,
 
468
                        _("No valid HFS[+X] signature has been found while "
 
469
                          "opening."));
 
470
                goto hpo_pg;
 
471
        }
 
472
 
 
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)
 
481
                        goto hpo_pg;
 
482
        }
 
483
 
 
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)
 
492
                        goto hpo_pg;
 
493
        }
 
494
 
 
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))
 
499
                        goto hpo_pg;
 
500
        }
 
501
 
 
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,
 
508
                                   PED_BE64_TO_CPU (
 
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,
 
515
                                   PED_BE64_TO_CPU (
 
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,
 
522
                                   PED_BE64_TO_CPU (
 
523
                                        vh->attributes_file.logical_size)
 
524
                                   / PED_SECTOR_SIZE_DEFAULT);
 
525
        if (!priv_data->attributes_file) goto hpo_cc;
 
526
 
 
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;
 
537
 
 
538
        priv_data->allocation_file =
 
539
                hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFSP_ALLOC_ID),
 
540
                                   vh->allocation_file.extents,
 
541
                                   PED_BE64_TO_CPU (
 
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)) {
 
547
                hfsplus_close(fs);
 
548
                return NULL;
 
549
        }
 
550
 
 
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);
 
554
 
 
555
        return fs;
 
556
 
 
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);
 
567
hpo_vh: free(vh);
 
568
hpo_fs: free(fs);
 
569
hpo:    return NULL;
 
570
}
 
571
 
 
572
PedConstraint *
 
573
hfsplus_get_resize_constraint (const PedFileSystem *fs)
 
574
{
 
575
        PedDevice*      dev = fs->geom->dev;
 
576
        PedAlignment    start_align;
 
577
        PedGeometry     start_sector;
 
578
        PedGeometry     full_dev;
 
579
        PedSector       min_size;
 
580
 
 
581
        if (!ped_alignment_init (&start_align, fs->geom->start, 0))
 
582
                return NULL;
 
583
        if (!ped_geometry_init (&start_sector, dev, fs->geom->start, 1))
 
584
                return NULL;
 
585
        if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
 
586
                return NULL;
 
587
 
 
588
        min_size = hfsplus_get_min_size (fs);
 
589
        if (!min_size) return NULL;
 
590
 
 
591
        return ped_constraint_new (&start_align, ped_alignment_any,
 
592
                                   &start_sector, &full_dev, min_size,
 
593
                                   fs->geom->length);
 
594
}
 
595
 
 
596
static int
 
597
hfsplus_volume_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
 
598
{
 
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*)
 
603
                                                fs->type_specific;
 
604
        HfsPVolumeHeader*       vh = priv_data->vh;
 
605
        int                     resize = 1;
 
606
        unsigned int            hfsp_sect_block =
 
607
                                    ( PED_BE32_TO_CPU (vh->block_size)
 
608
                                      / PED_SECTOR_SIZE_DEFAULT );
 
609
        unsigned int            map_sectors;
 
610
 
 
611
        old_blocks = PED_BE32_TO_CPU (vh->total_blocks);
 
612
 
 
613
        /* Flush caches */
 
614
        if (!ped_geometry_sync(priv_data->plus_geom))
 
615
                return 0;
 
616
 
 
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))
 
622
                return 0;
 
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))
 
626
                return 0;
 
627
 
 
628
        ped_timer_reset (timer);
 
629
        ped_timer_set_state_name(timer, _("shrinking"));
 
630
        ped_timer_update(timer, 0.0);
 
631
        /* relocate data */
 
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)) {
 
637
                resize = 0;
 
638
                ped_exception_throw (
 
639
                        PED_EXCEPTION_ERROR,
 
640
                        PED_EXCEPTION_CANCEL,
 
641
                        _("Data relocation has failed."));
 
642
                goto write_VH;
 
643
        }
 
644
 
 
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)
 
656
                        nfree++;
 
657
        }
 
658
 
 
659
        /* Check that all block after future end are really free */
 
660
        mblock = ( priv_data->plus_geom->length - 2 )
 
661
                 / hfsp_sect_block;
 
662
        if (mblock > old_blocks - 1)
 
663
                mblock = old_blocks - 1;
 
664
        for ( block = nblock;
 
665
              block < mblock;
 
666
              block++ ) {
 
667
                if (TST_BLOC_OCCUPATION(priv_data->alloc_map,block)) {
 
668
                        resize = 0;
 
669
                        ped_exception_throw (
 
670
                                PED_EXCEPTION_ERROR,
 
671
                                PED_EXCEPTION_CANCEL,
 
672
                                _("Data relocation left some data at the end "
 
673
                                  "of the volume."));
 
674
                        goto write_VH;
 
675
                }
 
676
        }
 
677
 
 
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);
 
684
 
 
685
        /* Update geometry */
 
686
        if (resize) {
 
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
 
695
                                            + geom->length - 1;
 
696
        }
 
697
 
 
698
        /* Effective write */
 
699
    write_VH:
 
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);
 
710
 
 
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)) {
 
716
                resize = 0;
 
717
                ped_exception_throw (
 
718
                        PED_EXCEPTION_ERROR,
 
719
                        PED_EXCEPTION_CANCEL,
 
720
                        _("Error while writing the allocation file."));
 
721
        } else {
 
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;
 
728
                     ++block) {
 
729
                        if (!hfsplus_file_write_sector (
 
730
                                        priv_data->allocation_file,
 
731
                                        buf, block)) {
 
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."));
 
738
                                break;
 
739
                        }
 
740
                }
 
741
        }
 
742
        ped_geometry_sync (priv_data->plus_geom);
 
743
 
 
744
        if (resize) {
 
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 );
 
748
        }
 
749
 
 
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);
 
753
                return 0;
 
754
        }
 
755
 
 
756
        if (!ped_geometry_sync(priv_data->plus_geom))
 
757
                return 0;
 
758
 
 
759
        ped_timer_update(timer, 1.0);
 
760
 
 
761
        return (resize);
 
762
}
 
763
 
 
764
/* Update the HFS wrapper mdb and bad blocks file to reflect
 
765
   the new geometry of the embedded HFS+ volume */
 
766
static int
 
767
hfsplus_wrapper_update (PedFileSystem* fs)
 
768
{
 
769
        uint8_t                 node[PED_SECTOR_SIZE_DEFAULT];
 
770
        HfsCPrivateLeafRec      ref;
 
771
        HfsExtentKey            key;
 
772
        HfsNodeDescriptor*      node_desc = (HfsNodeDescriptor*) node;
 
773
        HfsExtentKey*           ret_key;
 
774
        HfsExtDescriptor*       ret_data;
 
775
        unsigned int            i;
 
776
        HfsPPrivateFSData*      priv_data = (HfsPPrivateFSData*)
 
777
                                                fs->type_specific;
 
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)
 
789
                                    / hfs_sect_block;
 
790
        unsigned int            hfs_blocks_embedded_old;
 
791
 
 
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 );
 
804
 
 
805
        if (!hfs_update_mdb(priv_data->wrapper))
 
806
                return 0;
 
807
 
 
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;
 
814
        }
 
815
 
 
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;
 
825
             i++ ) {
 
826
                CLR_BLOC_OCCUPATION(hfs_priv_data->alloc_map, i);
 
827
        }
 
828
        /* and save it */
 
829
        if (!ped_geometry_write (fs->geom, hfs_priv_data->alloc_map,
 
830
                                 PED_BE16_TO_CPU (
 
831
                                      hfs_priv_data->mdb->volume_bitmap_block ),
 
832
                                 ( PED_BE16_TO_CPU (
 
833
                                        hfs_priv_data->mdb->total_blocks )
 
834
                                   + PED_SECTOR_SIZE_DEFAULT * 8 - 1 )
 
835
                                 / (PED_SECTOR_SIZE_DEFAULT * 8)))
 
836
                return 0;
 
837
        if (!ped_geometry_sync (fs->geom))
 
838
                return 0;
 
839
 
 
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);
 
844
        key.start = 0;
 
845
        if (!hfs_btree_search (hfs_priv_data->extent_file,
 
846
                               (HfsPrivateGenericKey*) &key, NULL, 0, &ref)) {
 
847
                ped_exception_throw (
 
848
                        PED_EXCEPTION_ERROR,
 
849
                        PED_EXCEPTION_CANCEL,
 
850
                        _("An error occurred while looking for the mandatory "
 
851
                          "bad blocks file."));
 
852
                return 0;
 
853
        }
 
854
        if (!hfs_file_read_sector (hfs_priv_data->extent_file, node,
 
855
                                   ref.node_number))
 
856
                return 0;
 
857
        ret_key = (HfsExtentKey*) (node + ref.record_pos);
 
858
        ret_data = (HfsExtDescriptor*) ( node + ref.record_pos
 
859
                                         + sizeof (HfsExtentKey) );
 
860
 
 
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))
 
874
                                        return 0;
 
875
                                return 1;
 
876
                        }
 
877
                }
 
878
 
 
879
                if (ref.record_number < PED_BE16_TO_CPU (node_desc->rec_nb)) {
 
880
                        ref.record_number++;
 
881
                } else {
 
882
                        ref.node_number = PED_BE32_TO_CPU (node_desc->next);
 
883
                        if (!ref.node_number
 
884
                            || !hfs_file_read_sector(hfs_priv_data->extent_file,
 
885
                                                     node, ref.node_number))
 
886
                                goto bb_not_found;
 
887
                        ref.record_number = 1;
 
888
                }
 
889
 
 
890
                ref.record_pos =
 
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) );
 
897
        }
 
898
 
 
899
bb_not_found:
 
900
        /* not found : not a valid hfs+ wrapper : failure */
 
901
        ped_exception_throw (
 
902
                PED_EXCEPTION_ERROR,
 
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."));
 
906
        return 0;
 
907
}
 
908
 
 
909
int
 
910
hfsplus_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
 
911
{
 
912
        HfsPPrivateFSData*      priv_data;
 
913
        PedTimer*               timer_plus;
 
914
        PedGeometry*            embedded_geom;
 
915
        PedSector               hgms;
 
916
 
 
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);
 
922
#ifdef DEBUG
 
923
        PED_ASSERT ((hgms = hfsplus_get_min_size (fs)) != 0);
 
924
#else
 
925
        if ((hgms = hfsplus_get_min_size (fs)) == 0)
 
926
                return 0;
 
927
#endif
 
928
 
 
929
        if (ped_geometry_test_equal(fs->geom, geom))
 
930
                return 1;
 
931
 
 
932
        priv_data = (HfsPPrivateFSData*) fs->type_specific;
 
933
 
 
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."));
 
941
                return 0;
 
942
        }
 
943
 
 
944
        if (priv_data->wrapper) {
 
945
                PedSector               red, hgee;
 
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;
 
951
 
 
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);
 
958
                if (!hgee) return 0;
 
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)
 
962
                               * hfs_sect_block;
 
963
                        red = priv_data->plus_geom->length - hgee;
 
964
                }
 
965
                embedded_geom = ped_geometry_new (geom->dev,
 
966
                                                  priv_data->plus_geom->start,
 
967
                                                  priv_data->plus_geom->length
 
968
                                                  - red);
 
969
 
 
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);
 
978
        } else {
 
979
                /* No wrapper : the desired geometry is the desired
 
980
                   HFS+ volume geometry */
 
981
                embedded_geom = geom;
 
982
                timer_plus = timer;
 
983
        }
 
984
 
 
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 (
 
989
                        PED_EXCEPTION_ERROR,
 
990
                        PED_EXCEPTION_CANCEL,
 
991
                        _("Resizing the HFS+ volume has failed."));
 
992
                return 0;
 
993
        }
 
994
 
 
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."));
 
1008
                        return 0;
 
1009
                }
 
1010
                ped_timer_destroy_nested (timer_plus);
 
1011
        }
 
1012
        ped_timer_update(timer, 1.0);
 
1013
 
 
1014
        return 1;
 
1015
}
 
1016
 
 
1017
#ifdef HFS_EXTRACT_FS
 
1018
/* The following is for debugging purpose only, NOT for packaging */
 
1019
 
 
1020
#include <stdio.h>
 
1021
 
 
1022
uint8_t* extract_buffer = NULL;
 
1023
 
 
1024
static int
 
1025
hfs_extract_file(const char* filename, HfsPrivateFile* hfs_file)
 
1026
{
 
1027
        FILE*           fout;
 
1028
        PedSector       sect;
 
1029
 
 
1030
        fout = fopen(filename, "w");
 
1031
        if (!fout) return 0;
 
1032
 
 
1033
        for (sect = 0; sect < hfs_file->sect_nb; ++sect) {
 
1034
                if (!hfs_file_read_sector(hfs_file, extract_buffer, sect))
 
1035
                        goto err_close;
 
1036
                if (!fwrite(extract_buffer, PED_SECTOR_SIZE_DEFAULT, 1, fout))
 
1037
                        goto err_close;
 
1038
        }
 
1039
 
 
1040
        return (fclose(fout) == 0 ? 1 : 0);
 
1041
 
 
1042
err_close:
 
1043
        fclose(fout);
 
1044
        return 0;
 
1045
}
 
1046
 
 
1047
static int
 
1048
hfs_extract_bitmap(const char* filename, PedFileSystem* fs)
 
1049
{
 
1050
        HfsPrivateFSData*               priv_data = (HfsPrivateFSData*)
 
1051
                                                fs->type_specific;
 
1052
        HfsMasterDirectoryBlock*        mdb = priv_data->mdb;
 
1053
        unsigned int    count;
 
1054
        FILE*           fout;
 
1055
        PedSector       sect;
 
1056
 
 
1057
        fout = fopen(filename, "w");
 
1058
        if (!fout) return 0;
 
1059
 
 
1060
        for (sect = PED_BE16_TO_CPU(mdb->volume_bitmap_block);
 
1061
             sect < PED_BE16_TO_CPU(mdb->start_block);
 
1062
             sect += count) {
 
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))
 
1067
                        goto err_close;
 
1068
                if (!fwrite (extract_buffer, count * PED_SECTOR_SIZE_DEFAULT,
 
1069
                             1, fout))
 
1070
                        goto err_close;
 
1071
        }
 
1072
 
 
1073
        return (fclose(fout) == 0 ? 1 : 0);
 
1074
 
 
1075
err_close:
 
1076
        fclose(fout);
 
1077
        return 0;
 
1078
}
 
1079
 
 
1080
static int
 
1081
hfs_extract_mdb (const char* filename, PedFileSystem* fs)
 
1082
{
 
1083
        FILE*           fout;
 
1084
 
 
1085
        fout = fopen(filename, "w");
 
1086
        if (!fout) return 0;
 
1087
 
 
1088
        if (!ped_geometry_read(fs->geom, extract_buffer, 2, 1))
 
1089
                goto err_close;
 
1090
        if (!fwrite(extract_buffer, PED_SECTOR_SIZE_DEFAULT, 1, fout))
 
1091
                goto err_close;
 
1092
 
 
1093
        return (fclose(fout) == 0 ? 1 : 0);
 
1094
 
 
1095
err_close:
 
1096
        fclose(fout);
 
1097
        return 0;
 
1098
}
 
1099
 
 
1100
static int
 
1101
hfs_extract (PedFileSystem* fs, PedTimer* timer)
 
1102
{
 
1103
        HfsPrivateFSData*       priv_data = (HfsPrivateFSData*)
 
1104
                                                fs->type_specific;
 
1105
 
 
1106
        ped_exception_throw (
 
1107
                PED_EXCEPTION_INFORMATION,
 
1108
                PED_EXCEPTION_OK,
 
1109
                _("This is not a real %s check.  This is going to extract "
 
1110
                  "special low level files for debugging purposes."),
 
1111
                "HFS");
 
1112
 
 
1113
        extract_buffer = ped_malloc(BLOCK_MAX_BUFF * PED_SECTOR_SIZE_DEFAULT);
 
1114
        if (!extract_buffer) return 0;
 
1115
 
 
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);
 
1120
 
 
1121
        free(extract_buffer); extract_buffer = NULL;
 
1122
        return 0; /* nothing has been fixed by us ! */
 
1123
}
 
1124
 
 
1125
static int
 
1126
hfsplus_extract_file(const char* filename, HfsPPrivateFile* hfsp_file)
 
1127
{
 
1128
        FILE*           fout;
 
1129
        unsigned int    cp_sect;
 
1130
        PedSector       rem_sect;
 
1131
 
 
1132
        fout = fopen(filename, "w");
 
1133
        if (!fout) return 0;
 
1134
 
 
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))
 
1139
                        goto err_close;
 
1140
                if (!fwrite (extract_buffer, cp_sect * PED_SECTOR_SIZE_DEFAULT,
 
1141
                             1, fout))
 
1142
                        goto err_close;
 
1143
        }
 
1144
 
 
1145
        return (fclose(fout) == 0 ? 1 : 0);
 
1146
 
 
1147
err_close:
 
1148
        fclose(fout);
 
1149
        return 0;
 
1150
}
 
1151
 
 
1152
static int
 
1153
hfsplus_extract_vh (const char* filename, PedFileSystem* fs)
 
1154
{
 
1155
        HfsPPrivateFSData*      priv_data = (HfsPPrivateFSData*)
 
1156
                                                fs->type_specific;
 
1157
        FILE*           fout;
 
1158
        PedGeometry*    geom = priv_data->plus_geom;
 
1159
 
 
1160
 
 
1161
        fout = fopen(filename, "w");
 
1162
        if (!fout) return 0;
 
1163
 
 
1164
        if (!ped_geometry_read(geom, extract_buffer, 2, 1))
 
1165
                goto err_close;
 
1166
        if (!fwrite(extract_buffer, PED_SECTOR_SIZE_DEFAULT, 1, fout))
 
1167
                goto err_close;
 
1168
 
 
1169
        return (fclose(fout) == 0 ? 1 : 0);
 
1170
 
 
1171
err_close:
 
1172
        fclose(fout);
 
1173
        return 0;
 
1174
}
 
1175
 
 
1176
/* TODO : use the timer to report what is happening */
 
1177
/* TODO : use exceptions to report errors */
 
1178
static int
 
1179
hfsplus_extract (PedFileSystem* fs, PedTimer* timer)
 
1180
{
 
1181
        HfsPPrivateFSData*      priv_data = (HfsPPrivateFSData*)
 
1182
                                                fs->type_specific;
 
1183
        HfsPVolumeHeader*       vh = priv_data->vh;
 
1184
        HfsPPrivateFile*        startup_file;
 
1185
 
 
1186
        if (priv_data->wrapper) {
 
1187
                /* TODO : create nested timer */
 
1188
                hfs_extract (priv_data->wrapper, timer);
 
1189
        }
 
1190
 
 
1191
        ped_exception_throw (
 
1192
                PED_EXCEPTION_INFORMATION,
 
1193
                PED_EXCEPTION_OK,
 
1194
                _("This is not a real %s check.  This is going to extract "
 
1195
                  "special low level files for debugging purposes."),
 
1196
                "HFS+");
 
1197
 
 
1198
        extract_buffer = ped_malloc(BLOCK_MAX_BUFF * PED_SECTOR_SIZE_DEFAULT);
 
1199
        if (!extract_buffer) return 0;
 
1200
 
 
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);
 
1206
 
 
1207
        startup_file = hfsplus_file_open(fs, PED_CPU_TO_BE32(HFSP_STARTUP_ID),
 
1208
                                        vh->startup_file.extents,
 
1209
                                        PED_BE64_TO_CPU (
 
1210
                                           vh->startup_file.logical_size)
 
1211
                                        / PED_SECTOR_SIZE_DEFAULT);
 
1212
        if (startup_file) {
 
1213
                hfsplus_extract_file(HFSP_STARTUP_FILENAME, startup_file);
 
1214
                hfsplus_file_close(startup_file); startup_file = NULL;
 
1215
        }
 
1216
 
 
1217
        free(extract_buffer); extract_buffer = NULL;
 
1218
        return 0; /* nothing has been fixed by us ! */
 
1219
}
 
1220
#endif /* HFS_EXTRACT_FS */
 
1221
 
 
1222
#endif /* !DISCOVER_ONLY */
 
1223
 
 
1224
#if 0
 
1225
static PedFileSystemOps hfs_ops = {
 
1226
        probe:          hfs_probe,
 
1227
#ifndef DISCOVER_ONLY
 
1228
        clobber:        hfs_clobber,
 
1229
        open:           hfs_open,
 
1230
        create:         NULL,
 
1231
        close:          hfs_close,
 
1232
#ifndef HFS_EXTRACT_FS
 
1233
        check:          NULL,
 
1234
#else
 
1235
        check:          hfs_extract,
 
1236
#endif
 
1237
        copy:           NULL,
 
1238
        resize:         hfs_resize,
 
1239
        get_create_constraint:  NULL,
 
1240
        get_resize_constraint:  hfs_get_resize_constraint,
 
1241
        get_copy_constraint:    NULL,
 
1242
#else /* DISCOVER_ONLY */
 
1243
        clobber:        NULL,
 
1244
        open:           NULL,
 
1245
        create:         NULL,
 
1246
        close:          NULL,
 
1247
        check:          NULL,
 
1248
        copy:           NULL,
 
1249
        resize:         NULL,
 
1250
        get_create_constraint:  NULL,
 
1251
        get_resize_constraint:  NULL,
 
1252
        get_copy_constraint:    NULL,
 
1253
#endif /* DISCOVER_ONLY */
 
1254
};
 
1255
 
 
1256
static PedFileSystemOps hfsplus_ops = {
 
1257
        probe:          hfsplus_probe,
 
1258
#ifndef DISCOVER_ONLY
 
1259
        clobber:        hfsplus_clobber,
 
1260
        open:           hfsplus_open,
 
1261
        create:         NULL,
 
1262
        close:          hfsplus_close,
 
1263
#ifndef HFS_EXTRACT_FS
 
1264
        check:          NULL,
 
1265
#else
 
1266
        check:          hfsplus_extract,
 
1267
#endif
 
1268
        copy:           NULL,
 
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 */
 
1274
        clobber:        NULL,
 
1275
        open:           NULL,
 
1276
        create:         NULL,
 
1277
        close:          NULL,
 
1278
        check:          NULL,
 
1279
        copy:           NULL,
 
1280
        resize:         NULL,
 
1281
        get_create_constraint:  NULL,
 
1282
        get_resize_constraint:  NULL,
 
1283
        get_copy_constraint:    NULL,
 
1284
#endif /* DISCOVER_ONLY */
 
1285
};
 
1286
 
 
1287
static PedFileSystemOps hfsx_ops = {
 
1288
        probe:          hfsx_probe,
 
1289
#ifndef DISCOVER_ONLY
 
1290
        clobber:        hfs_clobber, /* NOT hfsplus_clobber !
 
1291
                                        HFSX can't be embedded */
 
1292
        open:           hfsplus_open,
 
1293
        create:         NULL,
 
1294
        close:          hfsplus_close,
 
1295
#ifndef HFS_EXTRACT_FS
 
1296
        check:          NULL,
 
1297
#else
 
1298
        check:          hfsplus_extract,
 
1299
#endif
 
1300
        copy:           NULL,
 
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 */
 
1306
        clobber:        NULL,
 
1307
        open:           NULL,
 
1308
        create:         NULL,
 
1309
        close:          NULL,
 
1310
        check:          NULL,
 
1311
        copy:           NULL,
 
1312
        resize:         NULL,
 
1313
        get_create_constraint:  NULL,
 
1314
        get_resize_constraint:  NULL,
 
1315
        get_copy_constraint:    NULL,
 
1316
#endif /* DISCOVER_ONLY */
 
1317
};
 
1318
 
 
1319
 
 
1320
static PedFileSystemType hfs_type = {
 
1321
        next:   NULL,
 
1322
        ops:    &hfs_ops,
 
1323
        name:   "hfs",
 
1324
        block_sizes: HFS_BLOCK_SIZES
 
1325
};
 
1326
 
 
1327
static PedFileSystemType hfsplus_type = {
 
1328
        next:   NULL,
 
1329
        ops:    &hfsplus_ops,
 
1330
        name:   "hfs+",
 
1331
        block_sizes: HFSP_BLOCK_SIZES
 
1332
};
 
1333
 
 
1334
static PedFileSystemType hfsx_type = {
 
1335
        next:   NULL,
 
1336
        ops:    &hfsx_ops,
 
1337
        name:   "hfsx",
 
1338
        block_sizes: HFSX_BLOCK_SIZES
 
1339
};
 
1340
 
 
1341
void
 
1342
ped_file_system_hfs_init ()
 
1343
{
 
1344
        ped_file_system_type_register (&hfs_type);
 
1345
        ped_file_system_type_register (&hfsplus_type);
 
1346
        ped_file_system_type_register (&hfsx_type);
 
1347
}
 
1348
 
 
1349
void
 
1350
ped_file_system_hfs_done ()
 
1351
{
 
1352
        ped_file_system_type_unregister (&hfs_type);
 
1353
        ped_file_system_type_unregister (&hfsplus_type);
 
1354
        ped_file_system_type_unregister (&hfsx_type);
 
1355
}
 
1356
#endif