BSD 4_2 release
[unix-history] / usr / src / etc / fsck / fsck.c
index 2153d5e..34d26a5 100644 (file)
@@ -1,13 +1,18 @@
-char version[] = "@(#)fsck.c   2.22    (Berkeley)      3/8/83";
+#ifndef lint
+char version[] = "@(#)fsck.c   2.30 (Berkeley) 9/19/83";
+#endif
 
 #include <stdio.h>
 #include <ctype.h>
 #include <sys/param.h>
 #include <sys/fs.h>
 #include <sys/inode.h>
 
 #include <stdio.h>
 #include <ctype.h>
 #include <sys/param.h>
 #include <sys/fs.h>
 #include <sys/inode.h>
-#include <dir.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 #include <fstab.h>
 #include <fstab.h>
+#define KERNEL
+#include <sys/dir.h>
+#undef KERNEL
 
 /* RECONSTRUCT ONLY BAD CG IN PASS 6 */
 
 
 /* RECONSTRUCT ONLY BAD CG IN PASS 6 */
 
@@ -16,6 +21,7 @@ typedef       int     (*SIG_TYP)();
 #define        MAXNINDIR       (MAXBSIZE / sizeof (daddr_t))
 #define        MAXINOPB        (MAXBSIZE / sizeof (struct dinode))
 #define        SPERB           (MAXBSIZE / sizeof(short))
 #define        MAXNINDIR       (MAXBSIZE / sizeof (daddr_t))
 #define        MAXINOPB        (MAXBSIZE / sizeof (struct dinode))
 #define        SPERB           (MAXBSIZE / sizeof(short))
+#define MINDIRSIZE     (sizeof (struct dirtemplate))
 
 #define        MAXDUP  10              /* limit on dup blks (per inode) */
 #define        MAXBAD  10              /* limit on bad blks (per inode) */
 
 #define        MAXDUP  10              /* limit on dup blks (per inode) */
 #define        MAXBAD  10              /* limit on bad blks (per inode) */
@@ -38,8 +44,6 @@ typedef struct direct DIRECT;
 #define        BADBLK  ((dp->di_mode & IFMT) == IFMT)
 #define        SPECIAL (BLK || CHR)
 
 #define        BADBLK  ((dp->di_mode & IFMT) == IFMT)
 #define        SPECIAL (BLK || CHR)
 
-ino_t  startinum;              /* blk num of first in raw area */
-
 struct bufarea {
        struct bufarea  *b_next;                /* must be first */
        daddr_t b_bno;
 struct bufarea {
        struct bufarea  *b_next;                /* must be first */
        daddr_t b_bno;
@@ -60,7 +64,7 @@ typedef struct bufarea BUFAREA;
 BUFAREA        inoblk;                 /* inode blocks */
 BUFAREA        fileblk;                /* other blks in filesys */
 BUFAREA        sblk;                   /* file system superblock */
 BUFAREA        inoblk;                 /* inode blocks */
 BUFAREA        fileblk;                /* other blks in filesys */
 BUFAREA        sblk;                   /* file system superblock */
-BUFAREA        cgblk;
+BUFAREA        cgblk;                  /* cylinder group blocks */
 
 #define        initbarea(x)    (x)->b_dirty = 0;(x)->b_bno = (daddr_t)-1
 #define        dirty(x)        (x)->b_dirty = 1
 
 #define        initbarea(x)    (x)->b_dirty = 0;(x)->b_bno = (daddr_t)-1
 #define        dirty(x)        (x)->b_dirty = 1
@@ -78,6 +82,24 @@ struct filecntl {
        int     mod;
 } dfile;                       /* file descriptors for filesys */
 
        int     mod;
 } dfile;                       /* file descriptors for filesys */
 
+struct inodesc {
+       char id_type;           /* type of descriptor, DATA or ADDR */
+       int (*id_func)();       /* function to be applied to blocks of inode */
+       ino_t id_number;        /* inode number described */
+       ino_t id_parent;        /* for DATA nodes, their parent */
+       daddr_t id_blkno;       /* current block number being examined */
+       int id_numfrags;        /* number of frags contained in block */
+       long id_filesize;       /* for DATA nodes, the size of the directory */
+       int id_loc;             /* for DATA nodes, current location in dir */
+       int id_entryno;         /* for DATA nodes, current entry number */
+       DIRECT *id_dirp;        /* for data nodes, ptr to current entry */
+       enum {DONTKNOW, NOFIX, FIX} id_fix; /* policy on fixing errors */
+};
+/* file types */
+#define        DATA    1
+#define        ADDR    2
+
+
 #define        DUPTBLSIZE      100     /* num of dup blocks to remember */
 daddr_t        duplist[DUPTBLSIZE];    /* dup block table */
 daddr_t        *enddup;                /* next entry in dup table */
 #define        DUPTBLSIZE      100     /* num of dup blocks to remember */
 daddr_t        duplist[DUPTBLSIZE];    /* dup block table */
 daddr_t        *enddup;                /* next entry in dup table */
@@ -102,23 +124,17 @@ char      *freemap;               /* ptr to secondary blk allocation map */
 char   *statemap;              /* ptr to inode state table */
 short  *lncntp;                /* ptr to link count table */
 
 char   *statemap;              /* ptr to inode state table */
 short  *lncntp;                /* ptr to link count table */
 
-char   *pathp;                 /* pointer to pathname position */
-char   *thisname;              /* ptr to current pathname component */
 char   *srchname;              /* name being searched for in dir */
 char   *srchname;              /* name being searched for in dir */
-char   pathname[BUFSIZ];
+char   pathname[BUFSIZ];       /* current pathname */
+char   *pathp;                 /* pointer to pathname position */
 char   *endpathname = &pathname[BUFSIZ - 2];
 
 char   *lfname = "lost+found";
 
 char   *endpathname = &pathname[BUFSIZ - 2];
 
 char   *lfname = "lost+found";
 
-ino_t  inum;                   /* inode we are currently working on */
-ino_t  dnum;                   /* directory inode currently being worked on */
 ino_t  imax;                   /* number of inodes */
 ino_t  imax;                   /* number of inodes */
-ino_t  parentdir;              /* i number of parent directory */
 ino_t  lastino;                /* hiwater mark of inodes */
 ino_t  lfdir;                  /* lost & found directory */
 ino_t  lastino;                /* hiwater mark of inodes */
 ino_t  lfdir;                  /* lost & found directory */
-ino_t  orphan;                 /* orphaned inode */
 
 
-off_t  filsize;                /* num blks seen in file */
 off_t  maxblk;                 /* largest logical blk in file */
 off_t  bmapsz;                 /* num chars in blockmap */
 
 off_t  maxblk;                 /* largest logical blk in file */
 off_t  bmapsz;                 /* num chars in blockmap */
 
@@ -149,10 +165,7 @@ struct     dinode zino;
 #define        getfmap(x)      isset(freemap, x)
 #define        clrfmap(x)      clrbit(freemap, x)
 
 #define        getfmap(x)      isset(freemap, x)
 #define        clrfmap(x)      clrbit(freemap, x)
 
-#define        DATA    1
-#define        ADDR    0
-
-#define        ALTERD  010
+#define        ALTERED 010
 #define        KEEPON  04
 #define        SKIP    02
 #define        STOP    01
 #define        KEEPON  04
 #define        SKIP    02
 #define        STOP    01
@@ -161,15 +174,13 @@ int       (*signal())();
 long   lseek();
 time_t time();
 DINODE *ginode();
 long   lseek();
 time_t time();
 DINODE *ginode();
+DIRECT *fsck_readdir();
 BUFAREA        *getblk();
 BUFAREA        *getblk();
-int    dirscan();
-int    findino();
 int    catch();
 int    catch();
-int    mkentry();
-int    chgdd();
-int    pass1check(), pass1bcheck(), pass2check(), pass4check(), pass5check();
-int    (*pfunc)();
-char   *rawname(), *rindex(), *unrawname();
+int    findino(), mkentry(), chgdd();
+int    pass1check(), pass1bcheck(), pass2check(), pass4check();
+char   *rawname(), *unrawname();
+char   *calloc(), *strcpy(), *strcat(), *rindex();
 extern int inside[], around[];
 extern unsigned char *fragtbl[];
 
 extern int inside[], around[];
 extern unsigned char *fragtbl[];
 
@@ -191,7 +202,12 @@ main(argc, argv)
                        break;
 
                case 'b':
                        break;
 
                case 'b':
-                       bflag = atoi(argv[0]+1);
+                       if (argv[0][1] != '\0') {
+                               bflag = atoi(argv[0]+1);
+                       } else {
+                               bflag = atoi(*++argv);
+                               argc--;
+                       }
                        printf("Alternate super block location: %d\n", bflag);
                        break;
 
                        printf("Alternate super block location: %d\n", bflag);
                        break;
 
@@ -216,7 +232,7 @@ main(argc, argv)
                }
        }
        if (signal(SIGINT, SIG_IGN) != SIG_IGN)
                }
        }
        if (signal(SIGINT, SIG_IGN) != SIG_IGN)
-               signal(SIGINT, catch);
+               (void)signal(SIGINT, catch);
        if (argc) {
                while (argc-- > 0) {
                        hotroot = 0;
        if (argc) {
                while (argc-- > 0) {
                        hotroot = 0;
@@ -232,7 +248,8 @@ main(argc, argv)
                        errexit("Can't open checklist file: %s\n", FSTAB);
                while ((fsp = getfsent()) != 0) {
                        if (strcmp(fsp->fs_type, FSTAB_RW) &&
                        errexit("Can't open checklist file: %s\n", FSTAB);
                while ((fsp = getfsent()) != 0) {
                        if (strcmp(fsp->fs_type, FSTAB_RW) &&
-                           strcmp(fsp->fs_type, FSTAB_RO))
+                           strcmp(fsp->fs_type, FSTAB_RO) &&
+                           strcmp(fsp->fs_type, FSTAB_RQ))
                                continue;
                        if (preen == 0 ||
                            passno == 1 && fsp->fs_passno == passno) {
                                continue;
                        if (preen == 0 ||
                            passno == 1 && fsp->fs_passno == passno) {
@@ -254,15 +271,15 @@ main(argc, argv)
                        }
                }
                if (preen) {
                        }
                }
                if (preen) {
-                       int status;
+                       union wait status;
                        while (wait(&status) != -1)
                        while (wait(&status) != -1)
-                               sumstatus |= status;
+                               sumstatus |= status.w_retcode;
                }
                passno++;
        } while (anygtr);
        if (sumstatus)
                exit(8);
                }
                passno++;
        } while (anygtr);
        if (sumstatus)
                exit(8);
-       endfsent();
+       (void)endfsent();
        exit(0);
 }
 
        exit(0);
 }
 
