date and time created 84/03/31 21:03:48 by mckusick
authorKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Sun, 1 Apr 1984 12:03:48 +0000 (04:03 -0800)
committerKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Sun, 1 Apr 1984 12:03:48 +0000 (04:03 -0800)
SCCS-vsn: sbin/fsck/pass2.c 3.1

usr/src/sbin/fsck/pass2.c [new file with mode: 0644]

diff --git a/usr/src/sbin/fsck/pass2.c b/usr/src/sbin/fsck/pass2.c
new file mode 100644 (file)
index 0000000..55cf94b
--- /dev/null
@@ -0,0 +1,216 @@
+#ifndef lint
+static char version[] = "@(#)pass2.c   3.1 (Berkeley) %G%";
+#endif
+
+#include <sys/param.h>
+#include <sys/inode.h>
+#include <sys/fs.h>
+#include <sys/dir.h>
+#include <strings.h>
+#include "fsck.h"
+
+int    pass2check();
+
+pass2()
+{
+       register DINODE *dp;
+       struct inodesc rootdesc;
+
+       bzero((char *)&rootdesc, sizeof(struct inodesc));
+       rootdesc.id_type = ADDR;
+       rootdesc.id_func = pass2check;
+       rootdesc.id_number = ROOTINO;
+       pathp = pathname;
+       switch (statemap[ROOTINO]) {
+
+       case USTATE:
+               errexit("ROOT INODE UNALLOCATED. TERMINATING.\n");
+
+       case FSTATE:
+               pfatal("ROOT INODE NOT DIRECTORY");
+               if (reply("FIX") == 0 || (dp = ginode(ROOTINO)) == NULL)
+                       errexit("");
+               dp->di_mode &= ~IFMT;
+               dp->di_mode |= IFDIR;
+               inodirty();
+               inosumbad++;
+               statemap[ROOTINO] = DSTATE;
+               /* fall into ... */
+
+       case DSTATE:
+               descend(&rootdesc, ROOTINO);
+               break;
+
+       case CLEAR:
+               pfatal("DUPS/BAD IN ROOT INODE");
+               printf("\n");
+               if (reply("CONTINUE") == 0)
+                       errexit("");
+               statemap[ROOTINO] = DSTATE;
+               descend(&rootdesc, ROOTINO);
+       }
+}
+
+pass2check(idesc)
+       struct inodesc *idesc;
+{
+       register DIRECT *dirp = idesc->id_dirp;
+       char *curpathloc;
+       int n, entrysize, ret = 0;
+       DINODE *dp;
+       DIRECT proto;
+
+       /* 
+        * check for "."
+        */
+       if (idesc->id_entryno != 0)
+               goto chk1;
+       if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
+               if (dirp->d_ino != idesc->id_number) {
+                       direrr(idesc->id_number, "BAD INODE NUMBER FOR '.'");
+                       dirp->d_ino = idesc->id_number;
+                       if (reply("FIX") == 1)
+                               ret |= ALTERED;
+               }
+               goto chk1;
+       }
+       direrr(idesc->id_number, "MISSING '.'");
+       proto.d_ino = idesc->id_number;
+       proto.d_namlen = 1;
+       (void)strcpy(proto.d_name, ".");
+       entrysize = DIRSIZ(&proto);
+       if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
+               pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
+                       dirp->d_name);
+       } else if (dirp->d_reclen < entrysize) {
+               pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
+       } else if (dirp->d_reclen < 2 * entrysize) {
+               proto.d_reclen = dirp->d_reclen;
+               bcopy((char *)&proto, (char *)dirp, entrysize);
+               if (reply("FIX") == 1)
+                       ret |= ALTERED;
+       } else {
+               n = dirp->d_reclen - entrysize;
+               proto.d_reclen = entrysize;
+               bcopy((char *)&proto, (char *)dirp, entrysize);
+               idesc->id_entryno++;
+               lncntp[dirp->d_ino]--;
+               dirp = (DIRECT *)((char *)(dirp) + entrysize);
+               bzero((char *)dirp, n);
+               dirp->d_reclen = n;
+               if (reply("FIX") == 1)
+                       ret |= ALTERED;
+       }
+chk1:
+       if (idesc->id_entryno > 1)
+               goto chk2;
+       proto.d_ino = idesc->id_parent;
+       proto.d_namlen = 2;
+       (void)strcpy(proto.d_name, "..");
+       entrysize = DIRSIZ(&proto);
+       if (idesc->id_entryno == 0) {
+               n = DIRSIZ(dirp);
+               if (dirp->d_reclen < n + entrysize)
+                       goto chk2;
+               proto.d_reclen = dirp->d_reclen - n;
+               dirp->d_reclen = n;
+               idesc->id_entryno++;
+               lncntp[dirp->d_ino]--;
+               dirp = (DIRECT *)((char *)(dirp) + n);
+               bzero((char *)dirp, n);
+               dirp->d_reclen = n;
+       }
+       if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
+               if (dirp->d_ino != idesc->id_parent) {
+                       direrr(idesc->id_number, "BAD INODE NUMBER FOR '..'");
+                       dirp->d_ino = idesc->id_parent;
+                       if (reply("FIX") == 1)
+                               ret |= ALTERED;
+               }
+               goto chk2;
+       }
+       direrr(idesc->id_number, "MISSING '..'");
+       if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
+               pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
+                       dirp->d_name);
+       } else if (dirp->d_reclen < entrysize) {
+               pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
+       } else {
+               proto.d_reclen = dirp->d_reclen;
+               bcopy((char *)&proto, (char *)dirp, entrysize);
+               if (reply("FIX") == 1)
+                       ret |= ALTERED;
+       }
+chk2:
+       if (dirp->d_ino == 0)
+               return (ret|KEEPON);
+       if (dirp->d_namlen <= 2 &&
+           dirp->d_name[0] == '.' &&
+           idesc->id_entryno >= 2) {
+               if (dirp->d_namlen == 1) {
+                       direrr(idesc->id_number, "EXTRA '.' ENTRY");
+                       dirp->d_ino = 0;
+                       if (reply("FIX") == 1)
+                               ret |= ALTERED;
+                       return (KEEPON | ret);
+               }
+               if (dirp->d_name[1] == '.') {
+                       direrr(idesc->id_number, "EXTRA '..' ENTRY");
+                       dirp->d_ino = 0;
+                       if (reply("FIX") == 1)
+                               ret |= ALTERED;
+                       return (KEEPON | ret);
+               }
+       }
+       curpathloc = pathp;
+       *pathp++ = '/';
+       if (pathp + dirp->d_namlen >= endpathname) {
+               *pathp = '\0';
+               errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name);
+       }
+       bcopy(dirp->d_name, pathp, dirp->d_namlen + 1);
+       pathp += dirp->d_namlen;
+       idesc->id_entryno++;
+       n = 0;
+       if (dirp->d_ino > imax || dirp->d_ino <= 0) {
+               direrr(dirp->d_ino, "I OUT OF RANGE");
+               n = reply("REMOVE");
+       } else {
+again:
+               switch (statemap[dirp->d_ino]) {
+               case USTATE:
+                       direrr(dirp->d_ino, "UNALLOCATED");
+                       n = reply("REMOVE");
+                       break;
+
+               case CLEAR:
+                       direrr(dirp->d_ino, "DUP/BAD");
+                       if ((n = reply("REMOVE")) == 1)
+                               break;
+                       if ((dp = ginode(dirp->d_ino)) == NULL)
+                               break;
+                       statemap[dirp->d_ino] = DIRCT ? DSTATE : FSTATE;
+                       goto again;
+
+               case FSTATE:
+                       lncntp[dirp->d_ino]--;
+                       break;
+
+               case DSTATE:
+                       descend(idesc, dirp->d_ino);
+                       if (statemap[dirp->d_ino] != CLEAR) {
+                               lncntp[dirp->d_ino]--;
+                       } else {
+                               dirp->d_ino = 0;
+                               ret |= ALTERED;
+                       }
+                       break;
+               }
+       }
+       pathp = curpathloc;
+       *pathp = '\0';
+       if (n == 0)
+               return (ret|KEEPON);
+       dirp->d_ino = 0;
+       return (ret|KEEPON|ALTERED);
+}