X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/c689da7bea2208e85ab909b29e378c051d0f410a..94cf96fde7c78a95aa79a403aa093bffb3504b59:/usr/src/sbin/fsck/dir.c diff --git a/usr/src/sbin/fsck/dir.c b/usr/src/sbin/fsck/dir.c index 1e8ce07086..1500365cd1 100644 --- a/usr/src/sbin/fsck/dir.c +++ b/usr/src/sbin/fsck/dir.c @@ -1,82 +1,71 @@ /* - * Copyright (c) 1980 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. + * Copyright (c) 1980, 1986 The Regents of the University of California. + * All rights reserved. + * + * %sccs.include.redist.c% */ #ifndef lint -static char sccsid[] = "@(#)dir.c 5.5 (Berkeley) %G%"; -#endif not lint +static char sccsid[] = "@(#)dir.c 5.24 (Berkeley) %G%"; +#endif /* not lint */ #include -#include -#include -#define KERNEL -#include -#undef KERNEL +#include +#include +#include +#include +#include +#include #include "fsck.h" -#define MINDIRSIZE (sizeof (struct dirtemplate)) - -char *endpathname = &pathname[BUFSIZ - 2]; char *lfname = "lost+found"; int lfmode = 01777; struct dirtemplate emptydir = { 0, DIRBLKSIZ }; -struct dirtemplate dirhead = { 0, 12, 1, ".", 0, DIRBLKSIZ - 12, 2, ".." }; - -DIRECT *fsck_readdir(); -BUFAREA *getdirblk(); +struct dirtemplate dirhead = { + 0, 12, DT_DIR, 1, ".", + 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." +}; +struct odirtemplate odirhead = { + 0, 12, 1, ".", + 0, DIRBLKSIZ - 12, 2, ".." +}; + +struct direct *fsck_readdir(); +struct bufarea *getdirblk(); -descend(parentino, inumber) - struct inodesc *parentino; - ino_t inumber; +/* + * Propagate connected state through the tree. + */ +propagate() { - register DINODE *dp; - struct inodesc curino; - - bzero((char *)&curino, sizeof(struct inodesc)); - if (statemap[inumber] != DSTATE) - errexit("BAD INODE %d TO DESCEND", statemap[inumber]); - statemap[inumber] = DFOUND; - dp = ginode(inumber); - if (dp->di_size == 0) { - direrr(inumber, "ZERO LENGTH DIRECTORY"); - if (reply("REMOVE") == 1) - statemap[inumber] = DCLEAR; - return; - } - if (dp->di_size < MINDIRSIZE) { - direrr(inumber, "DIRECTORY TOO SHORT"); - dp->di_size = MINDIRSIZE; - if (reply("FIX") == 1) - inodirty(); - } - if ((dp->di_size & (DIRBLKSIZ - 1)) != 0) { - pwarn("DIRECTORY %s: LENGTH %d NOT MULTIPLE OF %d", - pathname, dp->di_size, DIRBLKSIZ); - dp->di_size = roundup(dp->di_size, DIRBLKSIZ); - if (preen) - printf(" (ADJUSTED)\n"); - if (preen || reply("ADJUST") == 1) - inodirty(); - } - curino.id_type = DATA; - curino.id_func = parentino->id_func; - curino.id_parent = parentino->id_number; - curino.id_number = inumber; - (void)ckinode(dp, &curino); - if (curino.id_entryno < 2) { - direrr(inumber, "NULL DIRECTORY"); - if (reply("REMOVE") == 1) - statemap[inumber] = DCLEAR; - } + register struct inoinfo **inpp, *inp; + struct inoinfo **inpend; + long change; + + inpend = &inpsort[inplast]; + do { + change = 0; + for (inpp = inpsort; inpp < inpend; inpp++) { + inp = *inpp; + if (inp->i_parent == 0) + continue; + if (statemap[inp->i_parent] == DFOUND && + statemap[inp->i_number] == DSTATE) { + statemap[inp->i_number] = DFOUND; + change++; + } + } + } while (change > 0); } +/* + * Scan each entry in a directory block. + */ dirscan(idesc) register struct inodesc *idesc; { - register DIRECT *dp; - register BUFAREA *bp; + register struct direct *dp; + register struct bufarea *bp; int dsize, n; long blksiz; char dbuf[DIRBLKSIZ]; @@ -87,18 +76,40 @@ dirscan(idesc) (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); blksiz = idesc->id_numfrags * sblock.fs_fsize; - if (outrange(idesc->id_blkno, idesc->id_numfrags)) { + if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { idesc->id_filesize -= blksiz; return (SKIP); } idesc->id_loc = 0; for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { dsize = dp->d_reclen; - bcopy((char *)dp, dbuf, dsize); - idesc->id_dirp = (DIRECT *)dbuf; + bcopy((char *)dp, dbuf, (size_t)dsize); +# if (BYTE_ORDER == LITTLE_ENDIAN) + if (!newinofmt) { + struct direct *tdp = (struct direct *)dbuf; + u_char tmp; + + tmp = tdp->d_namlen; + tdp->d_namlen = tdp->d_type; + tdp->d_type = tmp; + } +# endif + idesc->id_dirp = (struct direct *)dbuf; if ((n = (*idesc->id_func)(idesc)) & ALTERED) { +# if (BYTE_ORDER == LITTLE_ENDIAN) + if (!newinofmt && !doinglevel2) { + struct direct *tdp; + u_char tmp; + + tdp = (struct direct *)dbuf; + tmp = tdp->d_namlen; + tdp->d_namlen = tdp->d_type; + tdp->d_type = tmp; + } +# endif bp = getdirblk(idesc->id_blkno, blksiz); - bcopy(dbuf, (char *)dp, dsize); + bcopy(dbuf, bp->b_un.b_buf + idesc->id_loc - dsize, + (size_t)dsize); dirty(bp); sbdirty(); } @@ -111,47 +122,55 @@ dirscan(idesc) /* * get next entry in a directory. */ -DIRECT * +struct direct * fsck_readdir(idesc) register struct inodesc *idesc; { - register DIRECT *dp, *ndp; - register BUFAREA *bp; - long size, blksiz; + register struct direct *dp, *ndp; + register struct bufarea *bp; + long size, blksiz, fix, dploc; blksiz = idesc->id_numfrags * sblock.fs_fsize; bp = getdirblk(idesc->id_blkno, blksiz); if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && idesc->id_loc < blksiz) { - dp = (DIRECT *)(bp->b_un.b_buf + idesc->id_loc); + dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); if (dircheck(idesc, dp)) goto dpok; - idesc->id_loc += DIRBLKSIZ; - idesc->id_filesize -= DIRBLKSIZ; + fix = dofix(idesc, "DIRECTORY CORRUPTED"); + bp = getdirblk(idesc->id_blkno, blksiz); + dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); dp->d_reclen = DIRBLKSIZ; dp->d_ino = 0; + dp->d_type = 0; dp->d_namlen = 0; dp->d_name[0] = '\0'; - if (dofix(idesc, "DIRECTORY CORRUPTED")) + if (fix) dirty(bp); + idesc->id_loc += DIRBLKSIZ; + idesc->id_filesize -= DIRBLKSIZ; return (dp); } dpok: if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) return NULL; - dp = (DIRECT *)(bp->b_un.b_buf + idesc->id_loc); + dploc = idesc->id_loc; + dp = (struct direct *)(bp->b_un.b_buf + dploc); idesc->id_loc += dp->d_reclen; idesc->id_filesize -= dp->d_reclen; if ((idesc->id_loc % DIRBLKSIZ) == 0) return (dp); - ndp = (DIRECT *)(bp->b_un.b_buf + idesc->id_loc); + ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && dircheck(idesc, ndp) == 0) { size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); - dp->d_reclen += size; idesc->id_loc += size; idesc->id_filesize -= size; - if (dofix(idesc, "DIRECTORY CORRUPTED")) + fix = dofix(idesc, "DIRECTORY CORRUPTED"); + bp = getdirblk(idesc->id_blkno, blksiz); + dp = (struct direct *)(bp->b_un.b_buf + dploc); + dp->d_reclen += size; + if (fix) dirty(bp); } return (dp); @@ -163,25 +182,39 @@ dpok: */ dircheck(idesc, dp) struct inodesc *idesc; - register DIRECT *dp; + register struct direct *dp; { register int size; register char *cp; + u_char namlen, type; int spaceleft; - size = DIRSIZ(dp); + size = DIRSIZ(!newinofmt, dp); spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); - if (dp->d_ino < imax && +# if (BYTE_ORDER == LITTLE_ENDIAN) + if (!newinofmt) { + type = dp->d_namlen; + namlen = dp->d_type; + } else { + namlen = dp->d_namlen; + type = dp->d_type; + } +# else + 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 && - dp->d_namlen <= MAXNAMLEN) { + namlen <= MAXNAMLEN && + type <= 15) { if (dp->d_ino == 0) return (1); - for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++) - if (*cp == 0 || (*cp++ & 0200)) + for (cp = dp->d_name, size = 0; size < namlen; size++) + if (*cp == 0 || (*cp++ == '/')) return (0); if (*cp == 0) return (1); @@ -189,31 +222,42 @@ dircheck(idesc, dp) return (0); } -direrr(ino, s) +direrror(ino, errmesg) ino_t ino; - char *s; + char *errmesg; { - register DINODE *dp; - pwarn("%s ", s); + fileerror(ino, ino, errmesg); +} + +fileerror(cwd, ino, errmesg) + ino_t cwd, ino; + char *errmesg; +{ + register struct dinode *dp; + char pathbuf[MAXPATHLEN + 1]; + + pwarn("%s ", errmesg); pinode(ino); printf("\n"); - if (ino < ROOTINO || ino > imax) { - pfatal("NAME=%s\n", pathname); + getpathname(pathbuf, cwd, ino); + if (ino < ROOTINO || ino > maxino) { + pfatal("NAME=%s\n", pathbuf); return; } dp = ginode(ino); if (ftypeok(dp)) - pfatal("%s=%s\n", DIRCT(dp) ? "DIR" : "FILE", pathname); + pfatal("%s=%s\n", + (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); else - pfatal("NAME=%s\n", pathname); + pfatal("NAME=%s\n", pathbuf); } adjust(idesc, lcnt) register struct inodesc *idesc; short lcnt; { - register DINODE *dp; + register struct dinode *dp; dp = ginode(idesc->id_number); if (dp->di_nlink == lcnt) { @@ -221,10 +265,10 @@ adjust(idesc, lcnt) clri(idesc, "UNREF", 0); } else { pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : - (DIRCT(dp) ? "DIR" : "FILE")); + ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); pinode(idesc->id_number); printf(" COUNT %d SHOULD BE %d", - dp->di_nlink, dp->di_nlink-lcnt); + dp->di_nlink, dp->di_nlink - lcnt); if (preen) { if (lcnt < 0) { printf("\n"); @@ -242,14 +286,14 @@ adjust(idesc, lcnt) mkentry(idesc) struct inodesc *idesc; { - register DIRECT *dirp = idesc->id_dirp; - DIRECT newent; + register struct direct *dirp = idesc->id_dirp; + struct direct newent; int newlen, oldlen; - newent.d_namlen = 11; - newlen = DIRSIZ(&newent); + newent.d_namlen = strlen(idesc->id_name); + newlen = DIRSIZ(0, &newent); if (dirp->d_ino != 0) - oldlen = DIRSIZ(dirp); + oldlen = DIRSIZ(0, dirp); else oldlen = 0; if (dirp->d_reclen - oldlen < newlen) @@ -258,29 +302,37 @@ 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]; + else + dirp->d_type = 0; dirp->d_reclen = newent.d_reclen; - dirp->d_namlen = strlen(idesc->id_name); - bcopy(idesc->id_name, dirp->d_name, dirp->d_namlen + 1); + dirp->d_namlen = newent.d_namlen; + bcopy(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1); return (ALTERED|STOP); } chgino(idesc) struct inodesc *idesc; { - register DIRECT *dirp = idesc->id_dirp; + register struct direct *dirp = idesc->id_dirp; - if (bcmp(dirp->d_name, idesc->id_name, dirp->d_namlen + 1)) + if (bcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) return (KEEPON); - dirp->d_ino = idesc->id_parent;; + dirp->d_ino = idesc->id_parent; + if (newinofmt) + dirp->d_type = typemap[idesc->id_parent]; + else + dirp->d_type = 0; return (ALTERED|STOP); } -linkup(orphan, pdir) +linkup(orphan, parentdir) ino_t orphan; - ino_t pdir; + ino_t parentdir; { - register DINODE *dp; - int lostdir, len; + register struct dinode *dp; + int lostdir; ino_t oldlfdir; struct inodesc idesc; char tempname[BUFSIZ]; @@ -288,7 +340,7 @@ linkup(orphan, pdir) bzero((char *)&idesc, sizeof(struct inodesc)); dp = ginode(orphan); - lostdir = DIRCT(dp); + lostdir = (dp->di_mode & IFMT) == IFDIR; pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); pinode(orphan); if (preen && dp->di_size == 0) @@ -298,9 +350,6 @@ linkup(orphan, pdir) else if (reply("RECONNECT") == 0) return (0); - pathp = pathname; - *pathp++ = '/'; - *pathp = '\0'; if (lfdir == 0) { dp = ginode(ROOTINO); idesc.id_name = lfname; @@ -312,7 +361,7 @@ linkup(orphan, pdir) } else { pwarn("NO lost+found DIRECTORY"); if (preen || reply("CREATE")) { - lfdir = allocdir(ROOTINO, 0, lfmode); + lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); if (lfdir != 0) { if (makeentry(ROOTINO, lfdir, lfname) != 0) { if (preen) @@ -333,21 +382,16 @@ linkup(orphan, pdir) } } dp = ginode(lfdir); - if (!DIRCT(dp)) { + if ((dp->di_mode & IFMT) != IFDIR) { pfatal("lost+found IS NOT A DIRECTORY"); if (reply("REALLOCATE") == 0) return (0); oldlfdir = lfdir; - if ((lfdir = allocdir(ROOTINO, 0, lfmode)) == 0) { + if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); return (0); } - idesc.id_type = DATA; - idesc.id_func = chgino; - idesc.id_number = ROOTINO; - idesc.id_parent = lfdir; /* new inumber for lost+found */ - idesc.id_name = lfname; - if ((ckinode(ginode(ROOTINO), &idesc) & ALTERED) == 0) { + if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); return (0); } @@ -363,40 +407,50 @@ linkup(orphan, pdir) pfatal("SORRY. NO lost+found DIRECTORY\n\n"); return (0); } - len = strlen(lfname); - bcopy(lfname, pathp, len + 1); - pathp += len; - len = lftempname(tempname, orphan); + (void)lftempname(tempname, orphan); if (makeentry(lfdir, orphan, tempname) == 0) { pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); printf("\n\n"); return (0); } lncntp[orphan]--; - *pathp++ = '/'; - bcopy(tempname, pathp, len + 1); - pathp += len; if (lostdir) { - dp = ginode(orphan); - idesc.id_type = DATA; - idesc.id_func = chgino; - idesc.id_number = orphan; - idesc.id_fix = DONTKNOW; - idesc.id_name = ".."; - idesc.id_parent = lfdir; /* new value for ".." */ - (void)ckinode(dp, &idesc); + if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && + parentdir != (ino_t)-1) + (void)makeentry(orphan, lfdir, ".."); dp = ginode(lfdir); dp->di_nlink++; inodirty(); lncntp[lfdir]++; - pwarn("DIR I=%u CONNECTED. ", orphan); - printf("PARENT WAS I=%u\n", pdir); + pwarn("DIR I=%lu CONNECTED. ", orphan); + if (parentdir != (ino_t)-1) + printf("PARENT WAS I=%lu\n", parentdir); if (preen == 0) printf("\n"); } return (1); } +/* + * fix an entry in a directory. + */ +changeino(dir, name, newnum) + ino_t dir; + char *name; + ino_t newnum; +{ + struct inodesc idesc; + + bzero((char *)&idesc, sizeof(struct inodesc)); + idesc.id_type = DATA; + idesc.id_func = chgino; + idesc.id_number = dir; + idesc.id_fix = DONTKNOW; + idesc.id_name = name; + idesc.id_parent = newnum; /* new value for name */ + return (ckinode(ginode(dir), &idesc)); +} + /* * make an entry in a directory */ @@ -404,12 +458,14 @@ makeentry(parent, ino, name) ino_t parent, ino; char *name; { - DINODE *dp; + struct dinode *dp; struct inodesc idesc; + char pathbuf[MAXPATHLEN + 1]; - if (parent < ROOTINO || parent >= imax || ino < ROOTINO || ino >= imax) + if (parent < ROOTINO || parent >= maxino || + ino < ROOTINO || ino >= maxino) return (0); - bzero(&idesc, sizeof(struct inodesc)); + bzero((char *)&idesc, sizeof(struct inodesc)); idesc.id_type = DATA; idesc.id_func = mkentry; idesc.id_number = parent; @@ -423,7 +479,9 @@ makeentry(parent, ino, name) } if ((ckinode(dp, &idesc) & ALTERED) != 0) return (1); - if (expanddir(dp) == 0) + getpathname(pathbuf, parent, parent); + dp = ginode(parent); + if (expanddir(dp, pathbuf) == 0) return (0); return (ckinode(dp, &idesc) & ALTERED); } @@ -431,15 +489,16 @@ makeentry(parent, ino, name) /* * Attempt to expand the size of a directory */ -expanddir(dp) - register DINODE *dp; +expanddir(dp, name) + register struct dinode *dp; + char *name; { daddr_t lastbn, newblk; - register BUFAREA *bp; + register struct bufarea *bp; char *cp, firstblk[DIRBLKSIZ]; lastbn = lblkno(&sblock, dp->di_size); - if (lastbn >= NDADDR - 1) + if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) return (0); if ((newblk = allocblk(sblock.fs_frag)) == 0) return (0); @@ -448,12 +507,12 @@ expanddir(dp) dp->di_size += sblock.fs_bsize; dp->di_blocks += btodb(sblock.fs_bsize); bp = getdirblk(dp->di_db[lastbn + 1], - dblksize(&sblock, dp, lastbn + 1)); - if (bp->b_errs != NULL) + (long)dblksize(&sblock, dp, lastbn + 1)); + if (bp->b_errs) goto bad; bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ); bp = getdirblk(newblk, sblock.fs_bsize); - if (bp->b_errs != NULL) + if (bp->b_errs) goto bad; bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ); for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; @@ -462,11 +521,11 @@ expanddir(dp) bcopy((char *)&emptydir, cp, sizeof emptydir); dirty(bp); bp = getdirblk(dp->di_db[lastbn + 1], - dblksize(&sblock, dp, lastbn + 1)); - if (bp->b_errs != NULL) + (long)dblksize(&sblock, dp, lastbn + 1)); + if (bp->b_errs) goto bad; bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir); - pwarn("NO SPACE LEFT IN %s", pathname); + pwarn("NO SPACE LEFT IN %s", name); if (preen) printf(" (EXPANDED)\n"); else if (reply("EXPAND") == 0) @@ -492,19 +551,24 @@ allocdir(parent, request, mode) { ino_t ino; char *cp; - DINODE *dp; - register BUFAREA *bp; + struct dinode *dp; + register struct bufarea *bp; + struct dirtemplate *dirp; ino = allocino(request, IFDIR|mode); - dirhead.dot_ino = ino; - dirhead.dotdot_ino = parent; + if (newinofmt) + dirp = &dirhead; + else + dirp = (struct dirtemplate *)&odirhead; + dirp->dot_ino = ino; + dirp->dotdot_ino = parent; dp = ginode(ino); bp = getdirblk(dp->di_db[0], sblock.fs_fsize); - if (bp->b_errs != NULL) { + if (bp->b_errs) { freeino(ino); return (0); } - bcopy((char *)&dirhead, bp->b_un.b_buf, sizeof dirhead); + bcopy((char *)dirp, bp->b_un.b_buf, sizeof(struct dirtemplate)); for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; cp < &bp->b_un.b_buf[sblock.fs_fsize]; cp += DIRBLKSIZ) @@ -514,12 +578,14 @@ allocdir(parent, request, mode) inodirty(); if (ino == ROOTINO) { lncntp[ino] = dp->di_nlink; + cacheino(dp, ino); return(ino); } if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { freeino(ino); return (0); } + cacheino(dp, ino); statemap[ino] = statemap[parent]; if (statemap[ino] == DSTATE) { lncntp[ino] = dp->di_nlink; @@ -537,7 +603,7 @@ allocdir(parent, request, mode) freedir(ino, parent) ino_t ino, parent; { - DINODE *dp; + struct dinode *dp; if (ino != parent) { dp = ginode(parent); @@ -559,7 +625,7 @@ lftempname(bufp, ino) int namlen; cp = bufp + 2; - for (in = imax; in > 0; in /= 10) + for (in = maxino; in > 0; in /= 10) cp++; *--cp = 0; namlen = cp - bufp; @@ -576,15 +642,14 @@ lftempname(bufp, ino) * Get a directory block. * Insure that it is held until another is requested. */ -BUFAREA * +struct bufarea * getdirblk(blkno, size) daddr_t blkno; long size; { - static BUFAREA *pbp = 0; - if (pbp != 0) - pbp->b_flags &= ~B_INUSE; - pbp = getdatablk(blkno, size); - return (pbp); + if (pdirbp != 0) + pdirbp->b_flags &= ~B_INUSE; + pdirbp = getdatablk(blkno, size); + return (pdirbp); }