xref: /onnv-gate/usr/src/lib/libparted/common/libparted/fs/hfs/reloc.c (revision 9663:ace9a2ac3683)
1 /*
2     libparted - a library for manipulating disk partitions
3     Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #ifndef DISCOVER_ONLY
20 
21 #include <config.h>
22 
23 #include <parted/parted.h>
24 #include <parted/endian.h>
25 #include <parted/debug.h>
26 #include <stdint.h>
27 
28 #if ENABLE_NLS
29 #  include <libintl.h>
30 #  define _(String) dgettext (PACKAGE, String)
31 #else
32 #  define _(String) (String)
33 #endif /* ENABLE_NLS */
34 
35 #include "hfs.h"
36 #include "file.h"
37 #include "advfs.h"
38 #include "cache.h"
39 
40 #include "reloc.h"
41 
42 /* This function moves data of size blocks starting
43    at block *ptr_fblock to block *ptr_to_fblock */
44 /* return new start or -1 on failure */
45 static int
hfs_effect_move_extent(PedFileSystem * fs,unsigned int * ptr_fblock,unsigned int * ptr_to_fblock,unsigned int size)46 hfs_effect_move_extent (PedFileSystem *fs, unsigned int *ptr_fblock,
47 			unsigned int *ptr_to_fblock, unsigned int size)
48 {
49 	HfsPrivateFSData* 	priv_data = (HfsPrivateFSData*)
50 						fs->type_specific;
51 	unsigned int		i, ok = 0;
52 	unsigned int		next_to_fblock;
53 	unsigned int		start, stop;
54 
55 	PED_ASSERT (hfs_block != NULL, return -1);
56 	PED_ASSERT (*ptr_to_fblock <= *ptr_fblock, return -1);
57 	/* quiet gcc */
58 	next_to_fblock = start = stop = 0;
59 
60 /*
61 	Try to fit the extent AT or _BEFORE_ the wanted place,
62 	or then in the gap between dest and source.
63 	If failed try to fit the extent after source, for 2 pass relocation
64 	The extent is always copied in a non overlapping way
65 */
66 
67 	/* Backward search */
68 	/* 1 pass relocation AT or BEFORE *ptr_to_fblock */
69 	if (*ptr_to_fblock != *ptr_fblock) {
70 		start = stop = *ptr_fblock < *ptr_to_fblock+size ?
71 			       *ptr_fblock : *ptr_to_fblock+size;
72 		while (start && stop-start != size) {
73 			--start;
74 			if (TST_BLOC_OCCUPATION(priv_data->alloc_map,start))
75 				stop = start;
76 		}
77 		ok = (stop-start == size);
78 	}
79 
80 	/* Forward search */
81 	/* 1 pass relocation in the gap merged with 2 pass reloc after source */
82 	if (!ok && *ptr_to_fblock != *ptr_fblock) {
83 		start = stop = *ptr_to_fblock+1;
84 		while (stop < PED_BE16_TO_CPU(priv_data->mdb->total_blocks)
85 		       && stop-start != size) {
86 			if (TST_BLOC_OCCUPATION(priv_data->alloc_map,stop))
87 				start = stop + 1;
88 			++stop;
89 		}
90 		ok = (stop-start == size);
91 	}
92 
93 	/* new non overlapping room has been found ? */
94 	if (ok) {
95 		/* enough room */
96 		unsigned int j;
97 		unsigned int start_block =
98 			PED_BE16_TO_CPU (priv_data->mdb->start_block );
99 		unsigned int block_sz =
100 			(PED_BE32_TO_CPU (priv_data->mdb->block_size)
101 			 / PED_SECTOR_SIZE_DEFAULT);
102 
103 		if (stop > *ptr_to_fblock && stop <= *ptr_fblock)
104 			/* Fit in the gap */
105 			next_to_fblock = stop;
106 		else
107 			/* Before or after the gap */
108 			next_to_fblock = *ptr_to_fblock;
109 
110 		/* move blocks */
111 		for (i = 0; i < size; /*i+=j*/) {
112 			PedSector 	abs_sector;
113 			unsigned int	ai;
114 
115 			j = size - i; j = (j < hfs_block_count) ?
116 					   j : hfs_block_count ;
117 
118 			abs_sector = start_block
119 				     + (PedSector) (*ptr_fblock + i) * block_sz;
120 			if (!ped_geometry_read (fs->geom, hfs_block, abs_sector,
121 						block_sz * j))
122 				return -1;
123 
124 			abs_sector = start_block
125 				     + (PedSector) (start + i) * block_sz;
126 			if (!ped_geometry_write (fs->geom,hfs_block,abs_sector,
127 						 block_sz * j))
128 				return -1;
129 
130 			for (ai = i+j; i < ai; i++) {
131 				/* free source block */
132 				CLR_BLOC_OCCUPATION(priv_data->alloc_map,
133 						    *ptr_fblock + i);
134 
135 				/* set dest block */
136 				SET_BLOC_OCCUPATION(priv_data->alloc_map,
137 						    start + i);
138 			}
139 		}
140 		if (!ped_geometry_sync_fast (fs->geom))
141 			return -1;
142 
143 		*ptr_fblock += size;
144 		*ptr_to_fblock = next_to_fblock;
145 	} else {
146 		if (*ptr_fblock != *ptr_to_fblock)
147 			/* not enough room, but try to continue */
148 			ped_exception_throw (PED_EXCEPTION_WARNING,
149 					PED_EXCEPTION_IGNORE,
150 					_("An extent has not been relocated."));
151 		start = *ptr_fblock;
152 		*ptr_fblock = *ptr_to_fblock = start + size;
153 	}
154 
155 	return start;
156 }
157 
158 /* Update MDB */
159 /* Return 0 if an error occurred */
160 /* Return 1 if everything ok */
161 int
hfs_update_mdb(PedFileSystem * fs)162 hfs_update_mdb (PedFileSystem *fs)
163 {
164 	HfsPrivateFSData* 	priv_data = (HfsPrivateFSData*)
165 						fs->type_specific;
166 	uint8_t			node[PED_SECTOR_SIZE_DEFAULT];
167 
168     	if (!ped_geometry_read (fs->geom, node, 2, 1))
169 		return 0;
170 	memcpy (node, priv_data->mdb, sizeof (HfsMasterDirectoryBlock));
171 	if (   !ped_geometry_write (fs->geom, node, 2, 1)
172 	    || !ped_geometry_write (fs->geom, node, fs->geom->length - 2, 1)
173 	    || !ped_geometry_sync_fast (fs->geom))
174 		return 0;
175 	return 1;
176 }
177 
178 /* Generic relocator */
179 /* replace previous hfs_do_move_* */
180 static int
hfs_do_move(PedFileSystem * fs,unsigned int * ptr_src,unsigned int * ptr_dest,HfsCPrivateCache * cache,HfsCPrivateExtent * ref)181 hfs_do_move (PedFileSystem* fs, unsigned int *ptr_src,
182 	     unsigned int *ptr_dest, HfsCPrivateCache* cache,
183 	     HfsCPrivateExtent* ref)
184 {
185 	uint8_t			node[PED_SECTOR_SIZE_DEFAULT];
186 	HfsPrivateFSData* 	priv_data = (HfsPrivateFSData*)
187 						fs->type_specific;
188 	HfsPrivateFile*		file;
189 	HfsExtDescriptor*	extent;
190 	HfsCPrivateExtent*	move;
191 	int			new_start;
192 
193 	new_start = hfs_effect_move_extent (fs, ptr_src, ptr_dest,
194 					    ref->ext_length);
195 	if (new_start == -1) return -1;
196 
197 	if (ref->ext_start != (unsigned) new_start) {
198 		/* Load, modify & save */
199 		switch (ref->where) {
200 		/******** MDB *********/
201 		    case CR_PRIM_CAT :
202 			priv_data->catalog_file
203 			->first[ref->ref_index].start_block =
204 				PED_CPU_TO_BE16(new_start);
205 			goto CR_PRIM;
206 		    case CR_PRIM_EXT :
207 			priv_data->extent_file
208 			->first[ref->ref_index].start_block =
209 				PED_CPU_TO_BE16(new_start);
210 		    CR_PRIM :
211 			extent = ( HfsExtDescriptor* )
212 				 ( (uint8_t*)priv_data->mdb + ref->ref_offset );
213 			extent[ref->ref_index].start_block =
214 				PED_CPU_TO_BE16(new_start);
215 			if (!hfs_update_mdb(fs)) return -1;
216 			break;
217 
218 		/********* BTREE *******/
219 		    case CR_BTREE_EXT_CAT :
220 			if (priv_data->catalog_file
221 			    ->cache[ref->ref_index].start_block
222 			    == PED_CPU_TO_BE16(ref->ext_start))
223 				priv_data->catalog_file
224 				->cache[ref->ref_index].start_block =
225 				PED_CPU_TO_BE16(new_start);
226 		    case CR_BTREE_EXT_0 :
227 			file = priv_data->extent_file;
228 			goto CR_BTREE;
229 		    case CR_BTREE_CAT :
230 			file = priv_data->catalog_file;
231 		    CR_BTREE:
232 			PED_ASSERT(ref->sect_by_block == 1
233 			           && ref->ref_offset < PED_SECTOR_SIZE_DEFAULT,
234 				   return -1);
235 			if (!hfs_file_read_sector(file, node, ref->ref_block))
236 				return -1;
237 			extent = ( HfsExtDescriptor* ) (node + ref->ref_offset);
238 			extent[ref->ref_index].start_block =
239 				PED_CPU_TO_BE16(new_start);
240 			if (!hfs_file_write_sector(file, node, ref->ref_block)
241 			    || !ped_geometry_sync_fast (fs->geom))
242 				return -1;
243 			break;
244 
245 		/********** BUG ********/
246 		    default :
247 			ped_exception_throw (
248 				PED_EXCEPTION_ERROR,
249 				PED_EXCEPTION_CANCEL,
250 				_("A reference to an extent comes from a place "
251 				  "it should not.  You should check the file "
252 				  "system!"));
253 			return -1;
254 			break;
255 		}
256 
257 		/* Update the cache */
258 		move = hfsc_cache_move_extent(cache, ref->ext_start, new_start);
259 		if (!move) return -1; /* "cleanly" fail */
260 		PED_ASSERT(move == ref, return -1); /* generate a bug */
261 	}
262 
263 	return new_start;
264 }
265 
266 /* 0 error, 1 ok */
267 static int
hfs_save_allocation(PedFileSystem * fs)268 hfs_save_allocation(PedFileSystem* fs)
269 {
270 	HfsPrivateFSData*	priv_data = (HfsPrivateFSData*)
271 						fs->type_specific;
272 	unsigned int		map_sectors;
273 
274 	map_sectors = ( PED_BE16_TO_CPU (priv_data->mdb->total_blocks)
275 			+ PED_SECTOR_SIZE_DEFAULT * 8 - 1 )
276 		      / (PED_SECTOR_SIZE_DEFAULT * 8);
277 	return ( ped_geometry_write (fs->geom, priv_data->alloc_map,
278 			PED_BE16_TO_CPU (priv_data->mdb->volume_bitmap_block),
279 			map_sectors) );
280 }
281 
282 /* This function moves an extent starting at block fblock to block to_fblock
283    if there's enough room */
284 /* Return 1 if everything was fine */
285 /* Return -1 if an error occurred */
286 /* Return 0 if no extent was found */
287 /* Generic search thanks to the file system cache */
288 static int
hfs_move_extent_starting_at(PedFileSystem * fs,unsigned int * ptr_fblock,unsigned int * ptr_to_fblock,HfsCPrivateCache * cache)289 hfs_move_extent_starting_at (PedFileSystem *fs, unsigned int *ptr_fblock,
290 			     unsigned int *ptr_to_fblock,
291 			     HfsCPrivateCache* cache)
292 {
293 	HfsCPrivateExtent*	ref;
294 	unsigned int		old_start, new_start;
295 
296 	/* Reference search powered by the cache... */
297 	/* This is the optimisation secret :) */
298 	ref = hfsc_cache_search_extent(cache, *ptr_fblock);
299 	if (!ref) return 0; /* not found */
300 
301 	old_start = *ptr_fblock;
302 	new_start = hfs_do_move(fs, ptr_fblock, ptr_to_fblock, cache, ref);
303 	if (new_start == (unsigned int) -1) return -1;
304 	if (new_start > old_start) { /* detect 2 pass reloc */
305 		new_start = hfs_do_move(fs,&new_start,ptr_to_fblock,cache,ref);
306 		if (new_start == (unsigned int) -1 || new_start > old_start)
307 			return -1;
308 	}
309 
310 	/* allocation bitmap save is not atomic with data relocation */
311 	/* so we only do it a few times, and without syncing */
312 	/* The unmounted bit protect us anyway */
313 	hfs_save_allocation(fs);
314 	return 1;
315 }
316 
317 static int
hfs_cache_from_mdb(HfsCPrivateCache * cache,PedFileSystem * fs,PedTimer * timer)318 hfs_cache_from_mdb(HfsCPrivateCache* cache, PedFileSystem* fs,
319 		   PedTimer* timer)
320 {
321 	HfsPrivateFSData* 	priv_data = (HfsPrivateFSData*)
322 						fs->type_specific;
323 	HfsExtDescriptor*	extent;
324 	unsigned int		j;
325 
326 	extent = priv_data->mdb->extents_file_rec;
327     	for (j = 0; j < HFS_EXT_NB; ++j) {
328 		if (!extent[j].block_count) break;
329 		if (!hfsc_cache_add_extent(
330 			cache,
331 			PED_BE16_TO_CPU(extent[j].start_block),
332 			PED_BE16_TO_CPU(extent[j].block_count),
333 			0, /* unused for mdb */
334 			((uint8_t*)extent) - ((uint8_t*)priv_data->mdb),
335 			1, /* load/save only 1 sector */
336 			CR_PRIM_EXT,
337 			j )
338 		   )
339 			return 0;
340 	}
341 
342 	extent = priv_data->mdb->catalog_file_rec;
343 	for (j = 0; j < HFS_EXT_NB; ++j) {
344 		if (!extent[j].block_count) break;
345 		if (!hfsc_cache_add_extent(
346 			cache,
347 			PED_BE16_TO_CPU(extent[j].start_block),
348 			PED_BE16_TO_CPU(extent[j].block_count),
349 			0,
350 			((uint8_t*)extent) - ((uint8_t*)priv_data->mdb),
351 			1,
352 			CR_PRIM_CAT,
353 			j )
354 		   )
355 			return 0;
356 	}
357 
358 	return 1;
359 }
360 
361 static int
hfs_cache_from_catalog(HfsCPrivateCache * cache,PedFileSystem * fs,PedTimer * timer)362 hfs_cache_from_catalog(HfsCPrivateCache* cache, PedFileSystem* fs,
363 		   PedTimer* timer)
364 {
365 	HfsPrivateFSData* 	priv_data = (HfsPrivateFSData*)
366 						fs->type_specific;
367 	uint8_t			node[PED_SECTOR_SIZE_DEFAULT];
368 	HfsHeaderRecord*	header;
369 	HfsNodeDescriptor*	desc = (HfsNodeDescriptor*) node;
370 	HfsCatalogKey*		catalog_key;
371 	HfsCatalog*		catalog_data;
372 	HfsExtDescriptor*	extent;
373 	unsigned int		leaf_node, record_number;
374 	unsigned int		i, j;
375 
376 	if (!priv_data->catalog_file->sect_nb) {
377 		ped_exception_throw (
378 			PED_EXCEPTION_INFORMATION,
379 			PED_EXCEPTION_OK,
380 			_("This HFS volume has no catalog file.  "
381 			  "This is very unusual!"));
382 		return 1;
383 	}
384 
385 	if (!hfs_file_read_sector (priv_data->catalog_file, node, 0))
386 		return 0;
387 	header = (HfsHeaderRecord*)(node +  PED_BE16_TO_CPU(*((uint16_t*)
388 						(node+(PED_SECTOR_SIZE_DEFAULT-2)))));
389 
390 	for (leaf_node = PED_BE32_TO_CPU (header->first_leaf_node);
391 	     leaf_node;
392 	     leaf_node = PED_BE32_TO_CPU (desc->next)) {
393 		if (!hfs_file_read_sector (priv_data->catalog_file,
394 					   node, leaf_node))
395 			return 0;
396 		record_number = PED_BE16_TO_CPU (desc->rec_nb);
397 		for (i = 1; i <= record_number; ++i) {
398 		       /* undocumented alignement */
399 			unsigned int skip;
400 			catalog_key = (HfsCatalogKey*) (node + PED_BE16_TO_CPU(
401 				*((uint16_t*)(node+(PED_SECTOR_SIZE_DEFAULT - 2*i)))));
402 			skip = (1 + catalog_key->key_length + 1) & ~1;
403 			catalog_data = (HfsCatalog*)( ((uint8_t*)catalog_key)
404 							+ skip );
405 			/* check for obvious error in FS */
406 			if (((uint8_t*)catalog_key - node < HFS_FIRST_REC)
407 			    || ((uint8_t*)catalog_data - node
408 				>= PED_SECTOR_SIZE_DEFAULT
409 				   - 2 * (signed)(record_number+1))) {
410 				ped_exception_throw (
411 					PED_EXCEPTION_ERROR,
412 					PED_EXCEPTION_CANCEL,
413 					_("The file system contains errors."));
414 				return 0;
415 			}
416 
417 			if (catalog_data->type != HFS_CAT_FILE) continue;
418 
419 			extent = catalog_data->sel.file.extents_data;
420 			for (j = 0; j < HFS_EXT_NB; ++j) {
421 				if (!extent[j].block_count) break;
422 				if (!hfsc_cache_add_extent(
423 					cache,
424 					PED_BE16_TO_CPU(extent[j].start_block),
425 					PED_BE16_TO_CPU(extent[j].block_count),
426 					leaf_node,
427 					(uint8_t*)extent - node,
428 					1, /* hfs => btree block = 512 b */
429 					CR_BTREE_CAT,
430 					j )
431 				   )
432 					return 0;
433 			}
434 
435 			extent = catalog_data->sel.file.extents_res;
436 			for (j = 0; j < HFS_EXT_NB; ++j) {
437 				if (!extent[j].block_count) break;
438 				if (!hfsc_cache_add_extent(
439 					cache,
440 					PED_BE16_TO_CPU(extent[j].start_block),
441 					PED_BE16_TO_CPU(extent[j].block_count),
442 					leaf_node,
443 					(uint8_t*)extent - node,
444 					1, /* hfs => btree block = 512 b */
445 					CR_BTREE_CAT,
446 					j )
447 				   )
448 					return 0;
449 			}
450 		}
451 	}
452 
453 	return 1;
454 }
455 
456 static int
hfs_cache_from_extent(HfsCPrivateCache * cache,PedFileSystem * fs,PedTimer * timer)457 hfs_cache_from_extent(HfsCPrivateCache* cache, PedFileSystem* fs,
458 		   PedTimer* timer)
459 {
460 	HfsPrivateFSData* 	priv_data = (HfsPrivateFSData*)
461 						fs->type_specific;
462 	uint8_t			node[PED_SECTOR_SIZE_DEFAULT];
463 	HfsHeaderRecord*	header;
464 	HfsNodeDescriptor*	desc = (HfsNodeDescriptor*) node;
465 	HfsExtentKey*		extent_key;
466 	HfsExtDescriptor*	extent;
467 	unsigned int		leaf_node, record_number;
468 	unsigned int		i, j;
469 
470 	if (!priv_data->extent_file->sect_nb) {
471 		ped_exception_throw (
472 			PED_EXCEPTION_INFORMATION,
473 			PED_EXCEPTION_OK,
474 			_("This HFS volume has no extents overflow "
475 			  "file.  This is quite unusual!"));
476 		return 1;
477 	}
478 
479 	if (!hfs_file_read_sector (priv_data->extent_file, node, 0))
480 		return 0;
481 	header = ((HfsHeaderRecord*) (node + PED_BE16_TO_CPU(*((uint16_t *)
482 						(node+(PED_SECTOR_SIZE_DEFAULT-2))))));
483 
484 	for (leaf_node = PED_BE32_TO_CPU (header->first_leaf_node);
485 	     leaf_node;
486 	     leaf_node = PED_BE32_TO_CPU (desc->next)) {
487 		if (!hfs_file_read_sector (priv_data->extent_file, node,
488 					   leaf_node))
489 			return 0;
490 		record_number = PED_BE16_TO_CPU (desc->rec_nb);
491 		for (i = 1; i <= record_number; i++) {
492 			uint8_t	where;
493 			extent_key = (HfsExtentKey*)
494 					(node + PED_BE16_TO_CPU(*((uint16_t *)
495 					      (node+(PED_SECTOR_SIZE_DEFAULT - 2*i)))));
496 			/* size is cst */
497 			extent = (HfsExtDescriptor*)(((uint8_t*)extent_key)
498 						       + sizeof (HfsExtentKey));
499 			/* check for obvious error in FS */
500 			if (((uint8_t*)extent_key - node < HFS_FIRST_REC)
501 			    || ((uint8_t*)extent - node
502 			        >= PED_SECTOR_SIZE_DEFAULT
503 				   - 2 * (signed)(record_number+1))) {
504 				ped_exception_throw (
505 					PED_EXCEPTION_ERROR,
506 					PED_EXCEPTION_CANCEL,
507 					_("The file system contains errors."));
508 				return 0;
509 			}
510 
511 			switch (extent_key->file_ID) {
512 			    case PED_CPU_TO_BE32 (HFS_XTENT_ID) :
513 				if (ped_exception_throw (
514 					PED_EXCEPTION_WARNING,
515 					PED_EXCEPTION_IGNORE_CANCEL,
516 					_("The extents overflow file should not"
517 					  " contain its own extents!  You "
518 					  "should check the file system."))
519 						!= PED_EXCEPTION_IGNORE)
520 					return 0;
521 				where = CR_BTREE_EXT_EXT;
522 				break;
523 			    case PED_CPU_TO_BE32 (HFS_CATALOG_ID) :
524 				where = CR_BTREE_EXT_CAT;
525 				break;
526 			    default :
527 				where = CR_BTREE_EXT_0;
528 				break;
529 			}
530 
531 			for (j = 0; j < HFS_EXT_NB; ++j) {
532 				if (!extent[j].block_count) break;
533 				if (!hfsc_cache_add_extent(
534 					cache,
535 					PED_BE16_TO_CPU(extent[j].start_block),
536 					PED_BE16_TO_CPU(extent[j].block_count),
537 					leaf_node,
538 					(uint8_t*)extent - node,
539 					1, /* hfs => btree block = 512 b */
540 					where,
541 					j )
542 				   )
543 					return 0;
544 			}
545 		}
546 	}
547 
548 	return 1;
549 }
550 
551 /* This function cache every extents start and length stored in any
552    fs structure into the adt defined in cache.[ch]
553    Returns NULL on failure */
554 static HfsCPrivateCache*
hfs_cache_extents(PedFileSystem * fs,PedTimer * timer)555 hfs_cache_extents(PedFileSystem *fs, PedTimer* timer)
556 {
557 	HfsPrivateFSData* 	priv_data = (HfsPrivateFSData*)
558 						fs->type_specific;
559 	HfsCPrivateCache*	ret;
560 	unsigned int		file_number, block_number;
561 
562 	file_number = PED_BE32_TO_CPU(priv_data->mdb->file_count);
563 	block_number = PED_BE16_TO_CPU(priv_data->mdb->total_blocks);
564 	ret = hfsc_new_cache(block_number, file_number);
565 	if (!ret) return NULL;
566 
567 	if (!hfs_cache_from_mdb(ret, fs, timer) ||
568 	    !hfs_cache_from_catalog(ret, fs, timer) ||
569 	    !hfs_cache_from_extent(ret, fs, timer)) {
570 		ped_exception_throw(
571 			PED_EXCEPTION_ERROR,
572 			PED_EXCEPTION_CANCEL,
573 			_("Could not cache the file system in memory."));
574 		hfsc_delete_cache(ret);
575 		return NULL;
576 	}
577 
578 	return ret;
579 }
580 
581 /* This function moves file's data to compact used and free space,
582    starting at fblock block */
583 /* return 0 on error */
584 int
hfs_pack_free_space_from_block(PedFileSystem * fs,unsigned int fblock,PedTimer * timer,unsigned int to_free)585 hfs_pack_free_space_from_block (PedFileSystem *fs, unsigned int fblock,
586 			        PedTimer* timer, unsigned int to_free)
587 {
588 	PedSector		bytes_buff;
589 	HfsPrivateFSData* 	priv_data = (HfsPrivateFSData*)
590 						fs->type_specific;
591 	HfsMasterDirectoryBlock* mdb = priv_data->mdb;
592 	HfsCPrivateCache*	cache;
593 	unsigned int 		to_fblock = fblock;
594 	unsigned int		start = fblock;
595 	unsigned int		divisor = PED_BE16_TO_CPU (mdb->total_blocks)
596 				          + 1 - start - to_free;
597 	int			ret;
598 
599 	PED_ASSERT (!hfs_block, return 0);
600 
601 	cache = hfs_cache_extents (fs, timer);
602 	if (!cache)
603 		return 0;
604 
605 	/* Calculate the size of the copy buffer :
606 	 * Takes BLOCK_MAX_BUFF HFS blocks, but if > BYTES_MAX_BUFF
607 	 * takes the maximum number of HFS blocks so that the buffer
608 	 * will remain smaller than or equal to BYTES_MAX_BUFF, with
609 	 * a minimum of 1 HFS block */
610 	bytes_buff = PED_BE32_TO_CPU (priv_data->mdb->block_size)
611 		     * (PedSector) BLOCK_MAX_BUFF;
612 	if (bytes_buff > BYTES_MAX_BUFF) {
613 		hfs_block_count = BYTES_MAX_BUFF
614 				 / PED_BE32_TO_CPU (priv_data->mdb->block_size);
615 		if (!hfs_block_count)
616 			hfs_block_count = 1;
617 		bytes_buff = (PedSector) hfs_block_count
618 			     * PED_BE32_TO_CPU (priv_data->mdb->block_size);
619 	} else
620 		hfs_block_count = BLOCK_MAX_BUFF;
621 
622 	/* If the cache code requests more space, give it to him */
623 	if (bytes_buff < hfsc_cache_needed_buffer (cache))
624 		bytes_buff = hfsc_cache_needed_buffer (cache);
625 
626 	hfs_block = (uint8_t*) ped_malloc (bytes_buff);
627 	if (!hfs_block)
628 		goto error_cache;
629 
630 	if (!hfs_read_bad_blocks (fs)) {
631 		ped_exception_throw (
632 			PED_EXCEPTION_ERROR,
633 			PED_EXCEPTION_CANCEL,
634 			_("Bad blocks list could not be loaded."));
635 		goto error_alloc;
636 	}
637 
638 	while (fblock < PED_BE16_TO_CPU (mdb->total_blocks)) {
639 		if (TST_BLOC_OCCUPATION(priv_data->alloc_map,fblock)
640 		    && (!hfs_is_bad_block (fs, fblock))) {
641 			if (!(ret = hfs_move_extent_starting_at (fs, &fblock,
642 						&to_fblock, cache)))
643 				to_fblock = ++fblock;
644 			else if (ret == -1) {
645 				ped_exception_throw (
646 					PED_EXCEPTION_ERROR,
647 					PED_EXCEPTION_CANCEL,
648 					_("An error occurred during extent "
649 					  "relocation."));
650 				goto error_alloc;
651 			}
652 		} else {
653 			fblock++;
654 		}
655 
656 		ped_timer_update(timer, (float)(to_fblock - start)/divisor);
657 	}
658 
659 	ped_free (hfs_block); hfs_block = NULL; hfs_block_count = 0;
660 	hfsc_delete_cache (cache);
661 	return 1;
662 
663 error_alloc:
664 	ped_free (hfs_block); hfs_block = NULL; hfs_block_count = 0;
665 error_cache:
666 	hfsc_delete_cache (cache);
667 	return 0;
668 }
669 
670 #endif /* !DISCOVER_ONLY */
671