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