+#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);
+}