xref: /onnv-gate/usr/src/lib/libparted/common/libparted/fs/hfs/cache.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) 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 #ifndef DISCOVER_ONLY
20*9663SMark.Logan@Sun.COM 
21*9663SMark.Logan@Sun.COM #include <config.h>
22*9663SMark.Logan@Sun.COM 
23*9663SMark.Logan@Sun.COM #include <parted/parted.h>
24*9663SMark.Logan@Sun.COM #include <parted/endian.h>
25*9663SMark.Logan@Sun.COM #include <parted/debug.h>
26*9663SMark.Logan@Sun.COM #include <stdint.h>
27*9663SMark.Logan@Sun.COM 
28*9663SMark.Logan@Sun.COM #if ENABLE_NLS
29*9663SMark.Logan@Sun.COM #  include <libintl.h>
30*9663SMark.Logan@Sun.COM #  define _(String) dgettext (PACKAGE, String)
31*9663SMark.Logan@Sun.COM #else
32*9663SMark.Logan@Sun.COM #  define _(String) (String)
33*9663SMark.Logan@Sun.COM #endif /* ENABLE_NLS */
34*9663SMark.Logan@Sun.COM 
35*9663SMark.Logan@Sun.COM #include "hfs.h"
36*9663SMark.Logan@Sun.COM 
37*9663SMark.Logan@Sun.COM #include "cache.h"
38*9663SMark.Logan@Sun.COM 
39*9663SMark.Logan@Sun.COM static HfsCPrivateCacheTable*
hfsc_new_cachetable(unsigned int size)40*9663SMark.Logan@Sun.COM hfsc_new_cachetable(unsigned int size)
41*9663SMark.Logan@Sun.COM {
42*9663SMark.Logan@Sun.COM 	HfsCPrivateCacheTable* ret;
43*9663SMark.Logan@Sun.COM 
44*9663SMark.Logan@Sun.COM 	ret = (HfsCPrivateCacheTable*) ped_malloc(sizeof(*ret));
45*9663SMark.Logan@Sun.COM 	if (!ret) return NULL;
46*9663SMark.Logan@Sun.COM 
47*9663SMark.Logan@Sun.COM 	ret->next_cache = NULL;
48*9663SMark.Logan@Sun.COM 	ret->table_size = size;
49*9663SMark.Logan@Sun.COM 	ret->table_first_free = 0;
50*9663SMark.Logan@Sun.COM 
51*9663SMark.Logan@Sun.COM 	ret->table = ped_malloc(sizeof(*ret->table)*size);
52*9663SMark.Logan@Sun.COM 	if (!ret->table) { ped_free(ret); return NULL; }
53*9663SMark.Logan@Sun.COM 	memset(ret->table, 0, sizeof(*ret->table)*size);
54*9663SMark.Logan@Sun.COM 
55*9663SMark.Logan@Sun.COM 	return ret;
56*9663SMark.Logan@Sun.COM }
57*9663SMark.Logan@Sun.COM 
58*9663SMark.Logan@Sun.COM HfsCPrivateCache*
hfsc_new_cache(unsigned int block_number,unsigned int file_number)59*9663SMark.Logan@Sun.COM hfsc_new_cache(unsigned int block_number, unsigned int file_number)
60*9663SMark.Logan@Sun.COM {
61*9663SMark.Logan@Sun.COM 	unsigned int		cachetable_size, i;
62*9663SMark.Logan@Sun.COM 	HfsCPrivateCache*	ret;
63*9663SMark.Logan@Sun.COM 
64*9663SMark.Logan@Sun.COM 	ret = (HfsCPrivateCache*) ped_malloc(sizeof(*ret));
65*9663SMark.Logan@Sun.COM 	if (!ret) return NULL;
66*9663SMark.Logan@Sun.COM 	ret->block_number = block_number;
67*9663SMark.Logan@Sun.COM 	/* following code avoid integer overflow */
68*9663SMark.Logan@Sun.COM 	ret->linked_ref_size = block_number > block_number + ((1<<CR_SHIFT)-1) ?
69*9663SMark.Logan@Sun.COM 				( block_number >> CR_SHIFT ) + 1 :
70*9663SMark.Logan@Sun.COM 				( block_number + ((1<<CR_SHIFT)-1) ) >> CR_SHIFT
71*9663SMark.Logan@Sun.COM 			     ;
72*9663SMark.Logan@Sun.COM 
73*9663SMark.Logan@Sun.COM 	ret->linked_ref = (HfsCPrivateExtent**)
74*9663SMark.Logan@Sun.COM 			   ped_malloc( sizeof(*ret->linked_ref)
75*9663SMark.Logan@Sun.COM 			   		* ret->linked_ref_size );
76*9663SMark.Logan@Sun.COM 	if (!ret->linked_ref) { ped_free(ret); return NULL; }
77*9663SMark.Logan@Sun.COM 
78*9663SMark.Logan@Sun.COM 	cachetable_size = file_number + file_number / CR_OVER_DIV + CR_ADD_CST;
79*9663SMark.Logan@Sun.COM 	if (cachetable_size < file_number) cachetable_size = (unsigned) -1;
80*9663SMark.Logan@Sun.COM 	ret->first_cachetable_size = cachetable_size;
81*9663SMark.Logan@Sun.COM 	ret->table_list = hfsc_new_cachetable(cachetable_size);
82*9663SMark.Logan@Sun.COM 	if (!ret->table_list) {
83*9663SMark.Logan@Sun.COM 		ped_free(ret->linked_ref);
84*9663SMark.Logan@Sun.COM 		ped_free(ret);
85*9663SMark.Logan@Sun.COM 		return NULL;
86*9663SMark.Logan@Sun.COM 	}
87*9663SMark.Logan@Sun.COM 	ret->last_table = ret->table_list;
88*9663SMark.Logan@Sun.COM 
89*9663SMark.Logan@Sun.COM 	for (i = 0; i < ret->linked_ref_size; ++i)
90*9663SMark.Logan@Sun.COM 		ret->linked_ref[i] = NULL;
91*9663SMark.Logan@Sun.COM 
92*9663SMark.Logan@Sun.COM 	ret->needed_alloc_size = 0;
93*9663SMark.Logan@Sun.COM 
94*9663SMark.Logan@Sun.COM 	return ret;
95*9663SMark.Logan@Sun.COM }
96*9663SMark.Logan@Sun.COM 
97*9663SMark.Logan@Sun.COM static void
hfsc_delete_cachetable(HfsCPrivateCacheTable * list)98*9663SMark.Logan@Sun.COM hfsc_delete_cachetable(HfsCPrivateCacheTable* list)
99*9663SMark.Logan@Sun.COM {
100*9663SMark.Logan@Sun.COM 	HfsCPrivateCacheTable* next;
101*9663SMark.Logan@Sun.COM 
102*9663SMark.Logan@Sun.COM 	while (list) {
103*9663SMark.Logan@Sun.COM 		ped_free (list->table);
104*9663SMark.Logan@Sun.COM 		next = list->next_cache;
105*9663SMark.Logan@Sun.COM 		ped_free (list);
106*9663SMark.Logan@Sun.COM 		list = next;
107*9663SMark.Logan@Sun.COM 	}
108*9663SMark.Logan@Sun.COM }
109*9663SMark.Logan@Sun.COM 
110*9663SMark.Logan@Sun.COM void
hfsc_delete_cache(HfsCPrivateCache * cache)111*9663SMark.Logan@Sun.COM hfsc_delete_cache(HfsCPrivateCache* cache)
112*9663SMark.Logan@Sun.COM {
113*9663SMark.Logan@Sun.COM 	hfsc_delete_cachetable(cache->table_list);
114*9663SMark.Logan@Sun.COM 	ped_free(cache->linked_ref);
115*9663SMark.Logan@Sun.COM 	ped_free(cache);
116*9663SMark.Logan@Sun.COM }
117*9663SMark.Logan@Sun.COM 
118*9663SMark.Logan@Sun.COM HfsCPrivateExtent*
hfsc_cache_add_extent(HfsCPrivateCache * cache,uint32_t start,uint32_t length,uint32_t block,uint16_t offset,uint8_t sbb,uint8_t where,uint8_t ref_index)119*9663SMark.Logan@Sun.COM hfsc_cache_add_extent(HfsCPrivateCache* cache, uint32_t start, uint32_t length,
120*9663SMark.Logan@Sun.COM 		      uint32_t block, uint16_t offset, uint8_t sbb,
121*9663SMark.Logan@Sun.COM 		      uint8_t where, uint8_t ref_index)
122*9663SMark.Logan@Sun.COM {
123*9663SMark.Logan@Sun.COM 	HfsCPrivateExtent*	ext;
124*9663SMark.Logan@Sun.COM 	unsigned int		idx = start >> CR_SHIFT;
125*9663SMark.Logan@Sun.COM 
126*9663SMark.Logan@Sun.COM 	PED_ASSERT(idx < cache->linked_ref_size, return NULL);
127*9663SMark.Logan@Sun.COM 
128*9663SMark.Logan@Sun.COM 	for (ext = cache->linked_ref[idx];
129*9663SMark.Logan@Sun.COM 	     ext && start != ext->ext_start;
130*9663SMark.Logan@Sun.COM 	     ext = ext->next);
131*9663SMark.Logan@Sun.COM 
132*9663SMark.Logan@Sun.COM 	if (ext) {
133*9663SMark.Logan@Sun.COM 		ped_exception_throw (
134*9663SMark.Logan@Sun.COM 			PED_EXCEPTION_ERROR,
135*9663SMark.Logan@Sun.COM 			PED_EXCEPTION_CANCEL,
136*9663SMark.Logan@Sun.COM 			_("Trying to register an extent starting at block "
137*9663SMark.Logan@Sun.COM 			  "0x%X, but another one already exists at this "
138*9663SMark.Logan@Sun.COM 			  "position.  You should check the file system!"),
139*9663SMark.Logan@Sun.COM 			start);
140*9663SMark.Logan@Sun.COM 		return NULL;
141*9663SMark.Logan@Sun.COM 	}
142*9663SMark.Logan@Sun.COM 
143*9663SMark.Logan@Sun.COM 	if ( cache->last_table->table_first_free
144*9663SMark.Logan@Sun.COM 	     == cache->last_table->table_size ) {
145*9663SMark.Logan@Sun.COM 		cache->last_table->next_cache =
146*9663SMark.Logan@Sun.COM 			hfsc_new_cachetable( ( cache->first_cachetable_size
147*9663SMark.Logan@Sun.COM 					       / CR_NEW_ALLOC_DIV )
148*9663SMark.Logan@Sun.COM 					     + CR_ADD_CST );
149*9663SMark.Logan@Sun.COM 		if (!cache->last_table->next_cache)
150*9663SMark.Logan@Sun.COM 			return NULL;
151*9663SMark.Logan@Sun.COM 		cache->last_table = cache->last_table->next_cache;
152*9663SMark.Logan@Sun.COM 	}
153*9663SMark.Logan@Sun.COM 
154*9663SMark.Logan@Sun.COM 	ext = cache->last_table->table+(cache->last_table->table_first_free++);
155*9663SMark.Logan@Sun.COM 
156*9663SMark.Logan@Sun.COM 	ext->ext_start = start;
157*9663SMark.Logan@Sun.COM 	ext->ext_length = length;
158*9663SMark.Logan@Sun.COM 	ext->ref_block = block;
159*9663SMark.Logan@Sun.COM 	ext->ref_offset = offset;
160*9663SMark.Logan@Sun.COM 	ext->sect_by_block = sbb;
161*9663SMark.Logan@Sun.COM 	ext->where = where;
162*9663SMark.Logan@Sun.COM 	ext->ref_index = ref_index;
163*9663SMark.Logan@Sun.COM 
164*9663SMark.Logan@Sun.COM 	ext->next = cache->linked_ref[idx];
165*9663SMark.Logan@Sun.COM 	cache->linked_ref[idx] = ext;
166*9663SMark.Logan@Sun.COM 
167*9663SMark.Logan@Sun.COM 	cache->needed_alloc_size = cache->needed_alloc_size >
168*9663SMark.Logan@Sun.COM 				   (unsigned) PED_SECTOR_SIZE_DEFAULT * sbb ?
169*9663SMark.Logan@Sun.COM 				   cache->needed_alloc_size :
170*9663SMark.Logan@Sun.COM 				   (unsigned) PED_SECTOR_SIZE_DEFAULT * sbb;
171*9663SMark.Logan@Sun.COM 
172*9663SMark.Logan@Sun.COM 	return ext;
173*9663SMark.Logan@Sun.COM }
174*9663SMark.Logan@Sun.COM 
175*9663SMark.Logan@Sun.COM HfsCPrivateExtent*
hfsc_cache_search_extent(HfsCPrivateCache * cache,uint32_t start)176*9663SMark.Logan@Sun.COM hfsc_cache_search_extent(HfsCPrivateCache* cache, uint32_t start)
177*9663SMark.Logan@Sun.COM {
178*9663SMark.Logan@Sun.COM 	HfsCPrivateExtent*	ret;
179*9663SMark.Logan@Sun.COM 	unsigned int	idx = start >> CR_SHIFT;
180*9663SMark.Logan@Sun.COM 
181*9663SMark.Logan@Sun.COM 	PED_ASSERT(idx < cache->linked_ref_size, return NULL);
182*9663SMark.Logan@Sun.COM 
183*9663SMark.Logan@Sun.COM 	for (ret = cache->linked_ref[idx];
184*9663SMark.Logan@Sun.COM 	     ret && start != ret->ext_start;
185*9663SMark.Logan@Sun.COM 	     ret = ret->next);
186*9663SMark.Logan@Sun.COM 
187*9663SMark.Logan@Sun.COM 	return ret;
188*9663SMark.Logan@Sun.COM }
189*9663SMark.Logan@Sun.COM 
190*9663SMark.Logan@Sun.COM /* Can't fail if extent begining at old_start exists */
191*9663SMark.Logan@Sun.COM /* Returns 0 if no such extent, or on error */
192*9663SMark.Logan@Sun.COM HfsCPrivateExtent*
hfsc_cache_move_extent(HfsCPrivateCache * cache,uint32_t old_start,uint32_t new_start)193*9663SMark.Logan@Sun.COM hfsc_cache_move_extent(HfsCPrivateCache* cache, uint32_t old_start,
194*9663SMark.Logan@Sun.COM 			uint32_t new_start)
195*9663SMark.Logan@Sun.COM {
196*9663SMark.Logan@Sun.COM 	HfsCPrivateExtent**	ppext;
197*9663SMark.Logan@Sun.COM 	HfsCPrivateExtent*	pext;
198*9663SMark.Logan@Sun.COM 
199*9663SMark.Logan@Sun.COM 	unsigned int 		idx1 = old_start >> CR_SHIFT;
200*9663SMark.Logan@Sun.COM 	unsigned int		idx2 = new_start >> CR_SHIFT;
201*9663SMark.Logan@Sun.COM 
202*9663SMark.Logan@Sun.COM 	PED_ASSERT(idx1 < cache->linked_ref_size, return NULL);
203*9663SMark.Logan@Sun.COM 	PED_ASSERT(idx2 < cache->linked_ref_size, return NULL);
204*9663SMark.Logan@Sun.COM 
205*9663SMark.Logan@Sun.COM 	for (pext = cache->linked_ref[idx2];
206*9663SMark.Logan@Sun.COM 	     pext && new_start != pext->ext_start;
207*9663SMark.Logan@Sun.COM 	     pext = pext->next);
208*9663SMark.Logan@Sun.COM 
209*9663SMark.Logan@Sun.COM 	if (pext) {
210*9663SMark.Logan@Sun.COM 		ped_exception_throw (
211*9663SMark.Logan@Sun.COM 			PED_EXCEPTION_BUG,
212*9663SMark.Logan@Sun.COM 			PED_EXCEPTION_CANCEL,
213*9663SMark.Logan@Sun.COM 			_("Trying to move an extent from block Ox%X to block "
214*9663SMark.Logan@Sun.COM 			  "Ox%X, but another one already exists at this "
215*9663SMark.Logan@Sun.COM 			  "position.  This should not happen!"),
216*9663SMark.Logan@Sun.COM 			old_start, new_start);
217*9663SMark.Logan@Sun.COM 		return NULL;
218*9663SMark.Logan@Sun.COM 	}
219*9663SMark.Logan@Sun.COM 
220*9663SMark.Logan@Sun.COM 	for (ppext = &(cache->linked_ref[idx1]);
221*9663SMark.Logan@Sun.COM 	     (*ppext) && old_start != (*ppext)->ext_start;
222*9663SMark.Logan@Sun.COM 	     ppext = &((*ppext)->next));
223*9663SMark.Logan@Sun.COM 
224*9663SMark.Logan@Sun.COM 	if (!(*ppext)) return NULL;
225*9663SMark.Logan@Sun.COM 
226*9663SMark.Logan@Sun.COM 	/* removing the extent from the cache */
227*9663SMark.Logan@Sun.COM 	pext = *ppext;
228*9663SMark.Logan@Sun.COM 	(*ppext) = pext->next;
229*9663SMark.Logan@Sun.COM 
230*9663SMark.Logan@Sun.COM 	/* change ext_start and insert the extent again */
231*9663SMark.Logan@Sun.COM 	pext->ext_start = new_start;
232*9663SMark.Logan@Sun.COM 	pext->next = cache->linked_ref[idx2];
233*9663SMark.Logan@Sun.COM 	cache->linked_ref[idx2] = pext;
234*9663SMark.Logan@Sun.COM 
235*9663SMark.Logan@Sun.COM 	return pext;
236*9663SMark.Logan@Sun.COM }
237*9663SMark.Logan@Sun.COM 
238*9663SMark.Logan@Sun.COM #endif /* DISCOVER_ONLY */
239