diff options
Diffstat (limited to 'sbin/fsck/dir.c')
-rw-r--r-- | sbin/fsck/dir.c | 143 |
1 files changed, 79 insertions, 64 deletions
diff --git a/sbin/fsck/dir.c b/sbin/fsck/dir.c index 9a2b9239a99f..5662b6e4fee1 100644 --- a/sbin/fsck/dir.c +++ b/sbin/fsck/dir.c @@ -32,17 +32,20 @@ */ #ifndef lint -static const char sccsid[] = "@(#)dir.c 8.1 (Berkeley) 6/5/93"; +static const char sccsid[] = "@(#)dir.c 8.8 (Berkeley) 4/28/95"; #endif /* not lint */ #include <sys/param.h> #include <sys/time.h> + #include <ufs/ufs/dinode.h> #include <ufs/ufs/dir.h> #include <ufs/ffs/fs.h> #include <stdio.h> #include <stdlib.h> +#include <err.h> #include <string.h> + #include "fsck.h" char *lfname = "lost+found"; @@ -57,15 +60,14 @@ struct odirtemplate odirhead = { 0, DIRBLKSIZ - 12, 2, ".." }; - -static int chgino __P((struct inodesc *idesc)); -static int dircheck __P((struct inodesc *idesc, struct direct *dp)); -static int expanddir __P((struct dinode *dp, char *name)); -static void freedir __P((ino_t ino, ino_t parent)); -static struct direct * fsck_readdir __P((struct inodesc *idesc)); -static struct bufarea * getdirblk __P((daddr_t blkno, long size)); -static int lftempname __P((char *bufp, ino_t ino)); -static int mkentry __P((struct inodesc *idesc)); +static int chgino __P((struct inodesc *)); +static int dircheck __P((struct inodesc *, struct direct *)); +static int expanddir __P((struct dinode *dp, char *name)); +static void freedir __P((ino_t ino, ino_t parent)); +static struct direct *fsck_readdir __P((struct inodesc *)); +static struct bufarea *getdirblk __P((ufs_daddr_t blkno, long size)); +static int lftempname __P((char *bufp, ino_t ino)); +static int mkentry __P((struct inodesc *)); /* * Propagate connected state through the tree. @@ -107,7 +109,7 @@ dirscan(idesc) char dbuf[DIRBLKSIZ]; if (idesc->id_type != DATA) - errexit("wrong type to dirscan %d\n", idesc->id_type); + errx(EEXIT, "wrong type to dirscan %d", idesc->id_type); if (idesc->id_entryno == 0 && (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); @@ -119,7 +121,7 @@ dirscan(idesc) idesc->id_loc = 0; for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { dsize = dp->d_reclen; - bcopy((char *)dp, dbuf, (size_t)dsize); + memmove(dbuf, dp, (size_t)dsize); # if (BYTE_ORDER == LITTLE_ENDIAN) if (!newinofmt) { struct direct *tdp = (struct direct *)dbuf; @@ -144,7 +146,7 @@ dirscan(idesc) } # endif bp = getdirblk(idesc->id_blkno, blksiz); - bcopy(dbuf, bp->b_un.b_buf + idesc->id_loc - dsize, + memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, (size_t)dsize); dirty(bp); sbdirty(); @@ -158,7 +160,7 @@ dirscan(idesc) /* * get next entry in a directory. */ -struct direct * +static struct direct * fsck_readdir(idesc) register struct inodesc *idesc; { @@ -173,6 +175,8 @@ fsck_readdir(idesc) dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); if (dircheck(idesc, dp)) goto dpok; + if (idesc->id_fix == IGNORE) + return (0); fix = dofix(idesc, "DIRECTORY CORRUPTED"); bp = getdirblk(idesc->id_blkno, blksiz); dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); @@ -202,6 +206,8 @@ dpok: size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); idesc->id_loc += size; idesc->id_filesize -= size; + if (idesc->id_fix == IGNORE) + return (0); fix = dofix(idesc, "DIRECTORY CORRUPTED"); bp = getdirblk(idesc->id_blkno, blksiz); dp = (struct direct *)(bp->b_un.b_buf + dploc); @@ -216,7 +222,7 @@ dpok: * Verify that a directory entry is valid. * This is a superset of the checks made in the kernel. */ -int +static int dircheck(idesc, dp) struct inodesc *idesc; register struct direct *dp; @@ -226,8 +232,15 @@ dircheck(idesc, dp) u_char namlen, type; int spaceleft; - size = DIRSIZ(!newinofmt, dp); spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); + if (dp->d_ino >= maxino || + dp->d_reclen == 0 || + dp->d_reclen > spaceleft || + (dp->d_reclen & 0x3) != 0) + return (0); + if (dp->d_ino == 0) + return (1); + size = DIRSIZ(!newinofmt, dp); # if (BYTE_ORDER == LITTLE_ENDIAN) if (!newinofmt) { type = dp->d_namlen; @@ -240,23 +253,17 @@ dircheck(idesc, dp) namlen = dp->d_namlen; type = dp->d_type; # endif - if (dp->d_ino < maxino && - dp->d_reclen != 0 && - dp->d_reclen <= spaceleft && - (dp->d_reclen & 0x3) == 0 && - dp->d_reclen >= size && - idesc->id_filesize >= size && - namlen <= MAXNAMLEN && - type <= 15) { - if (dp->d_ino == 0) - return (1); - for (cp = dp->d_name, size = 0; size < namlen; size++) - if (*cp == 0 || (*cp++ == '/')) - return (0); - if (*cp == 0) - return (1); - } - return (0); + if (dp->d_reclen < size || + idesc->id_filesize < size || + namlen > MAXNAMLEN || + type > 15) + return (0); + for (cp = dp->d_name, size = 0; size < namlen; size++) + if (*cp == '\0' || (*cp++ == '/')) + return (0); + if (*cp != '\0') + return (0); + return (1); } void @@ -295,7 +302,7 @@ fileerror(cwd, ino, errmesg) void adjust(idesc, lcnt) register struct inodesc *idesc; - short lcnt; + int lcnt; { register struct dinode *dp; @@ -323,7 +330,7 @@ adjust(idesc, lcnt) } } -int +static int mkentry(idesc) struct inodesc *idesc; { @@ -343,30 +350,38 @@ mkentry(idesc) dirp->d_reclen = oldlen; dirp = (struct direct *)(((char *)dirp) + oldlen); dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ - if (newinofmt) { - dirp->d_type = typemap[idesc->id_parent]; - dirp->d_namlen = newent.d_namlen; - } else { -# if (BYTE_ORDER == LITTLE_ENDIAN) - dirp->d_type = newent.d_namlen; - dirp->d_namlen = 0; -# else - dirp->d_type = 0; - dirp->d_namlen = newent.d_namlen; -# endif - } dirp->d_reclen = newent.d_reclen; - bcopy(idesc->id_name, dirp->d_name, (size_t)newent.d_namlen + 1); + if (newinofmt) + dirp->d_type = typemap[idesc->id_parent]; + else + dirp->d_type = 0; + dirp->d_namlen = newent.d_namlen; + memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1); +# if (BYTE_ORDER == LITTLE_ENDIAN) + /* + * If the entry was split, dirscan() will only reverse the byte + * order of the original entry, and not the new one, before + * writing it back out. So, we reverse the byte order here if + * necessary. + */ + if (oldlen != 0 && !newinofmt && !doinglevel2) { + u_char tmp; + + tmp = dirp->d_namlen; + dirp->d_namlen = dirp->d_type; + dirp->d_type = tmp; + } +# endif return (ALTERED|STOP); } -int +static int chgino(idesc) struct inodesc *idesc; { register struct direct *dirp = idesc->id_dirp; - if (bcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) + if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) return (KEEPON); dirp->d_ino = idesc->id_parent; if (newinofmt) @@ -387,7 +402,7 @@ linkup(orphan, parentdir) struct inodesc idesc; char tempname[BUFSIZ]; - bzero((char *)&idesc, sizeof(struct inodesc)); + memset(&idesc, 0, sizeof(struct inodesc)); dp = ginode(orphan); lostdir = (dp->di_mode & IFMT) == IFDIR; pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); @@ -501,7 +516,7 @@ changeino(dir, name, newnum) { struct inodesc idesc; - bzero((char *)&idesc, sizeof(struct inodesc)); + memset(&idesc, 0, sizeof(struct inodesc)); idesc.id_type = DATA; idesc.id_func = chgino; idesc.id_number = dir; @@ -526,7 +541,7 @@ makeentry(parent, ino, name) if (parent < ROOTINO || parent >= maxino || ino < ROOTINO || ino >= maxino) return (0); - bzero((char *)&idesc, sizeof(struct inodesc)); + memset(&idesc, 0, sizeof(struct inodesc)); idesc.id_type = DATA; idesc.id_func = mkentry; idesc.id_number = parent; @@ -550,12 +565,12 @@ makeentry(parent, ino, name) /* * Attempt to expand the size of a directory */ -int +static int expanddir(dp, name) register struct dinode *dp; char *name; { - daddr_t lastbn, newblk; + ufs_daddr_t lastbn, newblk; register struct bufarea *bp; char *cp, firstblk[DIRBLKSIZ]; @@ -572,21 +587,21 @@ expanddir(dp, name) (long)dblksize(&sblock, dp, lastbn + 1)); if (bp->b_errs) goto bad; - bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ); + memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ); bp = getdirblk(newblk, sblock.fs_bsize); if (bp->b_errs) goto bad; - bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ); + memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ); for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; cp < &bp->b_un.b_buf[sblock.fs_bsize]; cp += DIRBLKSIZ) - bcopy((char *)&emptydir, cp, sizeof emptydir); + memmove(cp, &emptydir, sizeof emptydir); dirty(bp); bp = getdirblk(dp->di_db[lastbn + 1], (long)dblksize(&sblock, dp, lastbn + 1)); if (bp->b_errs) goto bad; - bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir); + memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir); pwarn("NO SPACE LEFT IN %s", name); if (preen) printf(" (EXPANDED)\n"); @@ -631,11 +646,11 @@ allocdir(parent, request, mode) freeino(ino); return (0); } - bcopy((char *)dirp, bp->b_un.b_buf, sizeof(struct dirtemplate)); + memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; cp < &bp->b_un.b_buf[sblock.fs_fsize]; cp += DIRBLKSIZ) - bcopy((char *)&emptydir, cp, sizeof emptydir); + memmove(cp, &emptydir, sizeof emptydir); dirty(bp); dp->di_nlink = 2; inodirty(); @@ -680,7 +695,7 @@ freedir(ino, parent) /* * generate a temporary name for the lost+found directory. */ -int +static int lftempname(bufp, ino) char *bufp; ino_t ino; @@ -707,9 +722,9 @@ lftempname(bufp, ino) * Get a directory block. * Insure that it is held until another is requested. */ -struct bufarea * +static struct bufarea * getdirblk(blkno, size) - daddr_t blkno; + ufs_daddr_t blkno; long size; { |