must be sure to always convert b_bno to disk block (db) units
[unix-history] / usr / src / sbin / fsck / dir.c
index f9771ee..56dc498 100644 (file)
@@ -1,6 +1,12 @@
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
 #ifndef lint
 #ifndef lint
-static char version[] = "@(#)dir.c     3.10 (Berkeley) %G%";
-#endif
+static char sccsid[] = "@(#)dir.c      5.4 (Berkeley) %G%";
+#endif not lint
 
 #include <sys/param.h>
 #include <sys/inode.h>
 
 #include <sys/param.h>
 #include <sys/inode.h>
@@ -18,6 +24,7 @@ struct        dirtemplate emptydir = { 0, DIRBLKSIZ };
 struct dirtemplate dirhead = { 0, 12, 1, ".", 0, DIRBLKSIZ - 12, 2, ".." };
 
 DIRECT *fsck_readdir();
 struct dirtemplate dirhead = { 0, 12, 1, ".", 0, DIRBLKSIZ - 12, 2, ".." };
 
 DIRECT *fsck_readdir();
+BUFAREA        *getdirblk();
 
 descend(parentino, inumber)
        struct inodesc *parentino;
 
 descend(parentino, inumber)
        struct inodesc *parentino;
@@ -43,17 +50,32 @@ descend(parentino, inumber)
                if (reply("FIX") == 1)
                        inodirty();
        }
                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);
        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;
+       }
 }
 
 dirscan(idesc)
        register struct inodesc *idesc;
 {
        register DIRECT *dp;
 }
 
 dirscan(idesc)
        register struct inodesc *idesc;
 {
        register DIRECT *dp;
+       register BUFAREA *bp;
        int dsize, n;
        long blksiz;
        char dbuf[DIRBLKSIZ];
        int dsize, n;
        long blksiz;
        char dbuf[DIRBLKSIZ];
@@ -74,12 +96,10 @@ dirscan(idesc)
                bcopy((char *)dp, dbuf, dsize);
                idesc->id_dirp = (DIRECT *)dbuf;
                if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
                bcopy((char *)dp, dbuf, dsize);
                idesc->id_dirp = (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;
+                       bp = getdirblk(idesc->id_blkno, blksiz);
+                       bcopy(dbuf, (char *)dp, dsize);
+                       dirty(bp);
+                       sbdirty();
                }
                if (n & STOP) 
                        return (n);
                }
                if (n & STOP) 
                        return (n);
@@ -95,16 +115,14 @@ fsck_readdir(idesc)
        register struct inodesc *idesc;
 {
        register DIRECT *dp, *ndp;
        register struct inodesc *idesc;
 {
        register DIRECT *dp, *ndp;
+       register BUFAREA *bp;
        long size, blksiz;
 
        blksiz = idesc->id_numfrags * sblock.fs_fsize;
        long size, blksiz;
 
        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) {
        if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
            idesc->id_loc < blksiz) {
-               dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
+               dp = (DIRECT *)(bp->b_un.b_buf + idesc->id_loc);
                if (dircheck(idesc, dp))
                        goto dpok;
                idesc->id_loc += DIRBLKSIZ;
                if (dircheck(idesc, dp))
                        goto dpok;
                idesc->id_loc += DIRBLKSIZ;
@@ -114,18 +132,18 @@ fsck_readdir(idesc)
                dp->d_namlen = 0;
                dp->d_name[0] = '\0';
                if (dofix(idesc, "DIRECTORY CORRUPTED"))
                dp->d_namlen = 0;
                dp->d_name[0] = '\0';
                if (dofix(idesc, "DIRECTORY CORRUPTED"))
-                       dirty(&fileblk);
+                       dirty(bp);
                return (dp);
        }
 dpok:
        if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
                return NULL;
                return (dp);
        }
 dpok:
        if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
                return NULL;
