do not have to have alternate superblock if -b is specified
[unix-history] / usr / src / sbin / fsck / dir.c
index 6191d14..52119d1 100644 (file)
@@ -2,34 +2,23 @@
  * Copyright (c) 1980, 1986 The Regents of the University of California.
  * All rights reserved.
  *
  * Copyright (c) 1980, 1986 The Regents of the University of California.
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * %sccs.include.redist.c%
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)dir.c      5.10 (Berkeley) %G%";
+static char sccsid[] = "@(#)dir.c      5.20 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/param.h>
 #endif /* not lint */
 
 #include <sys/param.h>
-#include <ufs/dinode.h>
-#include <ufs/fs.h>
+#include <ufs/ufs/dinode.h>
 #define KERNEL
 #define KERNEL
-#include <ufs/dir.h>
+#include <ufs/ufs/dir.h>
 #undef KERNEL
 #undef KERNEL
+#include <ufs/ffs/fs.h>
+#include <stdlib.h>
+#include <string.h>
 #include "fsck.h"
 
 #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 };
 char   *lfname = "lost+found";
 int    lfmode = 01777;
 struct dirtemplate emptydir = { 0, DIRBLKSIZ };
@@ -38,51 +27,34 @@ struct      dirtemplate dirhead = { 0, 12, 1, ".", 0, DIRBLKSIZ - 12, 2, ".." };
 struct direct  *fsck_readdir();
 struct bufarea *getdirblk();
 
 struct direct  *fsck_readdir();
 struct bufarea *getdirblk();
 
-descend(parentino, inumber)
-       struct inodesc *parentino;
-       ino_t inumber;
+/*
+ * Propagate connected state through the tree.
+ */
+propagate()
 {
 {
-       register struct 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) {
-               direrror(inumber, "ZERO LENGTH DIRECTORY");
-               if (reply("REMOVE") == 1)
-                       statemap[inumber] = DCLEAR;
-               return;
-       }
-       if (dp->di_size < MINDIRSIZE) {
-               direrror(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) {
-               direrror(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;
 {
 dirscan(idesc)
        register struct inodesc *idesc;
 {
@@ -105,11 +77,12 @@ dirscan(idesc)
        idesc->id_loc = 0;
        for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
                dsize = dp->d_reclen;
        idesc->id_loc = 0;
        for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
                dsize = dp->d_reclen;
-               bcopy((char *)dp, dbuf, dsize);
+               bcopy((char *)dp, dbuf, (size_t)dsize);
                idesc->id_dirp = (struct direct *)dbuf;
                if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
                        bp = getdirblk(idesc->id_blkno, blksiz);
                idesc->id_dirp = (struct direct *)dbuf;
                if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
                        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();
                }
                        dirty(bp);
                        sbdirty();
                }
@@ -128,7 +101,7 @@ fsck_readdir(idesc)
 {
        register struct direct *dp, *ndp;
        register struct bufarea *bp;
 {
        register struct direct *dp, *ndp;
        register struct bufarea *bp;
-       long size, blksiz;
+       long size, blksiz, fix;
 
        blksiz = idesc->id_numfrags * sblock.fs_fsize;
        bp = getdirblk(idesc->id_blkno, blksiz);
 
        blksiz = idesc->id_numfrags * sblock.fs_fsize;
        bp = getdirblk(idesc->id_blkno, blksiz);
@@ -139,11 +112,14 @@ fsck_readdir(idesc)
                        goto dpok;
                idesc->id_loc += DIRBLKSIZ;
                idesc->id_filesize -= DIRBLKSIZ;
                        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_namlen = 0;
                dp->d_name[0] = '\0';
                dp->d_reclen = DIRBLKSIZ;
                dp->d_ino = 0;
                dp->d_namlen = 0;
                dp->d_name[0] = '\0';
-               if (dofix(idesc, "DIRECTORY CORRUPTED"))
+               if (fix)
                        dirty(bp);
                return (dp);
        }
                        dirty(bp);
                return (dp);
        }
@@ -159,10 +135,13 @@ dpok:
        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);
-               dp->d_reclen += size;
                idesc->id_loc += size;
                idesc->id_filesize -= 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 + idesc->id_loc);
+               dp->d_reclen += size;
+               if (fix)
                        dirty(bp);
        }
        return (dp);
                        dirty(bp);
        }
        return (dp);