@@ -292,7 +309,7 @@ retry:
                if (stchar.st_mode & S_IFCHR) {
                        if (stslash.st_dev == stblock.st_rdev) {
                                hotroot++;
                if (stchar.st_mode & S_IFCHR) {
                        if (stslash.st_dev == stblock.st_rdev) {
                                hotroot++;
-                               raw = rawname(name);
+                               raw = unrawname(name);
                        }
                        checkfilesys(raw);
                        return (1);
                        }
                        checkfilesys(raw);
                        return (1);
@@ -316,12 +333,6 @@ retry:
 checkfilesys(filesys)
        char *filesys;
 {
 checkfilesys(filesys)
        char *filesys;
 {
-       register DINODE *dp;
-       register ino_t *blp;
-       register int i, n;
-       ino_t savino;
-       int b, c, j, partial, ndb;
-       daddr_t d, s;
 
        devname = filesys;
        if (setup(filesys) == 0) {
 
        devname = filesys;
        if (setup(filesys) == 0) {
@@ -346,22 +357,22 @@ checkfilesys(filesys)
                pass1b();
        }
 
                pass1b();
        }
 
-/* 2: traverse directories to check reference counts */
+/* 2: traverse directories from root to mark all connected directories */
        if (preen == 0)
                printf("** Phase 2 - Check Pathnames\n");
        pass2();
 
        if (preen == 0)
                printf("** Phase 2 - Check Pathnames\n");
        pass2();
 
-/* 3 */
+/* 3: scan inodes looking for disconnected directories */
        if (preen == 0)
                printf("** Phase 3 - Check Connectivity\n");
        pass3();
 
        if (preen == 0)
                printf("** Phase 3 - Check Connectivity\n");
        pass3();
 
-/* 4 */
+/* 4: scan inodes looking for disconnected files; check reference counts */
        if (preen == 0)
                printf("** Phase 4 - Check Reference Counts\n");
        pass4();
 
        if (preen == 0)
                printf("** Phase 4 - Check Reference Counts\n");
        pass4();
 
-/* 5 */
+/* 5: check resource counts in cylinder groups */
        if (preen == 0)
                printf("** Phase 5 - Check Cyl groups\n");
        pass5();
        if (preen == 0)
                printf("** Phase 5 - Check Cyl groups\n");
        pass5();
@@ -378,27 +389,25 @@ checkfilesys(filesys)
            n_files, n_blks - howmany(sblock.fs_cssize, sblock.fs_fsize),
            n_ffree + sblock.fs_frag * n_bfree, n_ffree, n_bfree);
        if (dfile.mod) {
            n_files, n_blks - howmany(sblock.fs_cssize, sblock.fs_fsize),
            n_ffree + sblock.fs_frag * n_bfree, n_ffree, n_bfree);
        if (dfile.mod) {
-               time(&sblock.fs_time);
+               (void)time(&sblock.fs_time);
                sbdirty();
        }
        ckfini();
        free(blockmap);
        free(freemap);
        free(statemap);
                sbdirty();
        }
        ckfini();
        free(blockmap);
        free(freemap);
        free(statemap);
-       free(lncntp);
-       if (dfile.mod) {
-               if (preen) {
-                       if (hotroot)
-                               exit(4);
-               } else {
-                       printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
-                       if (hotroot) {
-                               printf("\n***** BOOT UNIX (NO SYNC!) *****\n");
-                               exit(4);
-                       }
-               }
+       free((char *)lncntp);
+       if (!dfile.mod)
+               return;
+       if (!preen) {
+               printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
+               if (hotroot)
+                       printf("\n***** REBOOT UNIX *****\n");
+       }
+       if (hotroot) {
+               sync();
+               exit(4);
        }
        }
-       sync();                 /* ??? */
 }
 
 setup(dev)
 }
 
 setup(dev)
@@ -406,11 +415,12 @@ setup(dev)
 {
        dev_t rootdev;
        struct stat statb;
 {
        dev_t rootdev;
        struct stat statb;
-       int super = bflag ? bflag : SBLOCK;
-       int i, j, size;
-       int c, d, cgd;
+       daddr_t super = bflag ? bflag : SBLOCK;
+       int i, j, c, d, cgd;
+       long size;
+       BUFAREA asblk;
+#      define altsblock asblk.b_un.b_fs
 
 
-       bflag = 0;
        if (stat("/", &statb) < 0)
                errexit("Can't stat root\n");
        rootdev = statb.st_dev;
        if (stat("/", &statb) < 0)
                errexit("Can't stat root\n");
        rootdev = statb.st_dev;
@@ -454,10 +464,11 @@ setup(dev)
        initbarea(&fileblk);
        initbarea(&inoblk);
        initbarea(&cgblk);
        initbarea(&fileblk);
        initbarea(&inoblk);
        initbarea(&cgblk);
+       initbarea(&asblk);
        /*
         * Read in the super block and its summary info.
         */
        /*
         * Read in the super block and its summary info.
         */
-       if (bread(&dfile, &sblock, super, SBSIZE) == 0)
+       if (bread(&dfile, (char *)&sblock, super, (long)SBSIZE) == 0)
                return (0);
        sblk.b_bno = super;
        sblk.b_size = SBSIZE;
                return (0);
        sblk.b_bno = super;
        sblk.b_size = SBSIZE;
@@ -470,33 +481,41 @@ setup(dev)
                { badsb("NCG OUT OF RANGE"); return (0); }
        if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG)
                { badsb("CPG OUT OF RANGE"); return (0); }
                { badsb("NCG OUT OF RANGE"); return (0); }
        if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG)
                { badsb("CPG OUT OF RANGE"); return (0); }
-       if (sblock.fs_nsect < 1)
-               { badsb("NSECT < 1"); return (0); }
-       if (sblock.fs_ntrak < 1)
-               { badsb("NTRAK < 1"); return (0); }
-       if (sblock.fs_spc != sblock.fs_nsect * sblock.fs_ntrak)
-               { badsb("SPC DOES NOT JIVE w/NTRAK*NSECT"); return (0); }
-       if (sblock.fs_ipg % INOPB(&sblock))
-               { badsb("INODES NOT MULTIPLE OF A BLOCK"); return (0); }
-       if (cgdmin(&sblock, 0) >= sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock))
-               { badsb("IMPLIES MORE INODE THAN DATA BLOCKS"); return (0); }
        if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
            (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl)
                { badsb("NCYL DOES NOT JIVE WITH NCG*CPG"); return (0); }
        if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
            (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl)
                { badsb("NCYL DOES NOT JIVE WITH NCG*CPG"); return (0); }
-       if (sblock.fs_fpg != sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock))
-               { badsb("FPG DOES NOT JIVE WITH CPG & SPC"); return (0); }
-       if (sblock.fs_size * NSPF(&sblock) <=
-           (sblock.fs_ncyl - 1) * sblock.fs_spc)
-               { badsb("SIZE PREPOSTEROUSLY SMALL"); return (0); }
-       if (sblock.fs_size * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc)
+       if (sblock.fs_sbsize > SBSIZE)
                { badsb("SIZE PREPOSTEROUSLY LARGE"); return (0); }
                { badsb("SIZE PREPOSTEROUSLY LARGE"); return (0); }
-       /* rest we COULD repair... */
-       if (sblock.fs_cgsize != fragroundup(&sblock,
-           sizeof(struct cg) + howmany(sblock.fs_fpg, NBBY)))
-               { badsb("CGSIZE INCORRECT"); return (0); }
-       if (sblock.fs_cssize !=
-           fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)))
-               { badsb("CSSIZE INCORRECT"); return (0); }
+       /*
+        * Set all possible fields that could differ, then do check
+        * of whole super block against an alternate super block.
+        * When an alternate super-block is specified this check is skipped.
+        */
+       if (bflag)
+               goto sbok;
+       if (getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1),
+           sblock.fs_sbsize) == 0)
+               return (0);
+       altsblock.fs_link = sblock.fs_link;
+       altsblock.fs_rlink = sblock.fs_rlink;
+       altsblock.fs_time = sblock.fs_time;
+       altsblock.fs_cstotal = sblock.fs_cstotal;
+       altsblock.fs_cgrotor = sblock.fs_cgrotor;
+       altsblock.fs_fmod = sblock.fs_fmod;
+       altsblock.fs_clean = sblock.fs_clean;
+       altsblock.fs_ronly = sblock.fs_ronly;
+       altsblock.fs_flags = sblock.fs_flags;
+       altsblock.fs_maxcontig = sblock.fs_maxcontig;
+       altsblock.fs_minfree = sblock.fs_minfree;
+       altsblock.fs_rotdelay = sblock.fs_rotdelay;
+       altsblock.fs_maxbpg = sblock.fs_maxbpg;
+       bcopy((char *)sblock.fs_csp, (char *)altsblock.fs_csp,
+               sizeof sblock.fs_csp);
+       bcopy((char *)sblock.fs_fsmnt, (char *)altsblock.fs_fsmnt,
+               sizeof sblock.fs_fsmnt);
+       if (bcmp((char *)&sblock, (char *)&altsblock, (int)sblock.fs_sbsize))
+               { badsb("TRASHED VALUES IN SUPER BLOCK"); return (0); }
+sbok:
        fmax = sblock.fs_size;
        imax = sblock.fs_ncg * sblock.fs_ipg;
        n_bad = cgsblock(&sblock, 0); /* boot block plus dedicated sblock */
        fmax = sblock.fs_size;
        imax = sblock.fs_ncg * sblock.fs_ipg;
        n_bad = cgsblock(&sblock, 0); /* boot block plus dedicated sblock */
@@ -506,35 +525,36 @@ setup(dev)
        for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
                size = sblock.fs_cssize - i < sblock.fs_bsize ?
                    sblock.fs_cssize - i : sblock.fs_bsize;
        for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
                size = sblock.fs_cssize - i < sblock.fs_bsize ?
                    sblock.fs_cssize - i : sblock.fs_bsize;
-               sblock.fs_csp[j] = (struct csum *)calloc(1, size);
-               bread(&dfile, (char *)sblock.fs_csp[j],
+               sblock.fs_csp[j] = (struct csum *)calloc(1, (unsigned)size);
+               if (bread(&dfile, (char *)sblock.fs_csp[j],
                    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
                    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
-                   size);
+                   size) == 0)
+                       return (0);
        }
        /*
         * allocate and initialize the necessary maps
         */
        bmapsz = roundup(howmany(fmax, NBBY), sizeof(short));
        }
        /*
         * allocate and initialize the necessary maps
         */
        bmapsz = roundup(howmany(fmax, NBBY), sizeof(short));
-       blockmap = (char *)calloc(bmapsz, sizeof (char));
+       blockmap = calloc((unsigned)bmapsz, sizeof (char));
        if (blockmap == NULL) {
                printf("cannot alloc %d bytes for blockmap\n", bmapsz);
        if (blockmap == NULL) {
                printf("cannot alloc %d bytes for blockmap\n", bmapsz);
-               exit(1);
+               goto badsb;
        }
        }
-       freemap = (char *)calloc(bmapsz, sizeof (char));
+       freemap = calloc((unsigned)bmapsz, sizeof (char));
        if (freemap == NULL) {
                printf("cannot alloc %d bytes for freemap\n", bmapsz);
        if (freemap == NULL) {
                printf("cannot alloc %d bytes for freemap\n", bmapsz);
-               exit(1);
+               goto badsb;
        }
        }
