diff options
author | xiaogang <xiaogang@codeaurora.org> | 2013-05-16 10:29:23 -0700 |
---|---|---|
committer | Adnan Begovic <adnan@cyngn.com> | 2015-10-07 17:39:54 -0700 |
commit | c117549ff821d679778e23af7b25e22388d1f7c9 (patch) | |
tree | 1a6d2339e462ed6bc11fa87cb0681fe16325f517 | |
parent | 5c205e1fd3082288cf874ad9d3dc0740e21c0669 (diff) | |
download | android_external_fsck_msdos-c117549ff821d679778e23af7b25e22388d1f7c9.tar.gz android_external_fsck_msdos-c117549ff821d679778e23af7b25e22388d1f7c9.tar.bz2 android_external_fsck_msdos-c117549ff821d679778e23af7b25e22388d1f7c9.zip |
Correct free size calculation
When clearchain or trunc, move the fatcache to rb_free_root tree.
This way writefat will generate correct FAT table.
When clearchain or trunc, re-calculate the free sectors of
filesystem.
Change-Id: I3b480ab161db5777e6f948f780b6bdaf3ada9467
-rw-r--r-- | dir.c | 4 | ||||
-rw-r--r-- | ext.h | 2 | ||||
-rw-r--r-- | fat.c | 56 | ||||
-rw-r--r-- | fatcache.c | 48 | ||||
-rw-r--r-- | fatcache.h | 2 |
5 files changed, 84 insertions, 28 deletions
@@ -476,7 +476,7 @@ checksize(struct bootblock *boot, u_char *p, //TODO: i don't no why exec clearchain here.when cl != fat.head,clear do nothing //clearchain(boot, fat,cl); //if trunc it ,when next fsck ,the rest will locate in LOST.DIR - Trunc(fat,cl); + Trunc(boot,fat,cl); fsck_debug("after truncate ,fat->length = %d \n",fat->length); return FSFATMOD; } else @@ -840,7 +840,7 @@ readDosDirSection(int f, struct bootblock *boot, tofind.head = dirent.head; c_fat = RB_FIND(FSCK_MSDOS_CACHE,&rb_root,&tofind); if(c_fat) - clearchain(c_fat, dirent.head); + clearchain(boot,c_fat, dirent.head); else mod |= FSERROR; dirent.head = 0; @@ -143,5 +143,5 @@ char *rsrvdcltype(cl_t); /* * Clear a cluster chain in a FAT */ -void clearchain(struct cluster_chain_descriptor *, cl_t); +void clearchain(struct bootblock *,struct cluster_chain_descriptor *, cl_t); #endif @@ -52,7 +52,7 @@ static const char rcsid[] = #include "fragment.h" static int checkclnum(struct bootblock *, cl_t, cl_t *); static int clustdiffer(cl_t, cl_t *, cl_t *, int,int *); -static int tryclear(struct cluster_chain_descriptor *, cl_t, cl_t *); +static int tryclear(struct bootblock* ,struct cluster_chain_descriptor *, cl_t, cl_t *); int _readfat(int, struct bootblock *, int, u_char **); static cl_t firstfreecl = 0xFFFFFFFF; @@ -360,11 +360,12 @@ int checkfat(int fs, struct bootblock *boot, int no,u_char *buffer) p = buffer + 3*(nextclus/2); break; } - ret = checkclnum(boot,prevcl,&nextclus); - if(ret == FSERROR) + err = checkclnum(boot,prevcl,&nextclus); + ret |= err; + if(err & FSERROR) return -1; //truncate the rest clusters - if(ret == FSFATMOD) + if(err & FSFATMOD) break; len++; /* @@ -388,14 +389,14 @@ int checkfat(int fs, struct bootblock *boot, int no,u_char *buffer) fsck_warn("Cluster chain starting at %u ends with cluster marked %s,cl = %d ,nextclus = %d\n",cl,rsrvdcltype(nextclus),cl,nextclus); SET_BIT(fat_bitmap[prevcl/32],prevcl%32); /*if the next cluster is free or reversed ,just clear the existing cluster chain ,let this free or reversed cluster alone*/ - ret |= tryclear(fat,cl,&prevcl); + ret |= tryclear(boot,fat,cl,&prevcl); break; } /*out of range*/ if(nextclus < CLUST_FIRST ||(( nextclus >= boot->NumClusters) && (nextclus < (CLUST_EOFS & boot->ClustMask)))){ fsck_warn("Clusters chain starting at %u ends with cluster out of range (%u) \n",cl,nextclus); SET_BIT(fat_bitmap[prevcl/32],prevcl%32); - ret |= tryclear(fat,cl,&prevcl); + ret |= tryclear(boot,fat,cl,&prevcl); break; } @@ -471,7 +472,7 @@ int checkfat(int fs, struct bootblock *boot, int no,u_char *buffer) *because i handle fat chain by chain here, *it never appear situation that three or more cluster chains linked */ - ret |= tryclear(fat,cl,&prevcl); + ret |= tryclear(boot,fat,cl,&prevcl); break; } } @@ -732,19 +733,42 @@ comparefat(struct bootblock *boot, u_char*first, u_char *second, int fatnum) } void -clearchain(struct cluster_chain_descriptor *fat, cl_t head) -{ +clearchain(struct bootblock *boot,struct cluster_chain_descriptor *fat, cl_t head) + { + struct fatcache * curr,*next; + struct fragment *frag, *insert; + fsck_debug("%s:fat:%p , head(%d) ,length(%d)\n",__func__,fat,fat->head,fat->length); assert(fat); if(fat->head != head) - return ; + return; + /*re-calc free blocks*/ + boot->NumFree += fat->length; + /*move to free tree for writefat()*/ + curr = fat->child; + while(curr){ + next = curr->next; + frag = New_fragment(); + if(!frag){ + fsck_warn("%s: No space left\n",__func__); + goto free; + } + frag->head = curr->head; + frag->length = curr->length; + insert = RB_INSERT(FSCK_MSDOS_FRAGMENT,&rb_free_root,frag); + if(insert) + fsck_warn("%s:fragment(head:0x%x) exist\n",__func__,frag->head); +free: + free(curr); + curr = next; + } /*must remove from rb tree before free*/ RB_REMOVE(FSCK_MSDOS_CACHE,&rb_root,fat); free(fat); } int -tryclear(struct cluster_chain_descriptor *fat, cl_t head, cl_t *trunc) +tryclear(struct bootblock* boot, struct cluster_chain_descriptor *fat, cl_t head, cl_t *trunc) { fsck_debug("fat:%p ,head :%d ,trunc :%d \n",fat,head,*trunc); if(!fat || !trunc){ @@ -752,10 +776,10 @@ tryclear(struct cluster_chain_descriptor *fat, cl_t head, cl_t *trunc) return FSERROR; } if (ask(1, "Clear chain starting at %u", head)) { - clearchain(fat, head); + clearchain(boot,fat, head); return FSFATMOD; } else if (ask(1, "Truncate")) { - Trunc(fat,*trunc); + Trunc(boot,fat,*trunc); return FSFATMOD; } else return FSERROR; @@ -817,7 +841,7 @@ writefat(int fs, struct bootblock *boot, int correct_fat) break; } - if (!_readfat(fs, boot, boot->ValidFat >= 0 ? boot->ValidFat :0, + if (_readfat(fs, boot, boot->ValidFat >= 0 ? boot->ValidFat :0, &old_fat)) { free(buffer); return FSFATAL; @@ -907,13 +931,13 @@ checklost(int dosfs, struct bootblock *boot) /* If the reconnect failed, then just clear the chain */ pwarn("Error reconnecting chain - clearing\n"); mod &= ~FSFATAL; - clearchain(fat,fat->head); + clearchain(boot,fat,fat->head); mod |= FSFATMOD; fat = RB_NEXT(FSCK_MSDOS_CACHE,0,fat); continue; } if (ret == FSERROR && ask(1, "Clear")) { - clearchain(fat, fat->head); + clearchain(boot, fat, fat->head); mod |= FSFATMOD; } fat = RB_NEXT(FSCK_MSDOS_CACHE,0,fat); @@ -29,6 +29,7 @@ #include "dosfs.h" #include "ext.h" #include "fatcache.h" +#include "fragment.h" #include "fsutil.h" #include <stdio.h> #include <unistd.h> @@ -287,6 +288,8 @@ struct fatcache* Find_nextclus(struct cluster_chain_descriptor* fat,unsigned int int delete_fatcache_below(struct cluster_chain_descriptor * fatentry,struct fatcache*cache) { struct fatcache *curr = cache,*next,*last; + struct fragment *frag,*insert; + last = cache; if(!cache || !fatentry){ fsck_warn("%s:NULL pointer\n",__func__); @@ -299,6 +302,18 @@ int delete_fatcache_below(struct cluster_chain_descriptor * fatentry,struct fatc curr = next; next = next->next; fatentry->length -= curr->length; + frag = New_fragment(); + if(!frag){ + fsck_err("%s: No space left\n",__func__); + goto free; + } + /*when clear chain or Trunc ,move this cluster cache to free tree for writefat()*/ + frag->head = curr->head; + curr->length = curr->length; + insert = RB_INSERT(FSCK_MSDOS_FRAGMENT,&rb_free_root,frag); + if(insert) + fsck_warn("%s:fragment(head:0x%x) exist\n",__func__,frag->head); +free: free((void*)curr); } last->next = NULL; @@ -313,18 +328,35 @@ int delete_fatcache_below(struct cluster_chain_descriptor * fatentry,struct fatc * cl -> the cluster whose below clusters will be removed *NOTE: this function was used to handle the issue when a file has incorrect cluster numbers */ -void Trunc(struct cluster_chain_descriptor *fat, unsigned int cl) +void Trunc(struct bootblock *boot, struct cluster_chain_descriptor *fat, unsigned int cl) { - fsck_info("fat :%p ,cl : %d \n",fat,cl); - struct fatcache*prev ; - struct fatcache*cache = Find_cache(fat,cl,&prev); + struct fatcache *prev , *cache = Find_cache(fat,cl,&prev); + unsigned int currlen = 0,org_chain_len = fat->length; + struct fragment *frag,*insert; + fsck_info("cluster chain :%p ,cl : %d \n",fat,cl); + if(!cache) - return ; + return; delete_fatcache_below(fat,cache); - cache->length = cl - cache->head + 1; - fat->length -= (cache->length - (cl - cache->head) - 1); + currlen = cl - cache->head + 1; + if(currlen != cache->length){ + frag = New_fragment(); + if(!frag){ + fsck_err("%s ,No space left\n",__func__); + goto re_calc; + } + frag->head = cl + 1; + frag->length = cache->length - currlen; + insert = RB_INSERT(FSCK_MSDOS_FRAGMENT,&rb_free_root,frag); + if(insert) + fsck_info("%s:fragment(head:0x%x) exist\n",__func__,frag->head); + } +re_calc: + fat->length -= (cache->length - currlen); + cache->length = currlen; + /*re-calc Numfree*/ + boot->NumFree += (org_chain_len - fat->length); } - struct cluster_chain_descriptor* New_fatentry(void) { struct cluster_chain_descriptor *fat; @@ -79,7 +79,7 @@ struct fatcache *Find_cache(struct cluster_chain_descriptor *fat,unsigned int cl /*find the next cluster*/ struct fatcache *Find_nextclus(struct cluster_chain_descriptor* fat,unsigned int clus, unsigned int* cl); int delete_fatcache_below(struct cluster_chain_descriptor* fatentry,struct fatcache*cache); -void Trunc(struct cluster_chain_descriptor *fat, unsigned int cl); +void Trunc(struct bootblock *boot, struct cluster_chain_descriptor *fat, unsigned int cl); void free_rb_tree(void); /*for test*/ void Dump_fatentry(struct cluster_chain_descriptor *fat); |