summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorxiaogang <xiaogang@codeaurora.org>2013-05-16 10:29:23 -0700
committerAdnan Begovic <adnan@cyngn.com>2015-10-07 17:39:54 -0700
commitc117549ff821d679778e23af7b25e22388d1f7c9 (patch)
tree1a6d2339e462ed6bc11fa87cb0681fe16325f517
parent5c205e1fd3082288cf874ad9d3dc0740e21c0669 (diff)
downloadandroid_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.c4
-rw-r--r--ext.h2
-rw-r--r--fat.c56
-rw-r--r--fatcache.c48
-rw-r--r--fatcache.h2
5 files changed, 84 insertions, 28 deletions
diff --git a/dir.c b/dir.c
index 2d52492..0b26fd4 100644
--- a/dir.c
+++ b/dir.c
@@ -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;
diff --git a/ext.h b/ext.h
index 17f5326..05e8c96 100644
--- a/ext.h
+++ b/ext.h
@@ -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
diff --git a/fat.c b/fat.c
index 73725be..b5a3302 100644
--- a/fat.c
+++ b/fat.c
@@ -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);
diff --git a/fatcache.c b/fatcache.c
index 4d1e1a6..5b9a73b 100644
--- a/fatcache.c
+++ b/fatcache.c
@@ -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;
diff --git a/fatcache.h b/fatcache.h
index ea8d5ff..db08af0 100644
--- a/fatcache.h
+++ b/fatcache.h
@@ -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);