@@ -192,7 +171,7 @@ dircheck(idesc, dp)
                if (dp->d_ino == 0)
                        return (1);
                for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++)
                if (dp->d_ino == 0)
                        return (1);
                for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++)
-                       if (*cp == 0 || (*cp++ & 0200))
+                       if (*cp == 0 || (*cp++ == '/'))
                                return (0);
                if (*cp == 0)
                        return (1);
                                return (0);
                if (*cp == 0)
                        return (1);
@@ -204,21 +183,31 @@ direrror(ino, errmesg)
        ino_t ino;
        char *errmesg;
 {
        ino_t ino;
        char *errmesg;
 {
+
+       fileerror(ino, ino, errmesg);
+}
+
+fileerror(cwd, ino, errmesg)
+       ino_t cwd, ino;
+       char *errmesg;
+{
        register struct dinode *dp;
        register struct dinode *dp;
+       char pathbuf[MAXPATHLEN + 1];
 
        pwarn("%s ", errmesg);
        pinode(ino);
        printf("\n");
 
        pwarn("%s ", errmesg);
        pinode(ino);
        printf("\n");
+       getpathname(pathbuf, cwd, ino);
        if (ino < ROOTINO || ino > maxino) {
        if (ino < ROOTINO || ino > maxino) {
-               pfatal("NAME=%s\n", pathname);
+               pfatal("NAME=%s\n", pathbuf);
                return;
        }
        dp = ginode(ino);
        if (ftypeok(dp))
                pfatal("%s=%s\n",
                return;
        }
        dp = ginode(ino);
        if (ftypeok(dp))
                pfatal("%s=%s\n",
-                   (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathname);
+                   (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf);
        else
        else
-               pfatal("NAME=%s\n", pathname);
+               pfatal("NAME=%s\n", pathbuf);
 }
 
 adjust(idesc, lcnt)
 }
 
 adjust(idesc, lcnt)
@@ -258,7 +247,7 @@ mkentry(idesc)
        struct direct newent;
        int newlen, oldlen;
 
        struct direct newent;
        int newlen, oldlen;
 
-       newent.d_namlen = 11;
+       newent.d_namlen = strlen(idesc->id_name);
        newlen = DIRSIZ(&newent);
        if (dirp->d_ino != 0)
                oldlen = DIRSIZ(dirp);
        newlen = DIRSIZ(&newent);
        if (dirp->d_ino != 0)
                oldlen = DIRSIZ(dirp);
@@ -271,8 +260,8 @@ mkentry(idesc)
        dirp = (struct direct *)(((char *)dirp) + oldlen);
        dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */
        dirp->d_reclen = newent.d_reclen;
        dirp = (struct direct *)(((char *)dirp) + oldlen);
        dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */
        dirp->d_reclen = newent.d_reclen;
-       dirp->d_namlen = strlen(idesc->id_name);
-       bcopy(idesc->id_name, dirp->d_name, (int)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);
 }
 
        return (ALTERED|STOP);
 }
 
@@ -292,7 +281,7 @@ linkup(orphan, parentdir)
        ino_t parentdir;
 {
        register struct dinode *dp;
        ino_t parentdir;
 {
        register struct dinode *dp;
-       int lostdir, len;
+       int lostdir;
        ino_t oldlfdir;
        struct inodesc idesc;
        char tempname[BUFSIZ];
        ino_t oldlfdir;
        struct inodesc idesc;
        char tempname[BUFSIZ];
@@ -310,9 +299,6 @@ linkup(orphan, parentdir)
        else
                if (reply("RECONNECT") == 0)
                        return (0);
        else
                if (reply("RECONNECT") == 0)
                        return (0);
-       pathp = pathname;
-       *pathp++ = '/';
-       *pathp = '\0';
        if (lfdir == 0) {
                dp = ginode(ROOTINO);
                idesc.id_name = lfname;
        if (lfdir == 0) {
                dp = ginode(ROOTINO);
                idesc.id_name = lfname;
@@ -354,12 +340,7 @@ linkup(orphan, parentdir)
                        pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
                        return (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);
                }
                        pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
                        return (0);
                }
@@ -375,40 +356,50 @@ linkup(orphan, parentdir)
                pfatal("SORRY. NO lost+found DIRECTORY\n\n");
                return (0);
        }
                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]--;
        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) {
        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]++;
                dp = ginode(lfdir);
                dp->di_nlink++;
                inodirty();
                lncntp[lfdir]++;
