diff options
Diffstat (limited to 'dir.c')
-rw-r--r-- | dir.c | 189 |
1 files changed, 42 insertions, 147 deletions
@@ -35,8 +35,6 @@ static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ -#include <assert.h> -#include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -115,7 +113,7 @@ newDosDirEntry(void) struct dosDirEntry *de; if (!(de = freede)) { - if (!(de = malloc(sizeof *de))) + if (!(de = (struct dosDirEntry *)malloc(sizeof *de))) return 0; } else freede = de->next; @@ -140,7 +138,7 @@ newDirTodo(void) struct dirTodoNode *dt; if (!(dt = freedt)) { - if (!(dt = malloc(sizeof *dt))) + if (!(dt = (struct dirTodoNode *)malloc(sizeof *dt))) return 0; } else freedt = dt->next; @@ -169,24 +167,20 @@ fullpath(struct dosDirEntry *dir) char *cp, *np; int nl; - cp = namebuf + sizeof namebuf; - *--cp = '\0'; - - for(;;) { + cp = namebuf + sizeof namebuf - 1; + *cp = '\0'; + do { np = dir->lname[0] ? dir->lname : dir->name; nl = strlen(np); - if (cp <= namebuf + 1 + nl) { - *--cp = '?'; + if ((cp -= nl) <= namebuf + 1) break; - } - cp -= nl; memcpy(cp, np, nl); - dir = dir->parent; - if (!dir) - break; *--cp = '/'; - } - + } while ((dir = dir->parent) != NULL); + if (dir) + *--cp = '?'; + else + cp++; return cp; } @@ -224,6 +218,7 @@ int resetDosDirSection(struct bootblock *boot, struct fatEntry *fat) { int b1, b2; + cl_t cl; int ret = FSOK; size_t len; @@ -256,9 +251,24 @@ resetDosDirSection(struct bootblock *boot, struct fatEntry *fat) boot->bpbRootClust); return FSFATAL; } - if (fat[boot->bpbRootClust].head != boot->bpbRootClust) { - pfatal("Root directory doesn't start a cluster chain"); - return FSFATAL; + cl = fat[boot->bpbRootClust].next; + if (cl < CLUST_FIRST + || (cl >= CLUST_RSRVD && cl< CLUST_EOFS) + || fat[boot->bpbRootClust].head != boot->bpbRootClust) { + if (cl == CLUST_FREE) + pwarn("Root directory starts with free cluster\n"); + else if (cl >= CLUST_RSRVD) + pwarn("Root directory starts with cluster marked %s\n", + rsrvdcltype(cl)); + else { + pfatal("Root directory doesn't start a cluster chain"); + return FSFATAL; + } + if (ask(1, "Fix")) { + fat[boot->bpbRootClust].next = CLUST_FREE; + ret = FSFATMOD; + } else + ret = FSFATAL; } fat[boot->bpbRootClust].flags |= FAT_USED; @@ -317,14 +327,10 @@ delete(int f, struct bootblock *boot, struct fatEntry *fat, cl_t startcl, break; e = delbuf + endoff; } - off = (startcl - CLUST_FIRST) * boot->bpbSecPerClust + boot->FirstCluster; - + off = startcl * boot->bpbSecPerClust + boot->ClusterOffset; off *= boot->bpbBytesPerSec; - if (lseek(f, off, SEEK_SET) != off) { - perr("Unable to lseek to %" PRId64, off); - return FSFATAL; - } - if (read(f, delbuf, clsz) != clsz) { + if (lseek(f, off, SEEK_SET) != off + || read(f, delbuf, clsz) != clsz) { perr("Unable to read directory"); return FSFATAL; } @@ -332,11 +338,8 @@ delete(int f, struct bootblock *boot, struct fatEntry *fat, cl_t startcl, *s = SLOT_DELETED; s += 32; } - if (lseek(f, off, SEEK_SET) != off) { - perr("Unable to lseek to %" PRId64, off); - return FSFATAL; - } - if (write(f, delbuf, clsz) != clsz) { + if (lseek(f, off, SEEK_SET) != off + || write(f, delbuf, clsz) != clsz) { perr("Unable to write directory"); return FSFATAL; } @@ -433,75 +436,6 @@ checksize(struct bootblock *boot, struct fatEntry *fat, u_char *p, return FSOK; } -static const u_char dot_name[11] = ". "; -static const u_char dotdot_name[11] = ".. "; - -/* - * Basic sanity check if the subdirectory have good '.' and '..' entries, - * and they are directory entries. Further sanity checks are performed - * when we traverse into it. - */ -static int -check_subdirectory(int f, struct bootblock *boot, struct dosDirEntry *dir) -{ - u_char *buf, *cp; - off_t off; - cl_t cl; - int retval = FSOK; - - cl = dir->head; - if (dir->parent && (cl < CLUST_FIRST || cl >= boot->NumClusters)) { - return FSERROR; - } - - if (!(boot->flags & FAT32) && !dir->parent) { - off = boot->bpbResSectors + boot->bpbFATs * - boot->FATsecs; - } else { - off = (cl - CLUST_FIRST) * boot->bpbSecPerClust + boot->FirstCluster; - } - - /* - * We only need to check the first two entries of the directory, - * which is found in the first sector of the directory entry, - * so read in only the first sector. - */ - buf = malloc(boot->bpbBytesPerSec); - if (buf == NULL) { - perr("No space for directory buffer (%u)", - boot->bpbBytesPerSec); - return FSFATAL; - } - - off *= boot->bpbBytesPerSec; - if (lseek(f, off, SEEK_SET) != off || - read(f, buf, boot->bpbBytesPerSec) != (ssize_t)boot->bpbBytesPerSec) { - perr("Unable to read directory"); - free(buf); - return FSFATAL; - } - - /* - * Both `.' and `..' must be present and be the first two entries - * and be ATTR_DIRECTORY of a valid subdirectory. - */ - cp = buf; - if (memcmp(cp, dot_name, sizeof(dot_name)) != 0 || - (cp[11] & ATTR_DIRECTORY) != ATTR_DIRECTORY) { - pwarn("%s: Incorrect `.' for %s.\n", __func__, dir->name); - retval |= FSERROR; - } - cp += 32; - if (memcmp(cp, dotdot_name, sizeof(dotdot_name)) != 0 || - (cp[11] & ATTR_DIRECTORY) != ATTR_DIRECTORY) { - pwarn("%s: Incorrect `..' for %s. \n", __func__, dir->name); - retval |= FSERROR; - } - - free(buf); - return retval; -} - /* * Read a directory and * - resolve long name records @@ -539,7 +473,7 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat, boot->FATsecs; } else { last = boot->bpbSecPerClust * boot->bpbBytesPerSec; - off = (cl - CLUST_FIRST) * boot->bpbSecPerClust + boot->FirstCluster; + off = cl * boot->bpbSecPerClust + boot->ClusterOffset; } off *= boot->bpbBytesPerSec; @@ -549,6 +483,9 @@ 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; @@ -576,8 +513,7 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat, empcl, empty - buffer, cl, p - buffer, 1) == FSFATAL) return FSFATAL; - q = ((empcl == cl) ? empty : buffer); - assert(q != NULL); + q = empcl == cl ? empty : buffer; for (; q < p; q += 32) *q = SLOT_DELETED; mod |= THISMOD|FSDIRMOD; @@ -618,15 +554,6 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat, vallfn = NULL; } lidx = *p & LRNOMASK; - if (lidx == 0) { - pwarn("invalid long name\n"); - if (!invlfn) { - invlfn = vallfn; - invcl = valcl; - } - vallfn = NULL; - continue; - } t = longName + --lidx * 13; for (k = 1; k < 11 && t < longName + sizeof(longName); k += 2) { @@ -894,36 +821,6 @@ 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\n", - dirent.name, fullpath(dir)); - if (ask(1, "Remove")) { - *p = SLOT_DELETED; - mod |= THISMOD|FSDIRMOD; - } else - mod |= FSERROR; - continue; - } else if ((check_subdirectory(f, boot, - &dirent) & FSERROR) == FSERROR) { - /* - * A subdirectory should have - * a dot (.) entry and a dot-dot - * (..) entry of ATTR_DIRECTORY, - * we will inspect further when - * traversing into it. - */ - if (ask(1, "Remove")) { - *p = SLOT_DELETED; - mod |= THISMOD|FSDIRMOD; - } else - mod |= FSERROR; - continue; - } } /* create directory tree node */ @@ -1067,12 +964,10 @@ reconnect(int dosfs, struct bootblock *boot, struct fatEntry *fat, cl_t head) if (lfcl < CLUST_FIRST || lfcl >= boot->NumClusters) { /* Extend LOSTDIR? XXX */ pwarn("No space in %s\n", LOSTDIR); - lfcl = (lostDir->head < boot->NumClusters) ? lostDir->head : 0; return FSERROR; } - lfoff = (lfcl - CLUST_FIRST) * boot->ClusterSize - + boot->FirstCluster * boot->bpbBytesPerSec; - + lfoff = lfcl * boot->ClusterSize + + boot->ClusterOffset * boot->bpbBytesPerSec; if (lseek(dosfs, lfoff, SEEK_SET) != lfoff || (size_t)read(dosfs, lfbuf, boot->ClusterSize) != boot->ClusterSize) { perr("could not read LOST.DIR"); |