blob: 310547fcc290a955cb5784498c9cfe733079b92a [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*/
Brandon McAnsh10e42bb2015-10-10 16:50:58 -040028#include <stdlib.h>
jianfenge00bc4e2012-06-19 19:53:15 +080029#include <string.h>
30#include "dosfs.h"
31#include "ext.h"
32#include "fatcache.h"
xiaogangc1175492013-05-16 10:29:23 -070033#include "fragment.h"
jianfenge00bc4e2012-06-19 19:53:15 +080034#include "fsutil.h"
35#include <stdio.h>
36#include <unistd.h>
37#include "tree.h"
38int fsck_msdos_cache_compare(struct cluster_chain_descriptor *fat1,struct cluster_chain_descriptor *fat2)
39{
40 if(fat1->head > fat2->head)
41 return 1;
42 else if(fat1->head < fat2->head)
43 return -1;
44 else
45 return 0;
46}
47struct FSCK_MSDOS_CACHE rb_root;
48RB_GENERATE(FSCK_MSDOS_CACHE,cluster_chain_descriptor,rb,fsck_msdos_cache_compare);
rockiec0e0350a2013-05-16 09:24:26 -070049
50/*
51 *Function GetNextClusFromFAT
52 *PURPUSE: reconvert cluster fat from FAT table in memory
53 *PARAMETERS:
54 * boot -> pointer to the boot sector of FAT
55 * fatable -> pointer to the FAT table in memory
56 * clust ->get the next cluster of paramter clust
57 */
jianfenge00bc4e2012-06-19 19:53:15 +080058unsigned int GetNextClusFromFAT( struct bootblock*boot,u_char*fatable,unsigned int clust)
59{
60 unsigned int nextclus;
61 if(!fatable){
62 fsck_err("%s:No FAT table \n",__func__);
63 return 0;
64 }
65 switch(boot->ClustMask){
66 case CLUST32_MASK:
67 nextclus = fatable[4*clust] + (fatable[4*clust+1]<<8) + (fatable[4*clust+2]<<16) + (fatable[4*clust+3]<<24);
68 nextclus &= boot->ClustMask;
69 break;
70
71 case CLUST16_MASK:
72 nextclus = fatable[2*clust] + (fatable[2*clust+1]<<8);
73 nextclus &= boot->ClustMask;
74 break;
75
76 default:
77 if(clust & 0x1)
78 nextclus = ((fatable[3*(clust/2)+1]>>4) + (fatable[3*(clust/2)+2]<<4)) & 0x0fff;
79 else
80 nextclus = (fatable[3*(clust/2)] + (fatable[3*(clust/2)+1]<<8)) & 0x0fff;
81 break;
82 }
83 return nextclus;
84}
85
rockiec0e0350a2013-05-16 09:24:26 -070086/*
87 *Function SetNextClusToFAT
88 *PURPUSE: reconvert FAT table from cluster fats when write modified FAT table to media
89 *PARAMETERS:
90 * boot -> pointer to the boot sector of FAT
91 * fat -> pointer to the FAT table in memory
92 * cl ->set the next cluster of paramter cl
93 * next -> the next cluster of cl
94 */
jianfenge00bc4e2012-06-19 19:53:15 +080095void SetNextClusToFAT(struct bootblock*boot,u_char*fat ,unsigned int cl ,unsigned int next)
96{
97 /*fat must point to the head of FAT*/
98 u_char* p;
99 if(!fat){
100 fsck_err("%s :No FAT table \n",__func__);
101 return ;
102 }
103 switch(boot->ClustMask){
104 case CLUST32_MASK:
105 p = fat + 4*cl;
106 *p++ = (u_char)next;
107 *p++ = (u_char)(next >>8);
108 *p++ = (u_char)(next >> 16);
109 *p &= 0xf0;
xiaogang5c205e12013-01-31 18:27:23 +0800110 *p |= (next >> 24) & 0x0f;
jianfenge00bc4e2012-06-19 19:53:15 +0800111 break;
112
113 case CLUST16_MASK:
114 p = fat + 2*cl;
115 *p++ = (u_char)next;
116 *p = (u_char)(next >> 8);
117 break;
118
119 default:
120 p = fat + 3*(cl/2);
121 if(cl & 0x1){
122 p++;
123 *p++ |= (u_char)(next << 4);
124 *p = (u_char)(next >> 4);
125 }else{
126 *p++ = (u_char)next;
127 *p |= (next >> 8) & 0x0f;
128 }
129 break;
130
131 }
132}
rockiec0e0350a2013-05-16 09:24:26 -0700133 /*
134 *Function Dump_fatentry
135 *PURPUSE: dump cluster fat information for debug
136 *PARAMETERS:
137 * fat -> pointer to a cluster fat descripor
jianfenge00bc4e2012-06-19 19:53:15 +0800138 */
139void Dump_fatentry(struct cluster_chain_descriptor *fat)
140{
141 struct fatcache *cache;
142 if(!fat){
143 fsck_warn("%s;NULL pointer\n",__func__);
144 return ;
145 }
146 fsck_info("head: 0x%d:",fat->head);
147 cache = fat->child;
148 while(cache){
149 fsck_info(" 0x%d:0x%d ->" ,cache->head,cache->length);
150 cache = cache->next;
151 }
152 fsck_info("EOF\n");
153}
154
rockiec0e0350a2013-05-16 09:24:26 -0700155/*
156 *Function add_fatcache_To_Clusterfat
157 *PURPUSE: add continuous clusters to cluster fat
158 *PARAMETERS:
159 * fatentry -> pointer to a cluster fat descripor which this fatcache be added to
160 * new -> a new fatcache which represent some continuous clusters
161 *NOTE: this function will update length in cluster_fat_descriptor
162 * pls compare this with function add_fatcache_Totail
163 */
jianfenge00bc4e2012-06-19 19:53:15 +0800164int add_fatcache_To_ClusterChain(struct cluster_chain_descriptor *fatentry ,struct fatcache *new)
165{
166 struct fatcache *cache = fatentry->child;
167 if(!fatentry || !new){
168 fsck_warn("%s:NULL pointer\n",__func__);
169 return -1;
170 }
171 /*NULL*/
172 if(!cache){
173 fatentry->child = new;
174 new->next = NULL;
175 fatentry->head = new->head;
176 fatentry->length = new->length;
177 return 0;
178 }
179 /*DO NOT sort,just add to the tail*/
180 while(cache->next){
181 cache = cache->next;
182 }
183 cache->next = new;
184 new->next = NULL;
185 fatentry->length += new->length;
186 return 0;
187}
rockiec0e0350a2013-05-16 09:24:26 -0700188
jianfenge00bc4e2012-06-19 19:53:15 +0800189/*
rockiec0e0350a2013-05-16 09:24:26 -0700190 *Function add_fatcache_Totail_WithOutUpdate
191 *PURPUSE: add a fatcache to the tail of another cluster_fat_descriptor,be used to merge two existing cluster fat
192 *PARAMETERS:
193 * fatentry -> pointer to a cluster fat descripor which this fatcache be added to
194 * new -> a new fatcache which represent some continuous clusters
195 *NOTE: this function will NOT update length in cluster_fat_descriptor
196 * pls compare this with function add_fatcache_To_Clusterfat
jianfenge00bc4e2012-06-19 19:53:15 +0800197 */
198int add_fatcache_Totail(struct cluster_chain_descriptor *fatentry ,struct fatcache *new)
199{
200 struct fatcache *cache;
201 if(!fatentry || !new || !fatentry->child){
202 fsck_warn("%s:NULL pointer\n",__func__);
203 return -1;
204 }
205 cache = fatentry->child;
206 while(cache->next){
207 cache = cache->next;
208 }
209 cache->next = new;
210 return 0;
211}
rockiec0e0350a2013-05-16 09:24:26 -0700212
213 /*
214 *Function Find_cache
215 *PURPUSE: find a fatcache from cluster_fat_descriptor by cluster number cl
216 *PARAMETERS:
217 * fat -> pointer to a cluster fat descripor
218 * cl -> cluster number
219 * prev_cache-> the prev fatcache of OUTPUT
220 *OUTPUT:
221 * return a fatcache which contain cluster cl
jianfenge00bc4e2012-06-19 19:53:15 +0800222 *NOTE:
rockiec0e0350a2013-05-16 09:24:26 -0700223 * if *prev_cache = return cache,that means the cache we find in cluster fat is the first one
jianfenge00bc4e2012-06-19 19:53:15 +0800224 */
225struct fatcache *Find_cache(struct cluster_chain_descriptor *fat,unsigned int cl ,struct fatcache**prev_cache)
226{
227 struct fatcache *cache = fat->child,*prev;
228 prev = cache;
229 while(cache){
230 if( cl >= cache->head && cl < (cache->head + cache->length)){
231 *prev_cache = prev;
232 return cache;
233 }
234 prev = cache;
235 cache = cache->next;
236 }
237 return EMPTY_CACHE;
238}
239
240/*
rockiec0e0350a2013-05-16 09:24:26 -0700241 *Function Find_nextclus
242 *PURPUSE: find the next cluster number of clus
243 *PARAMETERS:
244 * fat -> pointer to a cluster fat descripor
245 * clus -> find the next cluster of cluster number clus
246 * cl -> the next cluster number will returned
247 *OUTPUT:
248 * return a fatcache which contain the next cluster
249 *NOTE:
250 * if returned fatcache is null and *cl = 0 ,that means DON'T find the next cluster from the given cluster fat
251 * if returned fatcache is null but *cl != 0 ,that means clus is the last cluster of the given cluster fat
252 */
jianfenge00bc4e2012-06-19 19:53:15 +0800253struct fatcache* Find_nextclus(struct cluster_chain_descriptor* fat,unsigned int clus, unsigned int* cl)
254{
255 struct fatcache* cache = fat->child;
256 *cl = 0x0;
257 if(!cache){
258 fsck_warn("Not find the cluster after cluster %d\n",clus);
259 return (struct fatcache*)0;
260 }
rockieca232cba2013-01-12 13:13:23 +0800261
jianfenge00bc4e2012-06-19 19:53:15 +0800262 while(cache){
263 if(clus >= cache->head && clus <= cache->head + cache->length -2 ){
264 *cl = clus + 1;
265 return cache;
266 }
267 if(clus == cache->head + cache->length -1 ){
268 cache = cache->next;
269 if(cache){
270 *cl = cache->head;
271 return cache;
272 }else{
273 *cl = CLUST_EOF;
274 return (struct fatcache*)0;
275 }
276 }
277 cache = cache->next;
278 }
279 return EMPTY_CACHE;
280}
rockiec0e0350a2013-05-16 09:24:26 -0700281
282/*
283 *Function delete_fatcache_below
284 *PURPUSE: delete all the fatcache below a given fatcache in a given cluster fat
285 *PARAMETERS:
286 * fatentry -> pointer to a cluster fat descripor
287 * cache -> the fatcache whose below fatcache will be removed
288 */
jianfenge00bc4e2012-06-19 19:53:15 +0800289int delete_fatcache_below(struct cluster_chain_descriptor * fatentry,struct fatcache*cache)
290{
291 struct fatcache *curr = cache,*next,*last;
xiaogangc1175492013-05-16 10:29:23 -0700292 struct fragment *frag,*insert;
293
jianfenge00bc4e2012-06-19 19:53:15 +0800294 last = cache;
295 if(!cache || !fatentry){
296 fsck_warn("%s:NULL pointer\n",__func__);
297 return -1;
298 }
299 next = curr->next;
300 if(!next)
301 return 0;
302 while(next){
303 curr = next;
304 next = next->next;
305 fatentry->length -= curr->length;
xiaogangc1175492013-05-16 10:29:23 -0700306 frag = New_fragment();
307 if(!frag){
308 fsck_err("%s: No space left\n",__func__);
309 goto free;
310 }
311 /*when clear chain or Trunc ,move this cluster cache to free tree for writefat()*/
312 frag->head = curr->head;
313 curr->length = curr->length;
314 insert = RB_INSERT(FSCK_MSDOS_FRAGMENT,&rb_free_root,frag);
315 if(insert)
316 fsck_warn("%s:fragment(head:0x%x) exist\n",__func__,frag->head);
317free:
jianfenge00bc4e2012-06-19 19:53:15 +0800318 free((void*)curr);
319 }
320 last->next = NULL;
321 return 0;
322}
323
rockiec0e0350a2013-05-16 09:24:26 -0700324/*
325 *Function Trunc
326 *PURPUSE: delete all the clusters after cl from a given cluster fat
327 *PARAMETERS:
328 * fat -> pointer to a cluster fat descripor
329 * cl -> the cluster whose below clusters will be removed
330 *NOTE: this function was used to handle the issue when a file has incorrect cluster numbers
331 */
xiaogangc1175492013-05-16 10:29:23 -0700332void Trunc(struct bootblock *boot, struct cluster_chain_descriptor *fat, unsigned int cl)
jianfenge00bc4e2012-06-19 19:53:15 +0800333{
xiaogangc1175492013-05-16 10:29:23 -0700334 struct fatcache *prev , *cache = Find_cache(fat,cl,&prev);
335 unsigned int currlen = 0,org_chain_len = fat->length;
336 struct fragment *frag,*insert;
337 fsck_info("cluster chain :%p ,cl : %d \n",fat,cl);
jianfenge00bc4e2012-06-19 19:53:15 +0800338
xiaogangc1175492013-05-16 10:29:23 -0700339 if(!cache)
340 return;
341 delete_fatcache_below(fat,cache);
342 currlen = cl - cache->head + 1;
343 if(currlen != cache->length){
344 frag = New_fragment();
345 if(!frag){
346 fsck_err("%s ,No space left\n",__func__);
347 goto re_calc;
348 }
349 frag->head = cl + 1;
350 frag->length = cache->length - currlen;
351 insert = RB_INSERT(FSCK_MSDOS_FRAGMENT,&rb_free_root,frag);
352 if(insert)
353 fsck_info("%s:fragment(head:0x%x) exist\n",__func__,frag->head);
354 }
355re_calc:
356 fat->length -= (cache->length - currlen);
357 cache->length = currlen;
358 /*re-calc Numfree*/
359 boot->NumFree += (org_chain_len - fat->length);
360}
Xiaogang Cui53020722014-04-09 19:30:53 +0800361
362/*
363 * This is a trade-off between time and memory
364 * In order to reduce the runtime memory consumption
365 * We change the whole strategy of cluster chain checking
366 * and managment.
367 * In some extreme cases, most of the clusters in FAT file
368 * system are discrete. that means it will take much time
369 * to manage memory and cluster chain at runtime.
370 * So set a limitation of max memory malloc here.
371 */
372int limit = 0;
373#define FSCK_MSDOS_MAX_CALLOC_TIMES 0x15000
374
jianfenge00bc4e2012-06-19 19:53:15 +0800375struct cluster_chain_descriptor* New_fatentry(void)
376{
377 struct cluster_chain_descriptor *fat;
378 fat = calloc(1,sizeof(struct cluster_chain_descriptor));
379 if(!fat){
380 fsck_warn("No space\n");
381 return fat;
382 }
383 RB_SET(fat, NULL, rb);
Xiaogang Cui53020722014-04-09 19:30:53 +0800384 if (++limit >= FSCK_MSDOS_MAX_CALLOC_TIMES)
385 exit(0);
386
jianfenge00bc4e2012-06-19 19:53:15 +0800387 return fat;
388}
389
390struct fatcache* New_fatcache(void)
391{
392 struct fatcache *cache;
393 cache = calloc(1,sizeof(struct fatcache));
394 if(!cache)
395 fsck_warn("No space \n");
Xiaogang Cui53020722014-04-09 19:30:53 +0800396 if (++limit >= FSCK_MSDOS_MAX_CALLOC_TIMES)
397 exit(0);
398
jianfenge00bc4e2012-06-19 19:53:15 +0800399 return cache;
400}
401
402void free_rb_tree(void)
403{
404 struct cluster_chain_descriptor *fat ,*next_fat;
405 struct fatcache *cache ,*next_cache;
406 fsck_info("%s \n",__func__);
407 fat = RB_MIN(FSCK_MSDOS_CACHE,&rb_root);
408 if(!fat){
409 fsck_info("%s :rb tree is empty\n",__func__);
410 return ;
411 }
412 while(fat){
413 cache = fat->child;
414 if(!cache)
415 continue;
416 while(cache->next){
417 next_cache = cache->next;
418 free(cache);
419 cache = next_cache;
420 }
421 next_fat = RB_NEXT(FSCK_MSDOS_CACHE,0,fat);
422 /*must remove from rb tree before free*/
423 RB_REMOVE(FSCK_MSDOS_CACHE,&rb_root,fat);
424 free(fat);
425 fat = next_fat;
426 }
427}