-       statemap = (char *)calloc(imax+1, sizeof(char));
+       statemap = calloc((unsigned)(imax + 1), sizeof(char));
        if (statemap == NULL) {
                printf("cannot alloc %d bytes for statemap\n", imax + 1);
        if (statemap == NULL) {
                printf("cannot alloc %d bytes for statemap\n", imax + 1);
-               exit(1);
+               goto badsb;
        }
        }
-       lncntp = (short *)calloc(imax+1, sizeof(short));
+       lncntp = (short *)calloc((unsigned)(imax + 1), sizeof(short));
        if (lncntp == NULL) {
                printf("cannot alloc %d bytes for lncntp\n", 
                    (imax + 1) * sizeof(short));
        if (lncntp == NULL) {
                printf("cannot alloc %d bytes for lncntp\n", 
                    (imax + 1) * sizeof(short));
-               exit(1);
+               goto badsb;
        }
        for (c = 0; c < sblock.fs_ncg; c++) {
                cgd = cgdmin(&sblock, c);
        }
        for (c = 0; c < sblock.fs_ncg; c++) {
                cgd = cgdmin(&sblock, c);
@@ -547,33 +567,37 @@ setup(dev)
                        setbmap(d);
        }
 
                        setbmap(d);
        }
 
-       startinum = imax + 1;
        return (1);
 
 badsb:
        ckfini();
        return (0);
        return (1);
 
 badsb:
        ckfini();
        return (0);