-       dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
+       dp = (DIRECT *)(bp->b_un.b_buf + idesc->id_loc);
        idesc->id_loc += dp->d_reclen;
        idesc->id_filesize -= dp->d_reclen;
        if ((idesc->id_loc % DIRBLKSIZ) == 0)
                return (dp);
        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 = (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);
        if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
            dircheck(idesc, ndp) == 0) {
                size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
@@ -133,7 +151,7 @@ dpok:
                idesc->id_loc += size;
                idesc->id_filesize -= size;
                if (dofix(idesc, "DIRECTORY CORRUPTED"))
                idesc->id_loc += size;
                idesc->id_filesize -= size;
                if (dofix(idesc, "DIRECTORY CORRUPTED"))
-                       dirty(&fileblk);
+                       dirty(bp);
        }
        return (dp);
 }
        }
        return (dp);
 }
@@ -288,8 +306,7 @@ linkup(orphan, pdir)
                idesc.id_type = DATA;
                idesc.id_func = findino;
                idesc.id_number = ROOTINO;
                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");
                        lfdir = idesc.id_parent;
                } else {
                        pwarn("NO lost+found DIRECTORY");
@@ -356,7 +373,7 @@ linkup(orphan, pdir)
        }
        lncntp[orphan]--;
        *pathp++ = '/';
        }
        lncntp[orphan]--;
        *pathp++ = '/';
-       bcopy(idesc.id_name, pathp, len + 1);
+       bcopy(tempname, pathp, len + 1);
        pathp += len;
        if (lostdir) {
                dp = ginode(orphan);
        pathp += len;
        if (lostdir) {
                dp = ginode(orphan);
@@ -417,6 +434,7 @@ expanddir(dp)
        register DINODE *dp;
 {
        daddr_t lastbn, newblk;
        register DINODE *dp;
 {
        daddr_t lastbn, newblk;
+       register BUFAREA *bp;
        char *cp, firstblk[DIRBLKSIZ];
 
        lastbn = lblkno(&sblock, dp->di_size);
        char *cp, firstblk[DIRBLKSIZ];
 
        lastbn = lblkno(&sblock, dp->di_size);
@@ -428,28 +446,31 @@ expanddir(dp)
        dp->di_db[lastbn] = newblk;
        dp->di_size += sblock.fs_bsize;
        dp->di_blocks += btodb(sblock.fs_bsize);
        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],
+               dblksize(&sblock, dp, lastbn + 1));
+       if (bp->b_errs != NULL)
                goto bad;
                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 != NULL)
                goto bad;
                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);
             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],
+               dblksize(&sblock, dp, lastbn + 1));
+       if (bp->b_errs != NULL)
                goto bad;
                goto bad;
-       bcopy((char *)&emptydir, dirblk.b_buf, sizeof emptydir);
+       bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir);
        pwarn("NO SPACE LEFT IN %s", pathname);
        if (preen)
                printf(" (EXPANDED)\n");
        else if (reply("EXPAND") == 0)
                goto bad;
        pwarn("NO SPACE LEFT IN %s", pathname);
        if (preen)
                printf(" (EXPANDED)\n");
        else if (reply("EXPAND") == 0)
                goto bad;
-       dirty(&fileblk);
+       dirty(bp);
        inodirty();
        return (1);
 bad:
        inodirty();
        return (1);
 bad:
@@ -470,21 +491,23 @@ allocdir(parent, request)
        ino_t ino;
        char *cp;
        DINODE *dp;
        ino_t ino;
        char *cp;
        DINODE *dp;
+       register BUFAREA *bp;
 
        ino = allocino(request, IFDIR|0755);
        dirhead.dot_ino = ino;
        dirhead.dotdot_ino = parent;
        dp = ginode(ino);
 
        ino = allocino(request, IFDIR|0755);
        dirhead.dot_ino = ino;
        dirhead.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 != NULL) {
                freeino(ino);
                return (0);
        }
                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 *)&dirhead, bp->b_un.b_buf, sizeof dirhead);
+       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);
             cp += DIRBLKSIZ)
                bcopy((char *)&emptydir, cp, sizeof emptydir);
-       dirty(&fileblk);
+       dirty(bp);
        dp->di_nlink = 2;
        inodirty();
        if (ino == ROOTINO) {
        dp->di_nlink = 2;
        inodirty();
        if (ino == ROOTINO) {
@@ -546,3 +569,20 @@ lftempname(bufp, ino)
        *cp = '#';
        return (namlen);
 }
        *cp = '#';
        return (namlen);
 }
+
+/*
+ * Get a directory block.
+ * Insure that it is held until another is requested.
+ */
+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);
+}