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