+#      undef altsblock
 }
 
 pass1()
 {
        register int c, i, n, j;
        register DINODE *dp;
 }
 
 pass1()
 {
        register int c, i, n, j;
        register DINODE *dp;
-       int savino, ndb, partial;
-
-       pfunc = pass1check;
-       inum = 0;
+       int ndb, partial;
+       struct inodesc idesc;
+       ino_t inumber;
+
+       bzero((char *)&idesc, sizeof(struct inodesc));
+       idesc.id_type = ADDR;
+       idesc.id_func = pass1check;
+       inumber = 0;
        n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
        for (c = 0; c < sblock.fs_ncg; c++) {
                if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
                        continue;
                if (cgrp.cg_magic != CG_MAGIC) {
        n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
        for (c = 0; c < sblock.fs_ncg; c++) {
                if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
                        continue;
                if (cgrp.cg_magic != CG_MAGIC) {
-                       pfatal("cg %d: bad magic number\n", c);
-                       bzero((caddr_t)&cgrp, sblock.fs_cgsize);
+                       pfatal("CG %d: BAD MAGIC NUMBER\n", c);
+                       bzero((char *)&cgrp, (int)sblock.fs_cgsize);
                }
                n = 0;
                }
                n = 0;
-               for (i = 0; i < sblock.fs_ipg; i++, inum++) {
-                       dp = ginode();
+               for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
+                       dp = ginode(inumber);
                        if (dp == NULL)
                                continue;
                        n++;
                        if (dp == NULL)
                                continue;
                        n++;
@@ -581,11 +605,11 @@ pass1()
                                if (!isset(cgrp.cg_iused, i)) {
                                        if (debug)
                                                printf("%d bad, not used\n",
                                if (!isset(cgrp.cg_iused, i)) {
                                        if (debug)
                                                printf("%d bad, not used\n",
-                                                   inum);
+                                                   inumber);
                                        inosumbad++;
                                }
                                n--;
                                        inosumbad++;
                                }
                                n--;
-                               lastino = inum;
+                               lastino = inumber;
                                if (!preen && BADBLK &&
                                    reply("HOLD BAD BLOCK") == 1) {
                                        dp->di_size = sblock.fs_fsize;
                                if (!preen && BADBLK &&
                                    reply("HOLD BAD BLOCK") == 1) {
                                        dp->di_size = sblock.fs_fsize;
@@ -619,24 +643,37 @@ pass1()
                                                goto unknown;
                                        }
                                n_files++;
                                                goto unknown;
                                        }
                                n_files++;
-                               lncntp[inum] = dp->di_nlink;
+                               lncntp[inumber] = dp->di_nlink;
                                if (dp->di_nlink <= 0) {
                                        if (badlnp < &badlncnt[MAXLNCNT])
                                if (dp->di_nlink <= 0) {
                                        if (badlnp < &badlncnt[MAXLNCNT])
-                                               *badlnp++ = inum;
+                                               *badlnp++ = inumber;
                                        else {
                                                pfatal("LINK COUNT TABLE OVERFLOW");
                                                if (reply("CONTINUE") == 0)
                                                        errexit("");
                                        }
                                }
                                        else {
                                                pfatal("LINK COUNT TABLE OVERFLOW");
                                                if (reply("CONTINUE") == 0)
                                                        errexit("");
                                        }
                                }
-                               statemap[inum] = DIRCT ? DSTATE : FSTATE;
-                               badblk = dupblk = 0; filsize = 0; maxblk = 0;
-                               ckinode(dp, ADDR);
+                               statemap[inumber] = DIRCT ? DSTATE : FSTATE;
+                               badblk = dupblk = 0; maxblk = 0;
+                               idesc.id_number = inumber;
+                               idesc.id_filesize = 0;
+                               (void)ckinode(dp, &idesc);
+                               idesc.id_filesize *= btodb(sblock.fs_fsize);
+                               if (dp->di_blocks != idesc.id_filesize) {
+                                       pwarn("INCORRECT BLOCK COUNT I=%u (%ld should be %ld)",
+                                           inumber, dp->di_blocks,
+                                           idesc.id_filesize);
+                                       if (preen)
+                                               printf(" (CORRECTED)\n");
+                                       else if (reply("CORRECT") == 0)
+                                               continue;
+                                       dp->di_blocks = idesc.id_filesize;
+                                       inodirty();
+                               }
                                continue;
                unknown:
                                continue;
                unknown:
-                               if (!SOCK)
-                                       pfatal("UNKNOWN FILE TYPE I=%u", inum);
-                               if ((preen && SOCK) || reply("CLEAR") == 1) {
+                               pfatal("UNKNOWN FILE TYPE I=%u", inumber);
+                               if (reply("CLEAR") == 1) {
                                        zapino(dp);
                                        inodirty();
                                        inosumbad++;
                                        zapino(dp);
                                        inodirty();
                                        inosumbad++;
@@ -645,7 +682,7 @@ pass1()
                                if (isset(cgrp.cg_iused, i)) {
                                        if (debug)
                                                printf("%d bad, marked used\n",
                                if (isset(cgrp.cg_iused, i)) {
                                        if (debug)
                                                printf("%d bad, marked used\n",
-                                                   inum);
+                                                   inumber);
                                        inosumbad++;
                                        n--;
                                }
                                        inosumbad++;
                                        n--;
                                }
@@ -658,7 +695,8 @@ pass1()
                                                partial++;
                                if (partial || dp->di_mode != 0 ||
                                    dp->di_size != 0) {
                                                partial++;
                                if (partial || dp->di_mode != 0 ||
                                    dp->di_size != 0) {
-                                       pfatal("PARTIALLY ALLOCATED INODE I=%u", inum);
+                                       pfatal("PARTIALLY ALLOCATED INODE I=%u",
+                                               inumber);
                                        if (reply("CLEAR") == 1) {
                                                zapino(dp);
                                                inodirty();
                                        if (reply("CLEAR") == 1) {
                                                zapino(dp);
                                                inodirty();
@@ -681,20 +719,21 @@ pass1()
        }
 }
 
        }
 }
 
-pass1check(blk, size)
-       daddr_t blk;
-       int size;
+pass1check(idesc)
+       register struct inodesc *idesc;
 {
        register daddr_t *dlp;
        int res = KEEPON;
 {
        register daddr_t *dlp;
        int res = KEEPON;
-       int anyout;
+       int anyout, nfrags;
+       daddr_t blkno = idesc->id_blkno;
 
 
-       anyout = outrange(blk, size);
-       for (; size > 0; blk++, size--) {
-               if (anyout && outrange(blk, 1)) {
-                       blkerr("BAD", blk);
+       anyout = outrange(blkno, idesc->id_numfrags);
+       for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
+               if (anyout && outrange(blkno, 1)) {
+                       blkerr(idesc->id_number, "BAD", blkno);
                        if (++badblk >= MAXBAD) {
                        if (++badblk >= MAXBAD) {
-                               pwarn("EXCESSIVE BAD BLKS I=%u", inum);
+                               pwarn("EXCESSIVE BAD BLKS I=%u",
+                                       idesc->id_number);
                                if (preen)
                                        printf(" (SKIPPING)\n");
                                else if (reply("CONTINUE") == 0)
                                if (preen)
                                        printf(" (SKIPPING)\n");
                                else if (reply("CONTINUE") == 0)
@@ -702,10 +741,11 @@ pass1check(blk, size)
                                return (STOP);
                        }
                        res = SKIP;
                                return (STOP);
                        }
                        res = SKIP;
-               } else if (getbmap(blk)) {
-                       blkerr("DUP", blk);
+               } else if (getbmap(blkno)) {
+                       blkerr(idesc->id_number, "DUP", blkno);
                        if (++dupblk >= MAXDUP) {
                        if (++dupblk >= MAXDUP) {
-                               pwarn("EXCESSIVE DUP BLKS I=%u", inum);
+                               pwarn("EXCESSIVE DUP BLKS I=%u",
+                                       idesc->id_number);
                                if (preen)
                                        printf(" (SKIPPING)\n");
                                else if (reply("CONTINUE") == 0)
                                if (preen)
                                        printf(" (SKIPPING)\n");
                                else if (reply("CONTINUE") == 0)
@@ -719,19 +759,19 @@ pass1check(blk, size)
                                return (STOP);
                        }
                        for (dlp = duplist; dlp < muldup; dlp++)
                                return (STOP);
                        }
                        for (dlp = duplist; dlp < muldup; dlp++)
-                               if (*dlp == blk) {
-                                       *enddup++ = blk;
+                               if (*dlp == blkno) {
+                                       *enddup++ = blkno;
                                        break;
                                }
                        if (dlp >= muldup) {
                                *enddup++ = *muldup;
                                        break;
                                }
                        if (dlp >= muldup) {
                                *enddup++ = *muldup;
-                               *muldup++ = blk;
+                               *muldup++ = blkno;
                        }
                } else {
                        n_blks++;
                        }
                } else {
                        n_blks++;
-                       setbmap(blk);
+                       setbmap(blkno);
                }
                }
-               filsize++;
+               idesc->id_filesize++;
        }
        return (res);
 }
        }
        return (res);
 }
@@ -740,16 +780,21 @@ pass1b()
 {
        register int c, i;
        register DINODE *dp;
 {
        register int c, i;
        register DINODE *dp;
+       struct inodesc idesc;
+       ino_t inumber;
 
 
-       pfunc = pass1bcheck;
-       inum = 0;
+       bzero((char *)&idesc, sizeof(struct inodesc));
+       idesc.id_type = ADDR;
+       idesc.id_func = pass1bcheck;
+       inumber = 0;
        for (c = 0; c < sblock.fs_ncg; c++) {
        for (c = 0; c < sblock.fs_ncg; c++) {
-               for (i = 0; i < sblock.fs_ipg; i++, inum++) {
-                       dp = ginode();
+               for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
+                       dp = ginode(inumber);
                        if (dp == NULL)
                                continue;
                        if (dp == NULL)
                                continue;
-                       if (statemap[inum] != USTATE &&
-                           (ckinode(dp, ADDR) & STOP))
+                       idesc.id_number = inumber;
+                       if (statemap[inumber] != USTATE &&
+                           (ckinode(dp, &idesc) & STOP))
                                goto out1b;
                }
        }
                                goto out1b;
                }
        }
@@ -757,21 +802,21 @@ out1b:
        flush(&dfile, &inoblk);
 }
 
        flush(&dfile, &inoblk);
 }
 
-pass1bcheck(blk, size)
-       daddr_t blk;
-       int size;
+pass1bcheck(idesc)
+       register struct inodesc *idesc;
 {
        register daddr_t *dlp;
 {
        register daddr_t *dlp;
-       int res = KEEPON;
+       int nfrags, res = KEEPON;
+       daddr_t blkno = idesc->id_blkno;
 
 
-       for (; size > 0; blk++, size--) {
-               if (outrange(blk, 1))
+       for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
+               if (outrange(blkno, 1))
                        res = SKIP;
                for (dlp = duplist; dlp < muldup; dlp++)
                        res = SKIP;
                for (dlp = duplist; dlp < muldup; dlp++)
-                       if (*dlp == blk) {
-                               blkerr("DUP", blk);
+                       if (*dlp == blkno) {
+                               blkerr(idesc->id_number, "DUP", blkno);
                                *dlp = *--muldup;
                                *dlp = *--muldup;
-                               *muldup = blk;
+                               *muldup = blkno;
                                if (muldup == duplist)
                                        return (STOP);
                        }
                                if (muldup == duplist)
                                        return (STOP);
                        }
@@ -782,28 +827,31 @@ pass1bcheck(blk, size)
 pass2()
 {
        register DINODE *dp;
 pass2()
 {
        register DINODE *dp;
+       struct inodesc rootdesc;
 
 
-       inum = ROOTINO;
-       thisname = pathp = pathname;
-       pfunc = pass2check;
-       switch (statemap[inum]) {
+       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");
 
        case USTATE:
                errexit("ROOT INODE UNALLOCATED. TERMINATING.\n");
 
        case FSTATE:
                pfatal("ROOT INODE NOT DIRECTORY");
-               if (reply("FIX") == 0 || (dp = ginode()) == NULL)
+               if (reply("FIX") == 0 || (dp = ginode(ROOTINO)) == NULL)
                        errexit("");
                dp->di_mode &= ~IFMT;
                dp->di_mode |= IFDIR;
                inodirty();
                inosumbad++;
                        errexit("");
                dp->di_mode &= ~IFMT;
                dp->di_mode |= IFDIR;
                inodirty();
                inosumbad++;
-               statemap[inum] = DSTATE;
+               statemap[ROOTINO] = DSTATE;
                /* fall into ... */
 
        case DSTATE:
                /* fall into ... */
 
        case DSTATE:
-               descend();
+               descend(&rootdesc, ROOTINO);
                break;
 
        case CLEAR:
                break;
 
        case CLEAR:
@@ -811,126 +859,249 @@ pass2()
                printf("\n");
                if (reply("CONTINUE") == 0)
                        errexit("");
                printf("\n");
                if (reply("CONTINUE") == 0)
                        errexit("");
-               statemap[inum] = DSTATE;
-               descend();
+               statemap[ROOTINO] = DSTATE;
+               descend(&rootdesc, ROOTINO);
        }
 }
 
        }
 }
 
-pass2check(dirp)
-       register DIRECT *dirp;
+pass2check(idesc)
+       struct inodesc *idesc;
 {
 {
-       register char *p;
-       register n;
+       register DIRECT *dirp = idesc->id_dirp;
+       char *curpathloc;
+       int n, entrysize, ret = 0;
        DINODE *dp;
        DINODE *dp;
+       DIRECT proto;
 
 
-       if ((inum = dirp->d_ino) == 0)
-               return (KEEPON);
-       thisname = pathp;
+       /* 
+        * check for "."
+        */
+       if (idesc->id_entryno != 0)
+               goto chk1;
+       if (dirp->d_ino != 0 && dirp->d_namlen == 1 && 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) {
+               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 && dirp->d_namlen == 2 &&
+           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) {
+               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 (idesc->id_entryno >= 2 &&
+           dirp->d_namlen <= 2 &&
+           dirp->d_name[0] == '.') {
+               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);
        }
        if (pathp + dirp->d_namlen >= endpathname) {
                *pathp = '\0';
                errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name);
        }
-       for (p = dirp->d_name; p < &dirp->d_name[MAXNAMLEN]; )
-               if ((*pathp++ = *p++) == 0) {
-                       --pathp;
-                       break;
-               }
-       *pathp = 0;
+       bcopy(dirp->d_name, pathp, dirp->d_namlen + 1);
+       pathp += dirp->d_namlen;
+       idesc->id_entryno++;
        n = 0;
        n = 0;
-       if (inum > imax || inum <= 0)
-               n = direrr("I OUT OF RANGE");
-       else {
+       if (dirp->d_ino > imax || dirp->d_ino <= 0) {
+               direrr(dirp->d_ino, "I OUT OF RANGE");
+               n = reply("REMOVE");
+       } else {
 again:
 again:
-               switch (statemap[inum]) {
+               switch (statemap[dirp->d_ino]) {
                case USTATE:
                case USTATE:
-                       n = direrr("UNALLOCATED");
+                       direrr(dirp->d_ino, "UNALLOCATED");
+                       n = reply("REMOVE");
                        break;
 
                case CLEAR:
                        break;
 
                case CLEAR:
-                       if ((n = direrr("DUP/BAD")) == 1)
+                       direrr(dirp->d_ino, "DUP/BAD");
+                       if ((n = reply("REMOVE")) == 1)
                                break;
                                break;
-                       if ((dp = ginode()) == NULL)
+                       if ((dp = ginode(dirp->d_ino)) == NULL)
                                break;
                                break;
-                       statemap[inum] = DIRCT ? DSTATE : FSTATE;
+                       statemap[dirp->d_ino] = DIRCT ? DSTATE : FSTATE;
                        goto again;
 
                case FSTATE:
                        goto again;
 
                case FSTATE:
-                       lncntp[inum]--;
+                       lncntp[dirp->d_ino]--;
                        break;
 
                case DSTATE:
                        break;
 
                case DSTATE:
-                       lncntp[inum]--;
-                       descend();
+                       descend(idesc, dirp->d_ino);
+                       if (statemap[dirp->d_ino] != CLEAR) {
+                               lncntp[dirp->d_ino]--;
+                       } else {
+                               dirp->d_ino = 0;
+                               ret |= ALTERED;
+                       }
                        break;
                }
        }
                        break;
                }
        }
-       pathp = thisname;
+       pathp = curpathloc;
+       *pathp = '\0';
        if (n == 0)
        if (n == 0)
-               return (KEEPON);
+               return (ret|KEEPON);
        dirp->d_ino = 0;
        dirp->d_ino = 0;
-       return (KEEPON|ALTERD);
+       return (ret|KEEPON|ALTERED);
 }
 
 pass3()
 {
 }
 
 pass3()
 {
-       ino_t savino;
        register DINODE *dp;
        register DINODE *dp;
-
-       for (inum = ROOTINO; inum <= lastino; inum++) {
-               if (statemap[inum] == DSTATE) {
-                       pfunc = findino;
+       struct inodesc idesc;
+       ino_t inumber, orphan;
+       int loopcnt;
+
+       bzero((char *)&idesc, sizeof(struct inodesc));
+       idesc.id_type = DATA;
+       for (inumber = ROOTINO; inumber <= lastino; inumber++) {
+               if (statemap[inumber] == DSTATE) {
+                       pathp = pathname;
+                       *pathp++ = '?';
+                       *pathp = '\0';
+                       idesc.id_func = findino;
                        srchname = "..";
                        srchname = "..";
-                       savino = inum;
+                       idesc.id_parent = inumber;
+                       loopcnt = 0;
                        do {
                        do {
-                               orphan = inum;
-                               if ((dp = ginode()) == NULL)
+                               orphan = idesc.id_parent;
+                               if ((dp = ginode(orphan)) == NULL)
+                                       break;
+                               idesc.id_parent = 0;
+                               idesc.id_filesize = dp->di_size;
+                               idesc.id_number = orphan;
+                               (void)ckinode(dp, &idesc);
+                               if (idesc.id_parent == 0)
                                        break;
                                        break;
-                               filsize = dp->di_size;
-                               parentdir = 0;
-                               ckinode(dp, DATA);
-                               if ((inum = parentdir) == 0)
+                               if (loopcnt >= sblock.fs_cstotal.cs_ndir)
                                        break;
                                        break;
-                       } while (statemap[inum] == DSTATE);
-                       inum = orphan;
-                       if (linkup() == 1) {
-                               thisname = pathp = pathname;
-                               *pathp++ = '?';
-                               pfunc = pass2check;
-                               descend();
+                               loopcnt++;
+                       } while (statemap[idesc.id_parent] == DSTATE);
+                       if (linkup(orphan, idesc.id_parent) == 1) {
+                               idesc.id_func = pass2check;
+                               idesc.id_number = lfdir;
+                               descend(&idesc, orphan);
                        }
                        }
-                       inum = savino;
                }
        }
 }
 
 pass4()
 {
                }
        }
 }
 
 pass4()
 {
-       register int n;
-       register ino_t *blp;
+       register ino_t inumber, *blp;
+       int n;
+       struct inodesc idesc;
 
 
-       pfunc = pass4check;
-       for (inum = ROOTINO; inum <= lastino; inum++) {
-               switch (statemap[inum]) {
+       bzero((char *)&idesc, sizeof(struct inodesc));
+       idesc.id_type = ADDR;
+       idesc.id_func = pass4check;
+       for (inumber = ROOTINO; inumber <= lastino; inumber++) {
+               idesc.id_number = inumber;
+               switch (statemap[inumber]) {
 
                case FSTATE:
 
                case FSTATE:
-                       n = lncntp[inum];
+                       n = lncntp[inumber];
                        if (n)
                        if (n)
-                               adjust((short)n);
+                               adjust(&idesc, (short)n);
                        else {
                                for (blp = badlncnt;blp < badlnp; blp++)
                        else {
                                for (blp = badlncnt;blp < badlnp; blp++)
-                                       if (*blp == inum) {
-                                               clri("UNREF", 1);
+                                       if (*blp == inumber) {
+                                               clri(&idesc, "UNREF", 1);
                                                break;
                                        }
                        }
                        break;
 
                case DSTATE:
                                                break;
                                        }
                        }
                        break;
 
                case DSTATE:
-                       clri("UNREF", 1);
+                       clri(&idesc, "UNREF", 1);
                        break;
 
                case CLEAR:
                        break;
 
                case CLEAR:
-                       clri("BAD/DUP", 1);
+                       clri(&idesc, "BAD/DUP", 1);
                        break;
                }
        }
                        break;
                }
        }
@@ -946,22 +1117,23 @@ pass4()
        flush(&dfile, &fileblk);
 }
 
        flush(&dfile, &fileblk);
 }
 
-pass4check(blk, size)
-       daddr_t blk;
+pass4check(idesc)
+       register struct inodesc *idesc;
 {
        register daddr_t *dlp;
 {
        register daddr_t *dlp;
-       int res = KEEPON;
+       int nfrags, res = KEEPON;
+       daddr_t blkno = idesc->id_blkno;
 
 
-       for (; size > 0; blk++, size--) {
-               if (outrange(blk, 1))
+       for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
+               if (outrange(blkno, 1))
                        res = SKIP;
                        res = SKIP;
-               else if (getbmap(blk)) {
+               else if (getbmap(blkno)) {
                        for (dlp = duplist; dlp < enddup; dlp++)
                        for (dlp = duplist; dlp < enddup; dlp++)
-                               if (*dlp == blk) {
+                               if (*dlp == blkno) {
                                        *dlp = *--enddup;
                                        return (KEEPON);
                                }
                                        *dlp = *--enddup;
                                        return (KEEPON);
                                }
-                       clrbmap(blk);
+                       clrbmap(blkno);
                        n_blks--;
                }
        }
                        n_blks--;
                }
        }
@@ -983,9 +1155,9 @@ pass5()
        n_index = sblock.fs_ncg * (cgdmin(&sblock, 0) - cgtod(&sblock, 0));
        for (c = 0; c < sblock.fs_ncg; c++) {
                cbase = cgbase(&sblock, c);
        n_index = sblock.fs_ncg * (cgdmin(&sblock, 0) - cgtod(&sblock, 0));
        for (c = 0; c < sblock.fs_ncg; c++) {
                cbase = cgbase(&sblock, c);
-               bzero(botot, sizeof (botot));
-               bzero(bo, sizeof (bo));
-               bzero(frsum, sizeof (frsum));
+               bzero((char *)botot, sizeof (botot));
+               bzero((char *)bo, sizeof (bo));
+               bzero((char *)frsum, sizeof (frsum));
                /*
                 * need to account for the super blocks
                 * which appear (inaccurately) bad
                /*
                 * need to account for the super blocks
                 * which appear (inaccurately) bad
@@ -994,8 +1166,8 @@ pass5()
                if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
                        continue;
                if (cgrp.cg_magic != CG_MAGIC) {
                if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
                        continue;
                if (cgrp.cg_magic != CG_MAGIC) {
-                       pfatal("cg %d: bad magic number\n", c);
-                       bzero((caddr_t)&cgrp, sblock.fs_cgsize);
+                       pfatal("CG %d: BAD MAGIC NUMBER\n", c);
+                       bzero((char *)&cgrp, (int)sblock.fs_cgsize);
                }
                for (b = 0; b < sblock.fs_fpg; b += sblock.fs_frag) {
                        blk = blkmap(&sblock, cgrp.cg_free, b);
                }
                for (b = 0; b < sblock.fs_fpg; b += sblock.fs_frag) {
                        blk = blkmap(&sblock, cgrp.cg_free, b);
@@ -1014,11 +1186,11 @@ pass5()
                        }
                        for (d = 0; d < sblock.fs_frag; d++)
                                if ((blk & (1<<d)) &&
                        }
                        for (d = 0; d < sblock.fs_frag; d++)
                                if ((blk & (1<<d)) &&
-                                   pass5check(cbase+b+d,1) == STOP)
+                                   pass5check(cbase + b + d, (long)1) == STOP)
                                        goto out5;
                        fragacct(&sblock, blk, frsum, 1);
                }
                                        goto out5;
                        fragacct(&sblock, blk, frsum, 1);
                }
-               if (bcmp(cgrp.cg_frsum, frsum, sizeof (frsum))) {
+               if (bcmp((char *)cgrp.cg_frsum, (char *)frsum, sizeof(frsum))) {
                        if (debug)
                        for (i = 0; i < sblock.fs_frag; i++)
                                if (cgrp.cg_frsum[i] != frsum[i])
                        if (debug)
                        for (i = 0; i < sblock.fs_frag; i++)
                                if (cgrp.cg_frsum[i] != frsum[i])
@@ -1026,7 +1198,7 @@ pass5()
                                    c, i, cgrp.cg_frsum[i], frsum[i]);
                        frsumbad++;
                }
                                    c, i, cgrp.cg_frsum[i], frsum[i]);
                        frsumbad++;
                }
-               if (bcmp(cgrp.cg_btot, botot, sizeof (botot))) {
+               if (bcmp((char *)cgrp.cg_btot, (char *)botot, sizeof (botot))) {
                        if (debug)
                        for (n = 0; n < sblock.fs_cpg; n++)
                                if (botot[n] != cgrp.cg_btot[n])
                        if (debug)
                        for (n = 0; n < sblock.fs_cpg; n++)
                                if (botot[n] != cgrp.cg_btot[n])
@@ -1034,7 +1206,7 @@ pass5()
                                    c, n, cgrp.cg_btot[n], botot[n]);
                        offsumbad++;
                }
                                    c, n, cgrp.cg_btot[n], botot[n]);
                        offsumbad++;
                }
-               if (bcmp(cgrp.cg_b, bo, sizeof (bo))) {
+               if (bcmp((char *)cgrp.cg_b, (char *)bo, sizeof (bo))) {
                        if (debug)
                        for (i = 0; i < NRPOS; i++)
                                if (bo[n][i] != cgrp.cg_b[n][i])
                        if (debug)
                        for (i = 0; i < NRPOS; i++)
                                if (bo[n][i] != cgrp.cg_b[n][i])
@@ -1080,10 +1252,10 @@ out5:
 
 pass5check(blk, size)
        daddr_t blk;
 
 pass5check(blk, size)
        daddr_t blk;
-       int size;
+       long size;
 {
 
 {
 
-       if (outrange(blk, size)) {
+       if (outrange(blk, (int)size)) {
                fixcg = 1;
                if (preen)
                        pfatal("BAD BLOCKS IN BIT MAPS.");
                fixcg = 1;
                if (preen)
                        pfatal("BAD BLOCKS IN BIT MAPS.");
@@ -1105,35 +1277,42 @@ pass5check(blk, size)
        return (KEEPON);
 }
 
        return (KEEPON);
 }
 
-ckinode(dp, flg)
+ckinode(dp, idesc)
        DINODE *dp;
        DINODE *dp;
-       register flg;
+       register struct inodesc *idesc;
 {
        register daddr_t *ap;
 {
        register daddr_t *ap;
-       register ret;
-       int (*func)(), n, ndb, size, offset;
-       ino_t number = inum;
+       int ret, n, ndb, offset;
        DINODE dino;
 
        if (SPECIAL)
                return (KEEPON);
        dino = *dp;
        DINODE dino;
 
        if (SPECIAL)
                return (KEEPON);
        dino = *dp;
-       func = (flg == ADDR) ? pfunc : dirscan;
+       idesc->id_fix = DONTKNOW;
+       idesc->id_entryno = 0;
        ndb = howmany(dino.di_size, sblock.fs_bsize);
        for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
                if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
        ndb = howmany(dino.di_size, sblock.fs_bsize);
        for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
                if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
-                       size = numfrags(&sblock, fragroundup(&sblock, offset));
+                       idesc->id_numfrags =
+                               numfrags(&sblock, fragroundup(&sblock, offset));
+               else
+                       idesc->id_numfrags = sblock.fs_frag;
+               if (*ap == 0)
+                       continue;
+               idesc->id_blkno = *ap;
+               if (idesc->id_type == ADDR)
+                       ret = (*idesc->id_func)(idesc);
                else
                else
-                       size = sblock.fs_frag;
-               dnum = number;
-               if (*ap && (ret = (*func)(*ap, size)) & STOP)
+                       ret = dirscan(idesc);
+               if (ret & STOP)
                        return (ret);
        }
                        return (ret);
        }
+       idesc->id_numfrags = sblock.fs_frag;
        for (ap = &dino.di_ib[0], n = 1; n <= 2; ap++, n++) {
        for (ap = &dino.di_ib[0], n = 1; n <= 2; ap++, n++) {
-               dnum = number;
                if (*ap) {
                if (*ap) {
-                       ret = iblock(*ap, n, flg,
-                           dino.di_size - sblock.fs_bsize * NDADDR);
+                       idesc->id_blkno = *ap;
+                       ret = iblock(idesc, n,
+                               dino.di_size - sblock.fs_bsize * NDADDR);
                        if (ret & STOP)
                                return (ret);
                }
                        if (ret & STOP)
                                return (ret);
                }
@@ -1141,27 +1320,26 @@ ckinode(dp, flg)
        return (KEEPON);
 }
 
        return (KEEPON);
 }
 
-iblock(blk, ilevel, flg, isize)
-       daddr_t blk;
+iblock(idesc, ilevel, isize)
+       struct inodesc *idesc;
        register ilevel;
        register ilevel;
-       int isize;
+       long isize;
 {
        register daddr_t *ap;
        register daddr_t *aplim;
 {
        register daddr_t *ap;
        register daddr_t *aplim;
-       register int i, n;
-       int (*func)(), nif;
+       int i, n, (*func)(), nif;
        BUFAREA ib;
 
        BUFAREA ib;
 
-       if (flg == ADDR) {
-               func = pfunc;
-               if (((n = (*func)(blk, sblock.fs_frag)) & KEEPON) == 0)
+       if (idesc->id_type == ADDR) {
+               func = idesc->id_func;
+               if (((n = (*func)(idesc)) & KEEPON) == 0)
                        return (n);
        } else
                func = dirscan;
                        return (n);
        } else
                func = dirscan;
-       if (outrange(blk, sblock.fs_frag))              /* protect thyself */
+       if (outrange(idesc->id_blkno, idesc->id_numfrags)) /* protect thyself */
                return (SKIP);
        initbarea(&ib);
                return (SKIP);
        initbarea(&ib);
-       if (getblk(&ib, blk, sblock.fs_bsize) == NULL)
+       if (getblk(&ib, idesc->id_blkno, sblock.fs_bsize) == NULL)
                return (SKIP);
        ilevel--;
        if (ilevel == 0) {
                return (SKIP);
        ilevel--;
        if (ilevel == 0) {
@@ -1174,11 +1352,12 @@ iblock(blk, ilevel, flg, isize)
        aplim = &ib.b_un.b_indir[nif];
        for (ap = ib.b_un.b_indir, i = 1; ap < aplim; ap++, i++)
                if (*ap) {
        aplim = &ib.b_un.b_indir[nif];
        for (ap = ib.b_un.b_indir, i = 1; ap < aplim; ap++, i++)
                if (*ap) {
+                       idesc->id_blkno = *ap;
                        if (ilevel > 0)
                        if (ilevel > 0)
-                               n = iblock(*ap, ilevel, flg,
+                               n = iblock(idesc, ilevel,
                                    isize - i*NINDIR(&sblock)*sblock.fs_bsize);
                        else
                                    isize - i*NINDIR(&sblock)*sblock.fs_bsize);
                        else
-                               n = (*func)(*ap, sblock.fs_frag);
+                               n = (*func)(idesc);
                        if (n & STOP)
                                return (n);
                }
                        if (n & STOP)
                                return (n);
                }
@@ -1218,176 +1397,195 @@ outrange(blk, cnt)
        return (0);
 }
 
        return (0);
 }
 
-blkerr(s, blk)
-       daddr_t blk;
+blkerr(ino, s, blk)
+       ino_t ino;
        char *s;
        char *s;
+       daddr_t blk;
 {
 
 {
 
-       pfatal("%ld %s I=%u", blk, s, inum);
+       pfatal("%ld %s I=%u", blk, s, ino);
        printf("\n");
        printf("\n");
-       statemap[inum] = CLEAR;
+       statemap[ino] = CLEAR;
 }
 
 }
 
-descend()
+descend(parentino, inumber)
+       struct inodesc *parentino;
+       ino_t inumber;
 {
        register DINODE *dp;
 {
        register DINODE *dp;
-       register char *savname;
-       off_t savsize;
+       struct inodesc curino;
 
 
-       statemap[inum] = FSTATE;
-       if ((dp = ginode()) == NULL)
+       bzero((char *)&curino, sizeof(struct inodesc));
+       statemap[inumber] = FSTATE;
+       if ((dp = ginode(inumber)) == NULL)
                return;
                return;
-       savname = thisname;
-       *pathp++ = '/';
-       savsize = filsize;
-       filsize = dp->di_size;
-       ckinode(dp, DATA);
-       thisname = savname;
-       *--pathp = 0;
-       filsize = savsize;
+       if (dp->di_size == 0) {
+               direrr(inumber, "ZERO LENGTH DIRECTORY");
+               if (reply("REMOVE") == 1)
+                       statemap[inumber] = CLEAR;
+               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;
+       curino.id_filesize = dp->di_size;
+       (void)ckinode(dp, &curino);
 }
 
 }
 
-struct dirstuff {
-       int loc;
-       int blkno;
-       int blksiz;
-       ino_t number;
-       enum {DONTKNOW, NOFIX, FIX} fix;
-};
-
-dirscan(blk, nf)
-       daddr_t blk;
-       int nf;
+dirscan(idesc)
+       register struct inodesc *idesc;
 {
        register DIRECT *dp;
 {
        register DIRECT *dp;
-       struct dirstuff dirp;
-       int blksiz, dsize, n;
+       int dsize, n;
+       long blksiz;
        char dbuf[DIRBLKSIZ];
 
        char dbuf[DIRBLKSIZ];
 
-       if (outrange(blk, 1)) {
-               filsize -= sblock.fs_bsize;
+       if (idesc->id_type != DATA)
+               errexit("wrong type to dirscan %d\n", idesc->id_type);
+       blksiz = idesc->id_numfrags * sblock.fs_fsize;
+       if (outrange(idesc->id_blkno, idesc->id_numfrags)) {
+               idesc->id_filesize -= blksiz;
                return (SKIP);
        }
                return (SKIP);
        }
-       blksiz = nf * sblock.fs_fsize;
-       dirp.loc = 0;
-       dirp.blkno = blk;
-       dirp.blksiz = blksiz;
-       if (dirp.number != dnum) {
-               dirp.number = dnum;
-               dirp.fix = DONTKNOW;
-       }
-       for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
+       idesc->id_loc = 0;
+       for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
                dsize = dp->d_reclen;
                dsize = dp->d_reclen;
-               bcopy(dp, dbuf, dsize);
-               if ((n = (*pfunc)(dbuf)) & ALTERD) {
-                       if (getblk(&fileblk, blk, blksiz) != NULL) {
-                               bcopy(dbuf, dp, dsize);
+               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
                                dirty(&fileblk);
                                sbdirty();
                        } else
-                               n &= ~ALTERD;
+                               n &= ~ALTERED;
                }
                if (n & STOP) 
                        return (n);
        }
                }
                if (n & STOP) 
                        return (n);
        }
-       return (filsize > 0 ? KEEPON : STOP);
+       return (idesc->id_filesize > 0 ? KEEPON : STOP);
 }
 
 /*
  * get next entry in a directory.
  */
 DIRECT *
 }
 
 /*
  * get next entry in a directory.
  */
 DIRECT *
-readdir(dirp)
-       register struct dirstuff *dirp;
+fsck_readdir(idesc)
+       register struct inodesc *idesc;
 {
        register DIRECT *dp, *ndp;
 {
        register DIRECT *dp, *ndp;
-       long size;
+       long size, blksiz;
 
 
-       if (getblk(&fileblk, dirp->blkno, dirp->blksiz) == NULL) {
-               filsize -= dirp->blksiz - dirp->loc;
+       blksiz = idesc->id_numfrags * sblock.fs_fsize;
+       if (getblk(&fileblk, idesc->id_blkno, blksiz) == NULL) {
+               idesc->id_filesize -= blksiz - idesc->id_loc;
                return NULL;
        }
                return NULL;
        }
-       while (dirp->loc % DIRBLKSIZ == 0 && filsize > 0 &&
-           dirp->loc < dirp->blksiz) {
-               dp = (DIRECT *)(dirblk.b_buf + dirp->loc);
-               if (dp->d_ino < imax &&
-                   dp->d_namlen <= MAXNAMLEN && dp->d_namlen >= 0 &&
-                   dp->d_reclen > 0 && dp->d_reclen <= DIRBLKSIZ)
-                       break;
-               dirp->loc += DIRBLKSIZ;
-               filsize -= DIRBLKSIZ;
-               if (dirp->fix == DONTKNOW) {
-                       pfatal("DIRECTORY %D CORRUPTED", dirp->number);
-                       dirp->fix = NOFIX;
-                       if (reply("SALVAGE") != 0)
-                               dirp->fix = FIX;
-               }
-               if (dirp->fix != FIX)
-                       continue;
+       if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
+           idesc->id_loc < blksiz) {
+               dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
+               if (dircheck(idesc, dp))
+                       goto dpok;
+               idesc->id_loc += DIRBLKSIZ;
+               idesc->id_filesize -= DIRBLKSIZ;
                dp->d_reclen = DIRBLKSIZ;
                dp->d_ino = 0;
                dp->d_namlen = 0;
                dp->d_reclen = DIRBLKSIZ;
                dp->d_ino = 0;
                dp->d_namlen = 0;
-               dirty(&fileblk);
+               dp->d_name[0] = '\0';
+               if (dofix(idesc))
+                       dirty(&fileblk);
+               return (dp);
        }
        }
-       if (filsize <= 0 || dirp->loc >= dirp->blksiz)
+dpok:
+       if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
                return NULL;
                return NULL;
-       dp = (DIRECT *)(dirblk.b_buf + dirp->loc);
-       dirp->loc += dp->d_reclen;
-       filsize -= dp->d_reclen;
-       ndp = (DIRECT *)(dirblk.b_buf + dirp->loc);
-       if ((filsize <= 0 && dirp->loc % DIRBLKSIZ != 0) ||
-           (dirp->loc < dirp->blksiz && filsize > 0 &&
-           (ndp->d_ino >= imax ||
-           ndp->d_namlen > MAXNAMLEN || ndp->d_namlen < 0 ||
-           ndp->d_reclen <= 0 || 
-           ndp->d_reclen > DIRBLKSIZ - (dirp->loc % DIRBLKSIZ)))) {
-               size = DIRBLKSIZ - (dirp->loc % DIRBLKSIZ);
-               dirp->loc += size;
-               filsize -= size;
-               if (dirp->fix == DONTKNOW) {
-                       pfatal("DIRECTORY %D CORRUPTED", dirp->number);
-                       dirp->fix = NOFIX;
-                       if (reply("SALVAGE") != 0)
-                               dirp->fix = FIX;
-               }
-               if (dirp->fix == FIX) {
-                       dp->d_reclen += size;
+       dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
+       idesc->id_loc += dp->d_reclen;
+       idesc->id_filesize -= dp->d_reclen;
+       ndp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
+       if ((idesc->id_filesize <= 0 && idesc->id_loc % DIRBLKSIZ != 0) ||
+           (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))
                        dirty(&fileblk);
                        dirty(&fileblk);
-               }
        }
        return (dp);
 }
 
        }
        return (dp);
 }
 
-direrr(s)
+/*
+ * Verify that a directory entry is valid.
+ * This is a superset of the checks made in the kernel.
+ */
+dircheck(idesc, dp)
+       struct inodesc *idesc;
+       register DIRECT *dp;
+{
+       register int size;
+       register char *cp;
+       int spaceleft;
+
+       size = DIRSIZ(dp);
+       spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
+       if (dp->d_ino < imax &&
+           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) {
+               if (dp->d_ino == 0)
+                       return (1);
+               for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++)
+                       if (*cp == 0 || (*cp++ & 0200))
+                               return (0);
+               if (*cp == 0)
+                       return (1);
+       }
+       return (0);
+}
+
+direrr(ino, s)
+       ino_t ino;
        char *s;
 {
        register DINODE *dp;
 
        pwarn("%s ", s);
        char *s;
 {
        register DINODE *dp;
 
        pwarn("%s ", s);
-       pinode();
+       pinode(ino);
        printf("\n");
        printf("\n");
-       if ((dp = ginode()) != NULL && ftypeok(dp))
-               pfatal("%s=%s", DIRCT?"DIR":"FILE", pathname);
+       if ((dp = ginode(ino)) != NULL && ftypeok(dp))
+               pfatal("%s=%s\n", DIRCT?"DIR":"FILE", pathname);
        else
        else
-               pfatal("NAME=%s", pathname);
-       return (reply("REMOVE"));
+               pfatal("NAME=%s\n", pathname);
 }
 
 }
 
-adjust(lcnt)
-       register short lcnt;
+adjust(idesc, lcnt)
+       register struct inodesc *idesc;
+       short lcnt;
 {
        register DINODE *dp;
 
 {
        register DINODE *dp;
 
-       if ((dp = ginode()) == NULL)
+       if ((dp = ginode(idesc->id_number)) == NULL)
                return;
        if (dp->di_nlink == lcnt) {
                return;
        if (dp->di_nlink == lcnt) {
-               if (linkup() == 0)
-                       clri("UNREF", 0);
+               if (linkup(idesc->id_number, (ino_t)0) == 0)
+                       clri(idesc, "UNREF", 0);
        }
        else {
                pwarn("LINK COUNT %s",
        }
        else {
                pwarn("LINK COUNT %s",
-                       (lfdir==inum)?lfname:(DIRCT?"DIR":"FILE"));
-               pinode();
+                       (lfdir==idesc->id_number)?lfname:(DIRCT?"DIR":"FILE"));
+               pinode(idesc->id_number);
                printf(" COUNT %d SHOULD BE %d",
                        dp->di_nlink, dp->di_nlink-lcnt);
                if (preen) {
                printf(" COUNT %d SHOULD BE %d",
                        dp->di_nlink, dp->di_nlink-lcnt);
                if (preen) {
@@ -1404,25 +1602,26 @@ adjust(lcnt)
        }
 }
 
        }
 }
 
-clri(s, flg)
+clri(idesc, s, flg)
+       register struct inodesc *idesc;
        char *s;
        char *s;
+       int flg;
 {
        register DINODE *dp;
 
 {
        register DINODE *dp;
 
-       if ((dp = ginode()) == NULL)
+       if ((dp = ginode(idesc->id_number)) == NULL)
                return;
        if (flg == 1) {
                pwarn("%s %s", s, DIRCT?"DIR":"FILE");
                return;
        if (flg == 1) {
                pwarn("%s %s", s, DIRCT?"DIR":"FILE");
-               pinode();
+               pinode(idesc->id_number);
        }
        if (preen || reply("CLEAR") == 1) {
                if (preen)
                        printf(" (CLEARED)\n");
                n_files--;
        }
        if (preen || reply("CLEAR") == 1) {
                if (preen)
                        printf(" (CLEARED)\n");
                n_files--;
-               pfunc = pass4check;
-               ckinode(dp, ADDR);
+               (void)ckinode(dp, idesc);
                zapino(dp);
                zapino(dp);
-               statemap[inum] = USTATE;
+               statemap[idesc->id_number] = USTATE;
                inodirty();
                inosumbad++;
        }
                inodirty();
                inosumbad++;
        }
@@ -1440,23 +1639,27 @@ badsb(s)
 }
 
 DINODE *
 }
 
 DINODE *
-ginode()
+ginode(inumber)
+       ino_t inumber;
 {
        daddr_t iblk;
 {
        daddr_t iblk;
+       static ino_t startinum = 0;     /* blk num of first in raw area */
 
 
-       if (inum < ROOTINO || inum > imax) {
-               if (debug && (inum < 0 || inum > imax))
-                       printf("inum out of range (%d)\n", inum);
+
+       if (inumber < ROOTINO || inumber > imax) {
+               if (debug && inumber > imax)
+                       printf("inumber out of range (%d)\n", inumber);
                return (NULL);
        }
                return (NULL);
        }
-       if (inum < startinum || inum >= startinum + INOPB(&sblock)) {
-               iblk = itod(&sblock, inum);
+       if (startinum == 0 ||
+           inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
+               iblk = itod(&sblock, inumber);
                if (getblk(&inoblk, iblk, sblock.fs_bsize) == NULL) {
                        return (NULL);
                }
                if (getblk(&inoblk, iblk, sblock.fs_bsize) == NULL) {
                        return (NULL);
                }
-               startinum = (inum / INOPB(&sblock)) * INOPB(&sblock);
+               startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
        }
        }
-       return (&inoblk.b_un.b_dinode[inum % INOPB(&sblock)]);
+       return (&inoblk.b_un.b_dinode[inumber % INOPB(&sblock)]);
 }
 
 ftypeok(dp)
 }
 
 ftypeok(dp)
@@ -1469,6 +1672,7 @@ ftypeok(dp)
        case IFBLK:
        case IFCHR:
        case IFLNK:
        case IFBLK:
        case IFCHR:
        case IFLNK:
+       case IFSOCK:
                return (1);
 
        default:
                return (1);
 
        default:
@@ -1525,9 +1729,9 @@ getline(fp, loc, maxlen)
 
 BUFAREA *
 getblk(bp, blk, size)
 
 BUFAREA *
 getblk(bp, blk, size)
-       daddr_t blk;
        register BUFAREA *bp;
        register BUFAREA *bp;
-       int size;
+       daddr_t blk;
+       long size;
 {
        register struct filecntl *fcp;
        daddr_t dblk;
 {
        register struct filecntl *fcp;
        daddr_t dblk;
@@ -1552,7 +1756,7 @@ flush(fcp, bp)
 {
 
        if (bp->b_dirty)
 {
 
        if (bp->b_dirty)
-               bwrite(fcp, bp->b_un.b_buf, bp->b_bno, bp->b_size);
+               (void)bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
        bp->b_dirty = 0;
 }
 
        bp->b_dirty = 0;
 }
 
@@ -1579,19 +1783,20 @@ ckfini()
                flush(&dfile, &sblk);
        }
        flush(&dfile, &inoblk);
                flush(&dfile, &sblk);
        }
        flush(&dfile, &inoblk);
-       close(dfile.rfdes);
-       close(dfile.wfdes);
+       (void)close(dfile.rfdes);
+       (void)close(dfile.wfdes);
 }
 
 }
 
-pinode()
+pinode(ino)
+       ino_t ino;
 {
        register DINODE *dp;
        register char *p;
        char uidbuf[BUFSIZ];
        char *ctime();
 
 {
        register DINODE *dp;
        register char *p;
        char uidbuf[BUFSIZ];
        char *ctime();
 
-       printf(" I=%u ", inum);
-       if ((dp = ginode()) == NULL)
+       printf(" I=%u ", ino);
+       if ((dp = ginode(ino)) == NULL)
                return;
        printf(" OWNER=");
        if (getpw((int)dp->di_uid, uidbuf) == 0) {
                return;
        printf(" OWNER=");
        if (getpw((int)dp->di_uid, uidbuf) == 0) {
@@ -1615,6 +1820,7 @@ makecg()
        int c, blk;
        daddr_t dbase, d, dlower, dupper, dmax;
        long i, j, s;
        int c, blk;
        daddr_t dbase, d, dlower, dupper, dmax;
        long i, j, s;
+       ino_t inumber;
        register struct csum *cs;
        register DINODE *dp;
 
        register struct csum *cs;
        register DINODE *dp;
 
@@ -1633,7 +1839,7 @@ makecg()
                dlower = cgsblock(&sblock, c) - dbase;
                dupper = cgdmin(&sblock, c) - dbase;
                cs = &sblock.fs_cs(&sblock, c);
                dlower = cgsblock(&sblock, c) - dbase;
                dupper = cgdmin(&sblock, c) - dbase;
                cs = &sblock.fs_cs(&sblock, c);
-               cgrp.cg_time = time(0);
+               (void)time(&cgrp.cg_time);
                cgrp.cg_magic = CG_MAGIC;
                cgrp.cg_cgx = c;
                if (c == sblock.fs_ncg - 1)
                cgrp.cg_magic = CG_MAGIC;
                cgrp.cg_cgx = c;
                if (c == sblock.fs_ncg - 1)
@@ -1651,11 +1857,11 @@ makecg()
                cgrp.cg_irotor = 0;
                for (i = 0; i < sblock.fs_frag; i++)
                        cgrp.cg_frsum[i] = 0;
                cgrp.cg_irotor = 0;
                for (i = 0; i < sblock.fs_frag; i++)
                        cgrp.cg_frsum[i] = 0;
-               inum = sblock.fs_ipg * c;
-               for (i = 0; i < sblock.fs_ipg; inum++, i++) {
+               inumber = sblock.fs_ipg * c;
+               for (i = 0; i < sblock.fs_ipg; inumber++, i++) {
                        cgrp.cg_cs.cs_nifree++;
                        clrbit(cgrp.cg_iused, i);
                        cgrp.cg_cs.cs_nifree++;
                        clrbit(cgrp.cg_iused, i);
-                       dp = ginode();
+                       dp = ginode(inumber);
                        if (dp == NULL)
                                continue;
                        if (ALLOC) {
                        if (dp == NULL)
                                continue;
                        if (ALLOC) {
@@ -1726,11 +1932,11 @@ makecg()
                sblock.fs_cstotal.cs_nifree += cgrp.cg_cs.cs_nifree;
                sblock.fs_cstotal.cs_ndir += cgrp.cg_cs.cs_ndir;
                *cs = cgrp.cg_cs;
                sblock.fs_cstotal.cs_nifree += cgrp.cg_cs.cs_nifree;
                sblock.fs_cstotal.cs_ndir += cgrp.cg_cs.cs_ndir;
                *cs = cgrp.cg_cs;
-               bwrite(&dfile, &cgrp, fsbtodb(&sblock, cgtod(&sblock, c)),
-                   sblock.fs_cgsize);
+               (void)bwrite(&dfile, (char *)&cgrp,
+                       fsbtodb(&sblock, cgtod(&sblock, c)), sblock.fs_cgsize);
        }
        for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
        }
        for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
-               bwrite(&dfile, (char *)sblock.fs_csp[j],
+               (void)bwrite(&dfile, (char *)sblock.fs_csp[j],
                    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
                    sblock.fs_cssize - i < sblock.fs_bsize ?
                    sblock.fs_cssize - i : sblock.fs_bsize);
                    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
                    sblock.fs_cssize - i < sblock.fs_bsize ?
                    sblock.fs_cssize - i : sblock.fs_bsize);
@@ -1740,24 +1946,25 @@ makecg()
        sbdirty();
 }
 
        sbdirty();
 }
 
-findino(dirp)
-       register DIRECT *dirp;
+findino(idesc)
+       struct inodesc *idesc;
 {
 {
+       register DIRECT *dirp = idesc->id_dirp;
+
        if (dirp->d_ino == 0)
                return (KEEPON);
        if (!strcmp(dirp->d_name, srchname)) {
                if (dirp->d_ino >= ROOTINO && dirp->d_ino <= imax)
        if (dirp->d_ino == 0)
                return (KEEPON);
        if (!strcmp(dirp->d_name, srchname)) {
                if (dirp->d_ino >= ROOTINO && dirp->d_ino <= imax)
-                       parentdir = dirp->d_ino;
+                       idesc->id_parent = dirp->d_ino;
                return (STOP);
        }
        return (KEEPON);
 }
 
                return (STOP);
        }
        return (KEEPON);
 }
 
-mkentry(dirp)
-       register DIRECT *dirp;
+mkentry(idesc)
+       struct inodesc *idesc;
 {
 {
-       register ino_t in;
-       register char *p;
+       register DIRECT *dirp = idesc->id_dirp;
        DIRECT newent;
        int newlen, oldlen;
 
        DIRECT newent;
        int newlen, oldlen;
 
@@ -1772,45 +1979,39 @@ mkentry(dirp)
        newent.d_reclen = dirp->d_reclen - oldlen;
        dirp->d_reclen = oldlen;
        dirp = (struct direct *)(((char *)dirp) + oldlen);
        newent.d_reclen = dirp->d_reclen - oldlen;
        dirp->d_reclen = oldlen;
        dirp = (struct direct *)(((char *)dirp) + oldlen);
-       dirp->d_ino = orphan;
+       dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */
        dirp->d_reclen = newent.d_reclen;
        dirp->d_reclen = newent.d_reclen;
-       p = &dirp->d_name[2];
-       for (in = imax; in > 0; in /= 10)
-               p++;
-       *--p = 0;
-       dirp->d_namlen = p - dirp->d_name;
-       in = orphan;
-       while (p > dirp->d_name) {
-               *--p = (in % 10) + '0';
-               in /= 10;
-       }
-       *p = '#';
-       return (ALTERD|STOP);
+       dirp->d_namlen = lftempname(dirp->d_name, idesc->id_parent);
+       return (ALTERED|STOP);
 }
 
 }
 
-chgdd(dirp)
-       register DIRECT *dirp;
+chgdd(idesc)
+       struct inodesc *idesc;
 {
 {
+       register DIRECT *dirp = idesc->id_dirp;
+
        if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' &&
        dirp->d_name[2] == 0) {
                dirp->d_ino = lfdir;
        if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' &&
        dirp->d_name[2] == 0) {
                dirp->d_ino = lfdir;
-               return (ALTERD|STOP);
+               return (ALTERED|STOP);
        }
        return (KEEPON);
 }
 
        }
        return (KEEPON);
 }
 
-linkup()
+linkup(orphan, pdir)
+       ino_t orphan;
+       ino_t pdir;
 {
        register DINODE *dp;
 {
        register DINODE *dp;
-       register lostdir;
-       register ino_t pdir;
+       int lostdir, len;
+       struct inodesc idesc;
 
 
-       if ((dp = ginode()) == NULL)
+       bzero((char *)&idesc, sizeof(struct inodesc));
+       if ((dp = ginode(orphan)) == NULL)
                return (0);
        lostdir = DIRCT;
                return (0);
        lostdir = DIRCT;
-       pdir = parentdir;
        pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
        pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
-       pinode();
+       pinode(orphan);
        if (preen && dp->di_size == 0)
                return (0);
        if (preen)
        if (preen && dp->di_size == 0)
                return (0);
        if (preen)
@@ -1818,28 +2019,26 @@ linkup()
        else
                if (reply("RECONNECT") == 0)
                        return (0);
        else
                if (reply("RECONNECT") == 0)
                        return (0);
-       orphan = inum;
+       pathp = pathname;
+       *pathp++ = '/';
+       *pathp = '\0';
        if (lfdir == 0) {
        if (lfdir == 0) {
-               inum = ROOTINO;
-               if ((dp = ginode()) == NULL) {
-                       inum = orphan;
+               if ((dp = ginode(ROOTINO)) == NULL)
                        return (0);
                        return (0);
-               }
-               pfunc = findino;
                srchname = lfname;
                srchname = lfname;
-               filsize = dp->di_size;
-               parentdir = 0;
-               ckinode(dp, DATA);
-               inum = orphan;
-               if ((lfdir = parentdir) == 0) {
+               idesc.id_type = DATA;
+               idesc.id_func = findino;
+               idesc.id_number = ROOTINO;
+               idesc.id_filesize = dp->di_size;
+               (void)ckinode(dp, &idesc);
+               if ((lfdir = idesc.id_parent) == 0) {
                        pfatal("SORRY. NO lost+found DIRECTORY");
                        printf("\n\n");
                        return (0);
                }
        }
                        pfatal("SORRY. NO lost+found DIRECTORY");
                        printf("\n\n");
                        return (0);
                }
        }
-       inum = lfdir;
-       if ((dp = ginode()) == NULL || !DIRCT || statemap[inum] != FSTATE) {
-               inum = orphan;
+       if ((dp = ginode(lfdir)) == NULL ||
+            !DIRCT || statemap[lfdir] != FSTATE) {
                pfatal("SORRY. NO lost+found DIRECTORY");
                printf("\n\n");
                return (0);
                pfatal("SORRY. NO lost+found DIRECTORY");
                printf("\n\n");
                return (0);
@@ -1848,27 +2047,36 @@ linkup()
                dp->di_size = fragroundup(&sblock, dp->di_size);
                inodirty();
        }
                dp->di_size = fragroundup(&sblock, dp->di_size);
                inodirty();
        }
-       filsize = dp->di_size;
-       inum = orphan;
-       pfunc = mkentry;
-       if ((ckinode(dp, DATA) & ALTERD) == 0) {
+       len = strlen(lfname);
+       bcopy(lfname, pathp, len + 1);
+       pathp += len;
+       idesc.id_type = DATA;
+       idesc.id_func = mkentry;
+       idesc.id_number = lfdir;
+       idesc.id_filesize = dp->di_size;
+       idesc.id_parent = orphan;       /* this is the inode to enter */
+       idesc.id_fix = DONTKNOW;
+       if ((ckinode(dp, &idesc) & ALTERED) == 0) {
                pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
                printf("\n\n");
                return (0);
        }
                pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
                printf("\n\n");
                return (0);
        }
-       lncntp[inum]--;
+       lncntp[orphan]--;
+       *pathp++ = '/';
+       pathp += lftempname(pathp, orphan);
        if (lostdir) {
        if (lostdir) {
-               pfunc = chgdd;
-               dp = ginode();
-               filsize = dp->di_size;
-               ckinode(dp, DATA);
-               inum = lfdir;
-               if ((dp = ginode()) != NULL) {
+               dp = ginode(orphan);
+               idesc.id_type = DATA;
+               idesc.id_func = chgdd;
+               idesc.id_number = orphan;
+               idesc.id_filesize = dp->di_size;
+               idesc.id_fix = DONTKNOW;
+               (void)ckinode(dp, &idesc);
+               if ((dp = ginode(lfdir)) != NULL) {
                        dp->di_nlink++;
                        inodirty();
                        dp->di_nlink++;
                        inodirty();
-                       lncntp[inum]++;
+                       lncntp[lfdir]++;
                }
                }
-               inum = orphan;
                pwarn("DIR I=%u CONNECTED. ", orphan);
                printf("PARENT WAS I=%u\n", pdir);
                if (preen == 0)
                pwarn("DIR I=%u CONNECTED. ", orphan);
                printf("PARENT WAS I=%u\n", pdir);
                if (preen == 0)
@@ -1877,32 +2085,57 @@ linkup()
        return (1);
 }
 
        return (1);
 }
 
+/*
+ * generate a temporary name for the lost+found directory.
+ */
+lftempname(bufp, ino)
+       char *bufp;
+       ino_t ino;
+{
+       register ino_t in;
+       register char *cp;
+       int namlen;
+
+       cp = bufp + 2;
+       for (in = imax; in > 0; in /= 10)
+               cp++;
+       *--cp = 0;
+       namlen = cp - bufp;
+       in = ino;
+       while (cp > bufp) {
+               *--cp = (in % 10) + '0';
+               in /= 10;
+       }
+       *cp = '#';
+       return (namlen);
+}
+
 bread(fcp, buf, blk, size)
 bread(fcp, buf, blk, size)
-       daddr_t blk;
        register struct filecntl *fcp;
        register struct filecntl *fcp;
-       register size;
        char *buf;
        char *buf;
+       daddr_t blk;
+       long size;
 {
 {
-       if (lseek(fcp->rfdes, blk * DEV_BSIZE, 0) < 0)
+       if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0)
                rwerr("SEEK", blk);
                rwerr("SEEK", blk);
-       else if (read(fcp->rfdes, buf, size) == size)
+       else if (read(fcp->rfdes, buf, (int)size) == size)
                return (1);
        rwerr("READ", blk);
        return (0);
 }
 
 bwrite(fcp, buf, blk, size)
                return (1);
        rwerr("READ", blk);
        return (0);
 }
 
 bwrite(fcp, buf, blk, size)
-       daddr_t blk;
        register struct filecntl *fcp;
        register struct filecntl *fcp;
-       register size;
        char *buf;
        char *buf;
+       daddr_t blk;
+       long size;
 {
 
        if (fcp->wfdes < 0)
                return (0);
 {
 
        if (fcp->wfdes < 0)
                return (0);
-       if (lseek(fcp->wfdes, blk * DEV_BSIZE, 0) < 0)
+       if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0)
                rwerr("SEEK", blk);
                rwerr("SEEK", blk);
-       else if (write(fcp->wfdes, buf, size) == size) {
+       else if (write(fcp->wfdes, buf, (int)size) == size) {
                fcp->mod = 1;
                return (1);
        }
                fcp->mod = 1;
                return (1);
        }
@@ -1932,7 +2165,7 @@ unrawname(cp)
                return (cp);
        if (*(dp+1) != 'r')
                return (cp);
                return (cp);
        if (*(dp+1) != 'r')
                return (cp);
-       strcpy(dp+1, dp+2);
+       (void)strcpy(dp+1, dp+2);
        return (cp);
 }
 
        return (cp);
 }
 
@@ -1946,13 +2179,43 @@ rawname(cp)
        if (dp == 0)
                return (0);
        *dp = 0;
        if (dp == 0)
                return (0);
        *dp = 0;
-       strcpy(rawbuf, cp);
+       (void)strcpy(rawbuf, cp);
        *dp = '/';
        *dp = '/';
-       strcat(rawbuf, "/r");
-       strcat(rawbuf, dp+1);
+       (void)strcat(rawbuf, "/r");
+       (void)strcat(rawbuf, dp+1);
        return (rawbuf);
 }
 
        return (rawbuf);
 }
 
+/*
+ * determine whether an inode should be fixed.
+ */
+dofix(idesc)
+       register struct inodesc *idesc;
+{
+
+       switch (idesc->id_fix) {
+
+       case DONTKNOW:
+               direrr(idesc->id_number, "DIRECTORY CORRUPTED");
+               if (reply("SALVAGE") == 0) {
+                       idesc->id_fix = NOFIX;
+                       return (0);
+               }
+               idesc->id_fix = FIX;
+               return (ALTERED);
+
+       case FIX:
+               return (ALTERED);
+
+       case NOFIX:
+               return (0);
+
+       default:
+               errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
+       }
+       /* NOTREACHED */
+}
+
 /* VARARGS1 */
 error(s1, s2, s3, s4)
        char *s1;
 /* VARARGS1 */
 error(s1, s2, s3, s4)
        char *s1;
@@ -2008,10 +2271,15 @@ pwarn(s, a1, a2, a3, a4, a5, a6)
        printf(s, a1, a2, a3, a4, a5, a6);
 }
 
        printf(s, a1, a2, a3, a4, a5, a6);
 }
 
+#ifndef lint
+/*
+ * Stub for routines from kernel.
+ */
 panic(s)
        char *s;
 {
 
 panic(s)
        char *s;
 {
 
-       pfatal("internal inconsistency: %s\n");
+       pfatal("INTERNAL INCONSISTENCY: %s\n", s);
        exit(12);
 }
        exit(12);
 }
+#endif