-               pwarn("DIR I=%u CONNECTED. ", orphan);
-               printf("PARENT WAS I=%u\n", parentdir);
+               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);
 }
 
                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
  */
 /*
  * make an entry in a directory
  */
@@ -418,6 +409,7 @@ makeentry(parent, ino, name)
 {
        struct dinode *dp;
        struct inodesc idesc;
 {
        struct dinode *dp;
        struct inodesc idesc;
+       char pathbuf[MAXPATHLEN + 1];
        
        if (parent < ROOTINO || parent >= maxino ||
            ino < ROOTINO || ino >= maxino)
        
        if (parent < ROOTINO || parent >= maxino ||
            ino < ROOTINO || ino >= maxino)
@@ -436,7 +428,9 @@ makeentry(parent, ino, name)
        }
        if ((ckinode(dp, &idesc) & ALTERED) != 0)
                return (1);
        }
        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);
 }
                return (0);
        return (ckinode(dp, &idesc) & ALTERED);
 }
@@ -444,15 +438,16 @@ makeentry(parent, ino, name)
 /*
  * Attempt to expand the size of a directory
  */
 /*
  * Attempt to expand the size of a directory
  */
-expanddir(dp)
+expanddir(dp, name)
        register struct dinode *dp;
        register struct dinode *dp;
+       char *name;
 {
        daddr_t lastbn, newblk;
        register struct bufarea *bp;
        char *cp, firstblk[DIRBLKSIZ];
 
        lastbn = lblkno(&sblock, dp->di_size);
 {
        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);
                return (0);
        if ((newblk = allocblk(sblock.fs_frag)) == 0)
                return (0);
@@ -461,7 +456,7 @@ expanddir(dp)
        dp->di_size += sblock.fs_bsize;
        dp->di_blocks += btodb(sblock.fs_bsize);
        bp = getdirblk(dp->di_db[lastbn + 1],
        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));
+               (long)dblksize(&sblock, dp, lastbn + 1));
        if (bp->b_errs)
                goto bad;
        bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ);
        if (bp->b_errs)
                goto bad;
        bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ);
@@ -475,11 +470,11 @@ expanddir(dp)
                bcopy((char *)&emptydir, cp, sizeof emptydir);
        dirty(bp);
        bp = getdirblk(dp->di_db[lastbn + 1],
                bcopy((char *)&emptydir, cp, sizeof emptydir);
        dirty(bp);
        bp = getdirblk(dp->di_db[lastbn + 1],
-               dblksize(&sblock, dp, lastbn + 1));
+               (long)dblksize(&sblock, dp, lastbn + 1));
        if (bp->b_errs)
                goto bad;
        bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir);
        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)
        if (preen)
                printf(" (EXPANDED)\n");
        else if (reply("EXPAND") == 0)
@@ -527,12 +522,14 @@ allocdir(parent, request, mode)
        inodirty();
        if (ino == ROOTINO) {
                lncntp[ino] = dp->di_nlink;
        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);
        }
                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;
        statemap[ino] = statemap[parent];
        if (statemap[ino] == DSTATE) {
                lncntp[ino] = dp->di_nlink;
@@ -594,10 +591,9 @@ getdirblk(blkno, size)
        daddr_t blkno;
        long size;
 {
        daddr_t blkno;
        long size;
 {
-       static struct 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);
 }
 }