summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authord.moskvitin@samsung.com <d.moskvitin@samsung.com>2010-11-04 15:35:36 -0400
committerMike Lockwood <lockwood@android.com>2010-11-05 15:35:18 -0400
commitb6ee08aadb580341a4d80943741b80de16a88b5d (patch)
tree09ad6ed495e2e2f5ec47332654f4be2776eef87c
parenta6eb0d1794880492a5779fd8e871eb9ceb3e8737 (diff)
downloadandroid_external_fsck_msdos-b6ee08aadb580341a4d80943741b80de16a88b5d.tar.gz
android_external_fsck_msdos-b6ee08aadb580341a4d80943741b80de16a88b5d.tar.bz2
android_external_fsck_msdos-b6ee08aadb580341a4d80943741b80de16a88b5d.zip
Integrate Samsung fsck_msdos fixes, including problem seeking beyond 4 gigcm-7.1.0gingerbread-releasegingerbreadgb-release-7.2
Change-Id: I8829a3a2c26625d7405fa0a43da1640ea5c9ffbc Signed-off-by: Mike Lockwood <lockwood@google.com>
-rw-r--r--dir.c148
-rw-r--r--fat.c30
2 files changed, 156 insertions, 22 deletions
diff --git a/dir.c b/dir.c
index 5837463..b09ab53 100644
--- a/dir.c
+++ b/dir.c
@@ -321,8 +321,12 @@ delete(int f, struct bootblock *boot, struct fatEntry *fat, cl_t startcl,
}
off = startcl * boot->SecPerClust + boot->ClusterOffset;
off *= boot->BytesPerSec;
- if (lseek(f, off, SEEK_SET) != off
- || read(f, delbuf, clsz) != clsz) {
+ if (lseek64(f, off, SEEK_SET) != off) {
+ printf("off = %llu\n", off);
+ perror("Unable to lseek64");
+ return FSFATAL;
+ }
+ if (read(f, delbuf, clsz) != clsz) {
perror("Unable to read directory");
return FSFATAL;
}
@@ -330,8 +334,12 @@ delete(int f, struct bootblock *boot, struct fatEntry *fat, cl_t startcl,
*s = SLOT_DELETED;
s += 32;
}
- if (lseek(f, off, SEEK_SET) != off
- || write(f, delbuf, clsz) != clsz) {
+ if (lseek64(f, off, SEEK_SET) != off) {
+ printf("off = %llu\n", off);
+ perror("Unable to lseek64");
+ return FSFATAL;
+ }
+ if (write(f, delbuf, clsz) != clsz) {
perror("Unable to write directory");
return FSFATAL;
}
@@ -424,6 +432,87 @@ checksize(struct bootblock *boot, struct fatEntry *fat, u_char *p,
return FSOK;
}
+
+static u_char dot_header[16]={0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00};
+static u_char dot_dot_header[16]={0x2E, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00};
+
+/*
+ * Check for missing or broken '.' and '..' entries.
+ */
+static int
+check_dot_dot(int f, struct bootblock *boot, struct fatEntry *fat,struct dosDirEntry *dir)
+{
+ u_char *p, *buf;
+ loff_t off;
+ int last;
+ cl_t cl;
+ int rc=0, n_count;
+
+ int dot, dotdot;
+ dot = dotdot = 0;
+ cl = dir->head;
+
+ if (dir->parent && (cl < CLUST_FIRST || cl >= boot->NumClusters)) {
+ return rc;
+ }
+
+ do {
+ if (!(boot->flags & FAT32) && !dir->parent) {
+ last = boot->RootDirEnts * 32;
+ off = boot->ResSectors + boot->FATs * boot->FATsecs;
+ } else {
+ last = boot->SecPerClust * boot->BytesPerSec;
+ off = cl * boot->SecPerClust + boot->ClusterOffset;
+ }
+
+ off *= boot->BytesPerSec;
+ buf = malloc(last);
+ if (!buf) {
+ perror("Unable to malloc");
+ return FSFATAL;
+ }
+ if (lseek64(f, off, SEEK_SET) != off) {
+ printf("off = %llu\n", off);
+ perror("Unable to lseek64");
+ return FSFATAL;
+ }
+ if (read(f, buf, last) != last) {
+ perror("Unable to read");
+ return FSFATAL;
+ }
+ last /= 32;
+ p = buf;
+ for (n_count=0, rc=0; n_count < 11; n_count++) {
+ if (dot_header[n_count] != p[n_count]) {
+ rc=-1;
+ break;
+ }
+ }
+ if(!rc)
+ dot=1;
+
+ for (n_count = 0, rc = 0; n_count < 11; n_count++) {
+ if (dot_dot_header[n_count] != p[n_count+32]) {
+ rc=-1;
+ break;
+ }
+ }
+ if(!rc)
+ dotdot=1;
+ free(buf);
+ } while ((cl = fat[cl].next) >= CLUST_FIRST && cl < boot->NumClusters);
+
+ if (!dot || !dotdot) {
+ if (!dot)
+ pwarn("%s: '.' absent for %s.\n",__func__,dir->name);
+
+ if (!dotdot)
+ pwarn("%s: '..' absent for %s. \n",__func__,dir->name);
+ return -1;
+ }
+ return 0;
+}
+
/*
* Read a directory and
* - resolve long name records
@@ -443,6 +532,8 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
u_int lidx = 0;
int shortSum;
int mod = FSOK;
+ int n_count=0;
+ int rc=0;
#define THISMOD 0x8000 /* Only used within this routine */
cl = dir->head;
@@ -454,6 +545,9 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
}
shortSum = -1;
vallfn = invlfn = empty = NULL;
+ int dot,dotdot;
+ dot = dotdot = 0;
+
do {
if (!(boot->flags & FAT32) && !dir->parent) {
last = boot->RootDirEnts * 32;
@@ -464,7 +558,7 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
}
off *= boot->BytesPerSec;
- if (lseek64(f, off, SEEK_SET) != off) {
+ if (lseek64(f, off, SEEK_SET) != off) {
printf("off = %llu\n", off);
perror("Unable to lseek64");
return FSFATAL;
@@ -474,9 +568,6 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
return FSFATAL;
}
last /= 32;
- /*
- * Check `.' and `..' entries here? XXX
- */
for (p = buffer, i = 0; i < last; i++, p += 32) {
if (dir->fsckflags & DIREMPWARN) {
*p = SLOT_EMPTY;
@@ -758,11 +849,11 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
mod |= FSERROR;
}
/*
- * handle `.' and `..' specially
+ * handle '.' and '..' specially
*/
if (strcmp(dirent.name, ".") == 0) {
if (dirent.head != dir->head) {
- pwarn("`.' entry in %s has incorrect start cluster\n",
+ pwarn("'.' entry in %s has incorrect start cluster\n",
fullpath(dir));
if (ask(1, "Correct")) {
dirent.head = dir->head;
@@ -777,12 +868,11 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
mod |= FSERROR;
}
continue;
- }
- if (strcmp(dirent.name, "..") == 0) {
+ } else if (strcmp(dirent.name, "..") == 0) {
if (dir->parent) { /* XXX */
if (!dir->parent->parent) {
if (dirent.head) {
- pwarn("`..' entry in %s has non-zero start cluster\n",
+ pwarn("'..' entry in %s has non-zero start cluster\n",
fullpath(dir));
if (ask(1, "Correct")) {
dirent.head = 0;
@@ -794,7 +884,7 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
mod |= FSERROR;
}
} else if (dirent.head != dir->parent->head) {
- pwarn("`..' entry in %s has incorrect start cluster\n",
+ pwarn("'..' entry in %s has incorrect start cluster\n",
fullpath(dir));
if (ask(1, "Correct")) {
dirent.head = dir->parent->head;
@@ -810,6 +900,31 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
}
}
continue;
+ } else { //only one directory entry can point to dir->head, it's '.'
+ if (dirent.head == dir->head) {
+ pwarn("%s entry in %s has incorrect start cluster.remove\n",
+ dirent.name, fullpath(dir));
+ //we have to remove this directory entry rigth now rigth here
+ if (ask(1, "Remove")) {
+ *p = SLOT_DELETED;
+ mod |= THISMOD|FSDIRMOD;
+ } else
+ mod |= FSERROR;
+ continue;
+ }
+ /* Consistency checking. a directory must have at least two entries:
+ a dot (.) entry that points to itself, and a dot-dot (..)
+ entry that points to its parent.
+ */
+ if (check_dot_dot(f,boot,fat,&dirent)) {
+ //mark directory entry as deleted.
+ if (ask(1, "Remove")) {
+ *p = SLOT_DELETED;
+ mod |= THISMOD|FSDIRMOD;
+ } else
+ mod |= FSERROR;
+ continue;
+ }
}
/* create directory tree node */
@@ -820,7 +935,10 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
memcpy(d, &dirent, sizeof(struct dosDirEntry));
/* link it into the tree */
dir->child = d;
-
+#if 0
+ printf("%s: %s : 0x%02x:head %d, next 0x%0x parent 0x%0x child 0x%0x\n",
+ __func__,d->name,d->flags,d->head,d->next,d->parent,d->child);
+#endif
/* Enter this directory into the todo list */
if (!(n = newDirTodo())) {
perror("No space for todo list");
diff --git a/fat.c b/fat.c
index 8871407..2047c88 100644
--- a/fat.c
+++ b/fat.c
@@ -449,7 +449,7 @@ tryclear(struct bootblock *boot, struct fatEntry *fat, cl_t head, cl_t *trunc)
int
checkfat(struct bootblock *boot, struct fatEntry *fat)
{
- cl_t head, p, h, n;
+ cl_t head, p, h, n, wdk;
u_int len;
int ret = 0;
int conf;
@@ -466,8 +466,14 @@ checkfat(struct bootblock *boot, struct fatEntry *fat)
/* follow the chain and mark all clusters on the way */
for (len = 0, p = head;
- p >= CLUST_FIRST && p < boot->NumClusters;
- p = fat[p].next) {
+ p >= CLUST_FIRST && p < boot->NumClusters;
+ p = fat[p].next) {
+ /* we have to check the len, to avoid infinite loop */
+ if (len > boot->NumClusters) {
+ printf("detect cluster chain loop: head %u for p %u\n", head, p);
+ break;
+ }
+
fat[p].head = head;
len++;
}
@@ -487,11 +493,14 @@ checkfat(struct bootblock *boot, struct fatEntry *fat)
continue;
/* follow the chain to its end (hopefully) */
- for (p = head;
- (n = fat[p].next) >= CLUST_FIRST && n < boot->NumClusters;
- p = n)
+ /* also possible infinite loop, that's why I insert wdk counter */
+ for (p = head,wdk=boot->NumClusters;
+ (n = fat[p].next) >= CLUST_FIRST && n < boot->NumClusters && wdk;
+ p = n,wdk--) {
if (fat[n].head != head)
break;
+ }
+
if (n >= CLUST_EOFS)
continue;
@@ -692,9 +701,16 @@ checklost(int dosfs, struct bootblock *boot, struct fatEntry *fat)
ret = 1;
}
}
+
+ if (boot->FSNext > boot->NumClusters ) {
+ pwarn("FSNext block (%d) not correct NumClusters (%d)\n",
+ boot->FSNext, boot->NumClusters);
+ boot->FSNext=CLUST_FIRST; // boot->FSNext can have -1 value.
+ }
+
if (boot->NumFree && fat[boot->FSNext].next != CLUST_FREE) {
pwarn("Next free cluster in FSInfo block (%u) not free\n",
- boot->FSNext);
+ boot->FSNext);
if (ask(1, "Fix"))
for (head = CLUST_FIRST; head < boot->NumClusters; head++)
if (fat[head].next == CLUST_FREE) {