2
libparted - a library for manipulating disk partitions
3
Copyright (C) 2004-2005, 2007, 2009-2012 Free Software Foundation, Inc.
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 3 of the License, or
8
(at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program. If not, see <http://www.gnu.org/licenses/>.
23
#include <parted/parted.h>
24
#include <parted/endian.h>
25
#include <parted/debug.h>
30
# define _(String) dgettext (PACKAGE, String)
32
# define _(String) (String)
33
#endif /* ENABLE_NLS */
36
#include "reloc_plus.h"
40
static int hfsj_vh_replayed = 0;
44
hfsj_calc_checksum(uint8_t *ptr, int len)
49
for (i=0; i < len; i++, ptr++) {
50
cksum = (cksum << 8) ^ (cksum + *ptr);
57
hfsj_update_jib(PedFileSystem* fs, uint32_t block)
59
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
62
priv_data->vh->journal_info_block = PED_CPU_TO_BE32(block);
64
if (!hfsplus_update_vh (fs))
67
priv_data->jib_start_block = block;
72
hfsj_update_jl(PedFileSystem* fs, uint32_t block)
74
uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
77
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
79
HfsJJournalInfoBlock* jib;
82
binsect = HFS_32_TO_CPU(priv_data->vh->block_size, is_le) / PED_SECTOR_SIZE_DEFAULT;
83
sector = (PedSector) priv_data->jib_start_block * binsect;
84
if (!ped_geometry_read(priv_data->plus_geom, buf, sector, 1))
86
jib = (HfsJJournalInfoBlock*) buf;
88
offset = (uint64_t)block * PED_SECTOR_SIZE_DEFAULT * binsect;
89
jib->offset = HFS_CPU_TO_64(offset, is_le);
91
if (!ped_geometry_write(priv_data->plus_geom, buf, sector, 1)
92
|| !ped_geometry_sync(priv_data->plus_geom))
95
priv_data->jl_start_block = block;
99
/* Return the sector in the journal that is after the area read */
102
hfsj_journal_read(PedGeometry* geom, HfsJJournalHeader* jh,
103
PedSector journ_sect, PedSector journ_length,
104
PedSector read_sect, unsigned int nb_sect,
110
r = ped_geometry_read(geom, buf, journ_sect + read_sect, 1);
113
buf = ((uint8_t*)buf) + PED_SECTOR_SIZE_DEFAULT;
115
if (read_sect == journ_length)
116
read_sect = 1; /* skip journal header
117
which is asserted to be
125
hfsj_replay_transaction(PedFileSystem* fs, HfsJJournalHeader* jh,
126
PedSector jsector, PedSector jlength)
128
PedSector start, sector;
129
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
131
HfsJBlockListHeader* blhdr;
133
unsigned int blhdr_nbsect;
135
uint32_t cksum, size;
137
blhdr_nbsect = HFS_32_TO_CPU(jh->blhdr_size, is_le) / PED_SECTOR_SIZE_DEFAULT;
138
blhdr = (HfsJBlockListHeader*)
139
ped_malloc (blhdr_nbsect * PED_SECTOR_SIZE_DEFAULT);
140
if (!blhdr) return 0;
142
start = HFS_64_TO_CPU(jh->start, is_le) / PED_SECTOR_SIZE_DEFAULT;
144
start = hfsj_journal_read(priv_data->plus_geom, jh, jsector,
145
jlength, start, blhdr_nbsect, blhdr);
146
if (!start) goto err_replay;
148
cksum = HFS_32_TO_CPU(blhdr->checksum, is_le);
150
if (cksum!=hfsj_calc_checksum((uint8_t*)blhdr, sizeof(*blhdr))){
151
ped_exception_throw (
153
PED_EXCEPTION_CANCEL,
154
_("Bad block list header checksum."));
157
blhdr->checksum = HFS_CPU_TO_32(cksum, is_le);
159
for (i=1; i < HFS_16_TO_CPU(blhdr->num_blocks, is_le); ++i) {
160
size = HFS_32_TO_CPU(blhdr->binfo[i].bsize, is_le);
161
sector = HFS_64_TO_CPU(blhdr->binfo[i].bnum, is_le);
163
if (size % PED_SECTOR_SIZE_DEFAULT) {
166
PED_EXCEPTION_CANCEL,
167
_("Invalid size of a transaction "
168
"block while replaying the journal "
173
block = (uint8_t*) ped_malloc(size);
174
if (!block) goto err_replay;
175
start = hfsj_journal_read(priv_data->plus_geom, jh,
176
jsector, jlength, start,
177
size / PED_SECTOR_SIZE_DEFAULT,
183
/* the sector stored in the journal seems to be
184
relative to the begin of the block device which
185
contains the hfs+ journaled volume */
187
r = ped_geometry_write (fs->geom, block, sector,
188
size / PED_SECTOR_SIZE_DEFAULT);
192
/* check if wrapper mdb or vh with no wrapper has
194
if ( (sector != ~0LL)
196
&& (2 < sector + size / PED_SECTOR_SIZE_DEFAULT) )
197
hfsj_vh_replayed = 1;
198
/* check if vh of embedded hfs+ has changed */
199
if ( (sector != ~0LL)
200
&& (priv_data->plus_geom != fs->geom)
203
- priv_data->plus_geom->start <= 2)
205
+ size / PED_SECTOR_SIZE_DEFAULT
207
- priv_data->plus_geom->start > 2) )
208
hfsj_vh_replayed = 1;
209
if (!r) goto err_replay;
211
} while (blhdr->binfo[0].next);
213
jh->start = HFS_CPU_TO_64(start * PED_SECTOR_SIZE_DEFAULT, is_le);
216
return (ped_geometry_sync (fs->geom));
223
/* 0 => Failure, don't continue to open ! */
224
/* 1 => Success, the journal has been completly replayed, or don't need to */
226
hfsj_replay_journal(PedFileSystem* fs)
228
uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
229
PedSector sector, length;
230
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
232
HfsJJournalInfoBlock* jib;
233
HfsJJournalHeader* jh;
237
binsect = PED_BE32_TO_CPU(priv_data->vh->block_size) / PED_SECTOR_SIZE_DEFAULT;
238
priv_data->jib_start_block =
239
PED_BE32_TO_CPU(priv_data->vh->journal_info_block);
240
sector = (PedSector) priv_data->jib_start_block * binsect;
241
if (!ped_geometry_read(priv_data->plus_geom, buf, sector, 1))
243
jib = (HfsJJournalInfoBlock*) buf;
245
if ( (jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_IN_FS))
246
&& !(jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_OTHER_DEV)) ) {
247
priv_data->jl_start_block = HFS_64_TO_CPU(jib->offset, is_le)
248
/ ( PED_SECTOR_SIZE_DEFAULT * binsect );
251
if (jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_NEED_INIT))
254
if ( !(jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_IN_FS))
255
|| (jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_OTHER_DEV)) ) {
256
ped_exception_throw (
257
PED_EXCEPTION_NO_FEATURE,
258
PED_EXCEPTION_CANCEL,
259
_("Journal stored outside of the volume are "
260
"not supported. Try to desactivate the "
261
"journal and run Parted again."));
265
if ( (PED_BE64_TO_CPU(jib->offset) % PED_SECTOR_SIZE_DEFAULT)
266
|| (PED_BE64_TO_CPU(jib->size) % PED_SECTOR_SIZE_DEFAULT) ) {
267
ped_exception_throw (
268
PED_EXCEPTION_NO_FEATURE,
269
PED_EXCEPTION_CANCEL,
270
_("Journal offset or size is not multiple of "
271
"the sector size."));
275
sector = PED_BE64_TO_CPU(jib->offset) / PED_SECTOR_SIZE_DEFAULT;
276
length = PED_BE64_TO_CPU(jib->size) / PED_SECTOR_SIZE_DEFAULT;
279
if (!ped_geometry_read(priv_data->plus_geom, buf, sector, 1))
281
jh = (HfsJJournalHeader*) buf;
283
if (jh->endian == PED_LE32_TO_CPU(HFSJ_ENDIAN_MAGIC))
286
if ( (jh->magic != HFS_32_TO_CPU(HFSJ_HEADER_MAGIC, is_le))
287
|| (jh->endian != HFS_32_TO_CPU(HFSJ_ENDIAN_MAGIC, is_le)) ) {
288
ped_exception_throw (
290
PED_EXCEPTION_CANCEL,
291
_("Incorrect magic values in the journal header."));
295
if ( (HFS_64_TO_CPU(jh->size, is_le)%PED_SECTOR_SIZE_DEFAULT)
296
|| (HFS_64_TO_CPU(jh->size, is_le)/PED_SECTOR_SIZE_DEFAULT
297
!= (uint64_t)length) ) {
298
ped_exception_throw (
300
PED_EXCEPTION_CANCEL,
301
_("Journal size mismatch between journal info block "
302
"and journal header."));
306
if ( (HFS_64_TO_CPU(jh->start, is_le) % PED_SECTOR_SIZE_DEFAULT)
307
|| (HFS_64_TO_CPU(jh->end, is_le) % PED_SECTOR_SIZE_DEFAULT)
308
|| (HFS_32_TO_CPU(jh->blhdr_size, is_le) % PED_SECTOR_SIZE_DEFAULT)
309
|| (HFS_32_TO_CPU(jh->jhdr_size, is_le) % PED_SECTOR_SIZE_DEFAULT) ) {
310
ped_exception_throw (
312
PED_EXCEPTION_CANCEL,
313
_("Some header fields are not multiple of the sector "
318
if (HFS_32_TO_CPU(jh->jhdr_size, is_le) != PED_SECTOR_SIZE_DEFAULT) {
319
ped_exception_throw (
321
PED_EXCEPTION_CANCEL,
322
_("The sector size stored in the journal is not 512 "
323
"bytes. Parted only supports 512 bytes length "
328
cksum = HFS_32_TO_CPU(jh->checksum, is_le);
330
if (cksum != hfsj_calc_checksum((uint8_t*)jh, sizeof(*jh))) {
331
ped_exception_throw (
333
PED_EXCEPTION_CANCEL,
334
_("Bad journal checksum."));
337
jh->checksum = HFS_CPU_TO_32(cksum, is_le);
339
/* The 2 following test are in the XNU Darwin source code */
340
/* so I assume they're needed */
341
if (jh->start == jh->size)
342
jh->start = HFS_CPU_TO_64(PED_SECTOR_SIZE_DEFAULT, is_le);
343
if (jh->end == jh->size)
344
jh->start = HFS_CPU_TO_64(PED_SECTOR_SIZE_DEFAULT, is_le);
346
if (jh->start == jh->end)
349
if (ped_exception_throw (
350
PED_EXCEPTION_WARNING,
351
PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL,
352
_("The journal is not empty. Parted must replay the "
353
"transactions before opening the file system. This will "
354
"modify the file system."))
355
!= PED_EXCEPTION_FIX)
358
while (jh->start != jh->end) {
359
/* Replay one complete transaction */
360
if (!hfsj_replay_transaction(fs, jh, sector, length))
363
/* Recalculate cksum of the journal header */
364
jh->checksum = 0; /* need to be 0 while calculating the cksum */
365
cksum = hfsj_calc_checksum((uint8_t*)jh, sizeof(*jh));
366
jh->checksum = HFS_CPU_TO_32(cksum, is_le);
368
/* Update the Journal Header */
369
if (!ped_geometry_write(priv_data->plus_geom, buf, sector, 1)
370
|| !ped_geometry_sync(priv_data->plus_geom))
374
if (hfsj_vh_replayed) {
375
/* probe could have reported incorrect info ! */
376
/* is there a way to ask parted to quit ? */
378
PED_EXCEPTION_WARNING,
380
_("The volume header or the master directory block has "
381
"changed while replaying the journal. You should "
389
#endif /* DISCOVER_ONLY */