X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/ca1a30be70c8c866d5b3a0387f6f4b538f56e706..ad7871609881e73855d0b04da49b486cd93efca7:/usr/src/sbin/fsck/dir.c diff --git a/usr/src/sbin/fsck/dir.c b/usr/src/sbin/fsck/dir.c index c93341aa0e..ee5d095e6c 100644 --- a/usr/src/sbin/fsck/dir.c +++ b/usr/src/sbin/fsck/dir.c @@ -1,82 +1,143 @@ +/* + * Copyright (c) 1980, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + #ifndef lint -static char version[] = "@(#)dir.c 3.9 (Berkeley) %G%"; -#endif +static char sccsid[] = "@(#)dir.c 8.1 (Berkeley) 6/5/93"; +#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, ".." }; +struct dirtemplate dirhead = { + 0, 12, DT_DIR, 1, ".", + 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." +}; +struct odirtemplate odirhead = { + 0, 12, 1, ".", + 0, DIRBLKSIZ - 12, 2, ".." +}; -DIRECT *fsck_readdir(); +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(); - } - curino.id_type = DATA; - curino.id_func = parentino->id_func; - curino.id_parent = parentino->id_number; - curino.id_number = inumber; - (void)ckinode(dp, &curino); + 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 struct direct *dp; + register struct bufarea *bp; int dsize, n; long blksiz; char dbuf[DIRBLKSIZ]; if (idesc->id_type != DATA) errexit("wrong type to dirscan %d\n", idesc->id_type); + if (idesc->id_entryno == 0 && + (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 (getblk(&fileblk, idesc->id_blkno, blksiz) != NULL) { - bcopy(dbuf, (char *)dp, dsize); - dirty(&fileblk); - sbdirty(); - } else - n &= ~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, bp->b_un.b_buf + idesc->id_loc - dsize, + (size_t)dsize); + dirty(bp); + sbdirty(); } if (n & STOP) return (n); @@ -87,50 +148,56 @@ dirscan(idesc) /* * get next entry in a directory. */ -DIRECT * +struct direct * fsck_readdir(idesc) register struct inodesc *idesc; { - register DIRECT *dp, *ndp; - long size, blksiz; + register struct direct *dp, *ndp; + register struct bufarea *bp; + long size, blksiz, fix, dploc; blksiz = idesc->id_numfrags * sblock.fs_fsize; - if (getblk(&fileblk, idesc->id_blkno, blksiz) == NULL) { - idesc->id_filesize -= blksiz - idesc->id_loc; - return NULL; - } + bp = getdirblk(idesc->id_blkno, blksiz); if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && idesc->id_loc < blksiz) { - dp = (DIRECT *)(dirblk.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")) - dirty(&fileblk); + 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 *)(dirblk.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 *)(dirblk.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")) - dirty(&fileblk); + 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); } @@ -141,25 +208,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); @@ -167,31 +248,42 @@ dircheck(idesc, dp) return (0); } -direrr(ino, s) +direrror(ino, errmesg) ino_t ino; - char *s; + char *errmesg; +{ + + fileerror(ino, ino, errmesg); +} + +fileerror(cwd, ino, errmesg) + ino_t cwd, ino; + char *errmesg; { - register DINODE *dp; + register struct dinode *dp; + char pathbuf[MAXPATHLEN + 1]; - pwarn("%s ", s); + 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) { @@ -199,10 +291,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"); @@ -220,14 +312,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) @@ -236,29 +328,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]; @@ -266,7 +366,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) @@ -276,22 +376,18 @@ 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; idesc.id_type = DATA; idesc.id_func = findino; idesc.id_number = ROOTINO; - (void)ckinode(dp, &idesc); - if (idesc.id_parent >= ROOTINO && idesc.id_parent < imax) { + if ((ckinode(dp, &idesc) & FOUND) != 0) { lfdir = idesc.id_parent; } else { pwarn("NO lost+found DIRECTORY"); if (preen || reply("CREATE")) { - lfdir = allocdir(ROOTINO, 0); + lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); if (lfdir != 0) { if (makeentry(ROOTINO, lfdir, lfname) != 0) { if (preen) @@ -312,21 +408,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)) == 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); } @@ -342,44 +433,50 @@ linkup(orphan, pdir) pfatal("SORRY. NO lost+found DIRECTORY\n\n"); return (0); } - if (dp->di_size % DIRBLKSIZ) { - dp->di_size = roundup(dp->di_size, DIRBLKSIZ); - inodirty(); - } - 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(idesc.id_name, 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 */ @@ -387,12 +484,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; @@ -400,9 +499,15 @@ makeentry(parent, ino, name) idesc.id_fix = DONTKNOW; idesc.id_name = name; dp = ginode(parent); + if (dp->di_size % DIRBLKSIZ) { + dp->di_size = roundup(dp->di_size, DIRBLKSIZ); + inodirty(); + } 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); } @@ -410,14 +515,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 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); @@ -425,28 +532,31 @@ expanddir(dp) dp->di_db[lastbn] = newblk; dp->di_size += sblock.fs_bsize; dp->di_blocks += btodb(sblock.fs_bsize); - if (getblk(&fileblk, dp->di_db[lastbn + 1], - dblksize(&sblock, dp, lastbn + 1)) == NULL) + bp = getdirblk(dp->di_db[lastbn + 1], + (long)dblksize(&sblock, dp, lastbn + 1)); + if (bp->b_errs) goto bad; - bcopy(dirblk.b_buf, firstblk, DIRBLKSIZ); - if (getblk(&fileblk, newblk, sblock.fs_bsize) == NULL) + bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ); + bp = getdirblk(newblk, sblock.fs_bsize); + if (bp->b_errs) goto bad; - bcopy(firstblk, dirblk.b_buf, DIRBLKSIZ); - for (cp = &dirblk.b_buf[DIRBLKSIZ]; - cp < &dirblk.b_buf[sblock.fs_bsize]; + bcopy(firstblk, bp->b_un.b_buf, 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); - dirty(&fileblk); - if (getblk(&fileblk, dp->di_db[lastbn + 1], - dblksize(&sblock, dp, lastbn + 1)) == NULL) + dirty(bp); + bp = getdirblk(dp->di_db[lastbn + 1], + (long)dblksize(&sblock, dp, lastbn + 1)); + if (bp->b_errs) goto bad; - bcopy((char *)&emptydir, dirblk.b_buf, sizeof emptydir); - pwarn("NO SPACE LEFT IN %s", pathname); + bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir); + pwarn("NO SPACE LEFT IN %s", name); if (preen) printf(" (EXPANDED)\n"); else if (reply("EXPAND") == 0) goto bad; - dirty(&fileblk); + dirty(bp); inodirty(); return (1); bad: @@ -461,37 +571,47 @@ bad: /* * allocate a new directory */ -allocdir(parent, request) +allocdir(parent, request, mode) ino_t parent, request; + int mode; { ino_t ino; char *cp; - DINODE *dp; + struct dinode *dp; + register struct bufarea *bp; + struct dirtemplate *dirp; - ino = allocino(request, IFDIR|0755); - dirhead.dot_ino = ino; - dirhead.dotdot_ino = parent; + ino = allocino(request, IFDIR|mode); + if (newinofmt) + dirp = &dirhead; + else + dirp = (struct dirtemplate *)&odirhead; + dirp->dot_ino = ino; + dirp->dotdot_ino = parent; dp = ginode(ino); - if (getblk(&fileblk, dp->di_db[0], sblock.fs_fsize) == NULL) { + bp = getdirblk(dp->di_db[0], sblock.fs_fsize); + if (bp->b_errs) { freeino(ino); return (0); } - bcopy((char *)&dirhead, dirblk.b_buf, sizeof dirhead); - for (cp = &dirblk.b_buf[DIRBLKSIZ]; - cp < &dirblk.b_buf[sblock.fs_fsize]; + 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) bcopy((char *)&emptydir, cp, sizeof emptydir); - dirty(&fileblk); + dirty(bp); dp->di_nlink = 2; 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; @@ -509,7 +629,7 @@ allocdir(parent, request) freedir(ino, parent) ino_t ino, parent; { - DINODE *dp; + struct dinode *dp; if (ino != parent) { dp = ginode(parent); @@ -531,7 +651,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; @@ -543,3 +663,19 @@ lftempname(bufp, ino) *cp = '#'; return (namlen); } + +/* + * Get a directory block. + * Insure that it is held until another is requested. + */ +struct bufarea * +getdirblk(blkno, size) + daddr_t blkno; + long size; +{ + + if (pdirbp != 0) + pdirbp->b_flags &= ~B_INUSE; + pdirbp = getdatablk(blkno, size); + return (pdirbp); +}