blob: 4d1e1a65c8d2fa74026846e53bb4fe0fbb38e82a [file] [log] [blame]
jianfenge00bc4e2012-06-19 19:53:15 +08001/*
2*Copyright (c) 2012, The Linux Foundation. All rights reserved.
3*Redistribution and use in source and binary forms, with or without
4*modification, are permitted provided that the following conditions are
5*met:
6 * Redistributions of source code must retain the above copyright
7 notice, this list of conditions and the following disclaimer.
8 * Redistributions in binary form must reproduce the above
9 copyright notice, this list of conditions and the following
10 disclaimer in the documentation and/or other materials provided
11 with the distribution.
12 * Neither the name of The Linux Foundation nor the names of its
13 contributors may be used to endorse or promote products derived
14 from this software without specific prior written permission.
15
16*THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17*WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19*ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20*BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23*BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24*WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25*OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26*IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
27*/
28#include <string.h>
29#include "dosfs.h"
30#include "ext.h"
31#include "fatcache.h"
32#include "fsutil.h"
33#include <stdio.h>
34#include <unistd.h>
35#include "tree.h"
36int fsck_msdos_cache_compare(struct cluster_chain_descriptor *fat1,struct cluster_chain_descriptor *fat2)
37{
38 if(fat1->head > fat2->head)
39 return 1;
40 else if(fat1->head < fat2->head)
41 return -1;
42 else
43 return 0;
44}
45struct FSCK_MSDOS_CACHE rb_root;
46RB_GENERATE(FSCK_MSDOS_CACHE,cluster_chain_descriptor,rb,fsck_msdos_cache_compare);
rockiec0e0350a2013-05-16 09:24:26 -070047
48/*
49 *Function GetNextClusFromFAT
50 *PURPUSE: reconvert cluster fat from FAT table in memory
51 *PARAMETERS:
52 * boot -> pointer to the boot sector of FAT
53 * fatable -> pointer to the FAT table in memory
54 * clust ->get the next cluster of paramter clust
55 */
jianfenge00bc4e2012-06-19 19:53:15 +080056unsigned int GetNextClusFromFAT( struct bootblock*boot,u_char*fatable,unsigned int clust)
57{
58 unsigned int nextclus;
59 if(!fatable){
60 fsck_err("%s:No FAT table \n",__func__);
61 return 0;
62 }
63 switch(boot->ClustMask){
64 case CLUST32_MASK:
65 nextclus = fatable[4*clust] + (fatable[4*clust+1]<<8) + (fatable[4*clust+2]<<16) + (fatable[4*clust+3]<<24);
66 nextclus &= boot->ClustMask;
67 break;
68
69 case CLUST16_MASK:
70 nextclus = fatable[2*clust] + (fatable[2*clust+1]<<8);
71 nextclus &= boot->ClustMask;
72 break;
73
74 default:
75 if(clust & 0x1)
76 nextclus = ((fatable[3*(clust/2)+1]>>4) + (fatable[3*(clust/2)+2]<<4)) & 0x0fff;
77 else
78 nextclus = (fatable[3*(clust/2)] + (fatable[3*(clust/2)+1]<<8)) & 0x0fff;
79 break;
80 }
81 return nextclus;
82}
83
rockiec0e0350a2013-05-16 09:24:26 -070084/*
85 *Function SetNextClusToFAT
86 *PURPUSE: reconvert FAT table from cluster fats when write modified FAT table to media
87 *PARAMETERS:
88 * boot -> pointer to the boot sector of FAT
89 * fat -> pointer to the FAT table in memory
90 * cl ->set the next cluster of paramter cl
91 * next -> the next cluster of cl
92 */
jianfenge00bc4e2012-06-19 19:53:15 +080093void SetNextClusToFAT(struct bootblock*boot,u_char*fat ,unsigned int cl ,unsigned int next)
94{
95 /*fat must point to the head of FAT*/
96 u_char* p;
97 if(!fat){
98 fsck_err("%s :No FAT table \n",__func__);
99 return ;
100 }
101 switch(boot->ClustMask){
102 case CLUST32_MASK:
103 p = fat + 4*cl;
104 *p++ = (u_char)next;
105 *p++ = (u_char)(next >>8);
106 *p++ = (u_char)(next >> 16);
107 *p &= 0xf0;
xiaogang5c205e12013-01-31 18:27:23 +0800108 *p |= (next >> 24) & 0x0f;
jianfenge00bc4e2012-06-19 19:53:15 +0800109 break;
110
111 case CLUST16_MASK:
112 p = fat + 2*cl;
113 *p++ = (u_char)next;
114 *p = (u_char)(next >> 8);
115 break;
116
117 default:
118 p = fat + 3*(cl/2);
119 if(cl & 0x1){
120 p++;
121 *p++ |= (u_char)(next << 4);
122 *p = (u_char)(next >> 4);
123 }else{
124 *p++ = (u_char)next;
125 *p |= (next >> 8) & 0x0f;
126 }
127 break;
128
129 }
130}
rockiec0e0350a2013-05-16 09:24:26 -0700131 /*
132 *Function Dump_fatentry
133 *PURPUSE: dump cluster fat information for debug
134 *PARAMETERS:
135 * fat -> pointer to a cluster fat descripor
jianfenge00bc4e2012-06-19 19:53:15 +0800136 */
137void Dump_fatentry(struct cluster_chain_descriptor *fat)
138{
139 struct fatcache *cache;
140 if(!fat){
141 fsck_warn("%s;NULL pointer\n",__func__);
142 return ;
143 }
144 fsck_info("head: 0x%d:",fat->head);
145 cache = fat->child;
146 while(cache){
147 fsck_info(" 0x%d:0x%d ->" ,cache->head,cache->length);
148 cache = cache->next;
149 }
150 fsck_info("EOF\n");
151}
152
rockiec0e0350a2013-05-16 09:24:26 -0700153/*
154 *Function add_fatcache_To_Clusterfat
155 *PURPUSE: add continuous clusters to cluster fat
156 *PARAMETERS:
157 * fatentry -> pointer to a cluster fat descripor which this fatcache be added to
158 * new -> a new fatcache which represent some continuous clusters
159 *NOTE: this function will update length in cluster_fat_descriptor
160 * pls compare this with function add_fatcache_Totail
161 */
jianfenge00bc4e2012-06-19 19:53:15 +0800162int add_fatcache_To_ClusterChain(struct cluster_chain_descriptor *fatentry ,struct fatcache *new)
163{
164 struct fatcache *cache = fatentry->child;
165 if(!fatentry || !new){
166 fsck_warn("%s:NULL pointer\n",__func__);
167 return -1;
168 }
169 /*NULL*/
170 if(!cache){
171 fatentry->child = new;
172 new->next = NULL;
173 fatentry->head = new->head;
174 fatentry->length = new->length;
175 return 0;
176 }
177 /*DO NOT sort,just add to the tail*/
178 while(cache->next){
179 cache = cache->next;
180 }
181 cache->next = new;
182 new->next = NULL;
183 fatentry->length += new->length;
184 return 0;
185}
rockiec0e0350a2013-05-16 09:24:26 -0700186
jianfenge00bc4e2012-06-19 19:53:15 +0800187/*
rockiec0e0350a2013-05-16 09:24:26 -0700188 *Function add_fatcache_Totail_WithOutUpdate
189 *PURPUSE: add a fatcache to the tail of another cluster_fat_descriptor,be used to merge two existing cluster fat
190 *PARAMETERS:
191 * fatentry -> pointer to a cluster fat descripor which this fatcache be added to
192 * new -> a new fatcache which represent some continuous clusters
193 *NOTE: this function will NOT update length in cluster_fat_descriptor
194 * pls compare this with function add_fatcache_To_Clusterfat
jianfenge00bc4e2012-06-19 19:53:15 +0800195 */
196int add_fatcache_Totail(struct cluster_chain_descriptor *fatentry ,struct fatcache *new)
197{
198 struct fatcache *cache;
199 if(!fatentry || !new || !fatentry->child){
200 fsck_warn("%s:NULL pointer\n",__func__);
201 return -1;
202 }
203 cache = fatentry->child;
204 while(cache->next){
205 cache = cache->next;
206 }
207 cache->next = new;
208 return 0;
209}
rockiec0e0350a2013-05-16 09:24:26 -0700210
211 /*
212 *Function Find_cache
213 *PURPUSE: find a fatcache from cluster_fat_descriptor by cluster number cl
214 *PARAMETERS:
215 * fat -> pointer to a cluster fat descripor
216 * cl -> cluster number
217 * prev_cache-> the prev fatcache of OUTPUT
218 *OUTPUT:
219 * return a fatcache which contain cluster cl
jianfenge00bc4e2012-06-19 19:53:15 +0800220 *NOTE:
rockiec0e0350a2013-05-16 09:24:26 -0700221 * if *prev_cache = return cache,that means the cache we find in cluster fat is the first one
jianfenge00bc4e2012-06-19 19:53:15 +0800222 */
223struct fatcache *Find_cache(struct cluster_chain_descriptor *fat,unsigned int cl ,struct fatcache**prev_cache)
224{
225 struct fatcache *cache = fat->child,*prev;
226 prev = cache;
227 while(cache){
228 if( cl >= cache->head && cl < (cache->head + cache->length)){
229 *prev_cache = prev;
230 return cache;
231 }
232 prev = cache;
233 cache = cache->next;
234 }
235 return EMPTY_CACHE;
236}
237
238/*
rockiec0e0350a2013-05-16 09:24:26 -0700239 *Function Find_nextclus
240 *PURPUSE: find the next cluster number of clus
241 *PARAMETERS:
242 * fat -> pointer to a cluster fat descripor
243 * clus -> find the next cluster of cluster number clus
244 * cl -> the next cluster number will returned
245 *OUTPUT:
246 * return a fatcache which contain the next cluster
247 *NOTE:
248 * if returned fatcache is null and *cl = 0 ,that means DON'T find the next cluster from the given cluster fat
249 * if returned fatcache is null but *cl != 0 ,that means clus is the last cluster of the given cluster fat
250 */
jianfenge00bc4e2012-06-19 19:53:15 +0800251struct fatcache* Find_nextclus(struct cluster_chain_descriptor* fat,unsigned int clus, unsigned int* cl)
252{
253 struct fatcache* cache = fat->child;
254 *cl = 0x0;
255 if(!cache){
256 fsck_warn("Not find the cluster after cluster %d\n",clus);
257 return (struct fatcache*)0;
258 }
rockieca232cba2013-01-12 13:13:23 +0800259
jianfenge00bc4e2012-06-19 19:53:15 +0800260 while(cache){
261 if(clus >= cache->head && clus <= cache->head + cache->length -2 ){
262 *cl = clus + 1;
263 return cache;
264 }
265 if(clus == cache->head + cache->length -1 ){
266 cache = cache->next;
267 if(cache){
268 *cl = cache->head;
269 return cache;
270 }else{
271 *cl = CLUST_EOF;
272 return (struct fatcache*)0;
273 }
274 }
275 cache = cache->next;
276 }
277 return EMPTY_CACHE;
278}
rockiec0e0350a2013-05-16 09:24:26 -0700279
280/*
281 *Function delete_fatcache_below
282 *PURPUSE: delete all the fatcache below a given fatcache in a given cluster fat
283 *PARAMETERS:
284 * fatentry -> pointer to a cluster fat descripor
285 * cache -> the fatcache whose below fatcache will be removed
286 */
jianfenge00bc4e2012-06-19 19:53:15 +0800287int delete_fatcache_below(struct cluster_chain_descriptor * fatentry,struct fatcache*cache)
288{
289 struct fatcache *curr = cache,*next,*last;
290 last = cache;
291 if(!cache || !fatentry){
292 fsck_warn("%s:NULL pointer\n",__func__);
293 return -1;
294 }
295 next = curr->next;
296 if(!next)
297 return 0;
298 while(next){
299 curr = next;
300 next = next->next;
301 fatentry->length -= curr->length;
302 free((void*)curr);
303 }
304 last->next = NULL;
305 return 0;
306}
307
rockiec0e0350a2013-05-16 09:24:26 -0700308/*
309 *Function Trunc
310 *PURPUSE: delete all the clusters after cl from a given cluster fat
311 *PARAMETERS:
312 * fat -> pointer to a cluster fat descripor
313 * cl -> the cluster whose below clusters will be removed
314 *NOTE: this function was used to handle the issue when a file has incorrect cluster numbers
315 */
jianfenge00bc4e2012-06-19 19:53:15 +0800316void Trunc(struct cluster_chain_descriptor *fat, unsigned int cl)
317{
318 fsck_info("fat :%p ,cl : %d \n",fat,cl);
319 struct fatcache*prev ;
320 struct fatcache*cache = Find_cache(fat,cl,&prev);
321 if(!cache)
322 return ;
323 delete_fatcache_below(fat,cache);
324 cache->length = cl - cache->head + 1;
325 fat->length -= (cache->length - (cl - cache->head) - 1);
326}
327
328struct cluster_chain_descriptor* New_fatentry(void)
329{
330 struct cluster_chain_descriptor *fat;
331 fat = calloc(1,sizeof(struct cluster_chain_descriptor));
332 if(!fat){
333 fsck_warn("No space\n");
334 return fat;
335 }
336 RB_SET(fat, NULL, rb);
337 return fat;
338}
339
340struct fatcache* New_fatcache(void)
341{
342 struct fatcache *cache;
343 cache = calloc(1,sizeof(struct fatcache));
344 if(!cache)
345 fsck_warn("No space \n");
346 return cache;
347}
348
349void free_rb_tree(void)
350{
351 struct cluster_chain_descriptor *fat ,*next_fat;
352 struct fatcache *cache ,*next_cache;
353 fsck_info("%s \n",__func__);
354 fat = RB_MIN(FSCK_MSDOS_CACHE,&rb_root);
355 if(!fat){
356 fsck_info("%s :rb tree is empty\n",__func__);
357 return ;
358 }
359 while(fat){
360 cache = fat->child;
361 if(!cache)
362 continue;
363 while(cache->next){
364 next_cache = cache->next;
365 free(cache);
366 cache = next_cache;
367 }
368 next_fat = RB_NEXT(FSCK_MSDOS_CACHE,0,fat);
369 /*must remove from rb tree before free*/
370 RB_REMOVE(FSCK_MSDOS_CACHE,&rb_root,fat);
371 free(fat);
372 fat = next_fat;
373 }
374}