X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/76123246624f9102eeb70c4afee5a331e4bdf6e5..e2326c44aa7105886be6e0b2d2ce507b1f588540:/usr/src/sbin/fsck/main.c diff --git a/usr/src/sbin/fsck/main.c b/usr/src/sbin/fsck/main.c index 260d898ea3..37170372cf 100644 --- a/usr/src/sbin/fsck/main.c +++ b/usr/src/sbin/fsck/main.c @@ -1,20 +1,27 @@ -static char *sccsid = "@(#)main.c 1.30 (Berkeley) %G%"; +#ifndef lint +char version[] = "@(#)main.c 2.30 (Berkeley) %G%"; +#endif #include #include -#include "../h/param.h" -#include "../h/fs.h" -#include "../h/inode.h" -#include "../h/stat.h" -#include "../h/ostat.h" -#include +#include +#include +#include +#include +#include #include +#define KERNEL +#include +#undef KERNEL + +/* RECONSTRUCT ONLY BAD CG IN PASS 6 */ typedef int (*SIG_TYP)(); #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) */ @@ -32,10 +39,11 @@ typedef struct direct DIRECT; #define REG ((dp->di_mode & IFMT) == IFREG) #define BLK ((dp->di_mode & IFMT) == IFBLK) #define CHR ((dp->di_mode & IFMT) == IFCHR) +#define LNK ((dp->di_mode & IFMT) == IFLNK) +#define SOCK ((dp->di_mode & IFMT) == IFSOCK) +#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; @@ -56,7 +64,7 @@ typedef struct bufarea BUFAREA; 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 @@ -74,12 +82,30 @@ struct filecntl { 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 */ daddr_t *muldup; /* multiple dups part of table */ -#define MAXLNCNT 20 /* num zero link cnts to remember */ +#define MAXLNCNT 500 /* num zero link cnts to remember */ ino_t badlncnt[MAXLNCNT]; /* table of inos with zero link cnts */ ino_t *badlnp; /* next entry in table */ @@ -98,21 +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 *pathp; /* pointer to pathname position */ -char *thisname; /* ptr to current pathname component */ 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"; -ino_t inum; /* inode we are currently working on */ 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 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 */ @@ -130,14 +152,11 @@ daddr_t dupblk; int inosumbad; int offsumbad; int frsumbad; +int sbsumbad; #define zapino(x) (*(x) = zino) struct dinode zino; -#define setlncnt(x) (lncntp[inum] = x) -#define getlncnt() (lncntp[inum]) -#define declncnt() (--lncntp[inum]) - #define setbmap(x) setbit(blockmap, x) #define getbmap(x) isset(blockmap, x) #define clrbmap(x) clrbit(blockmap, x) @@ -146,13 +165,7 @@ struct dinode zino; #define getfmap(x) isset(freemap, x) #define clrfmap(x) clrbit(freemap, x) -#define setstate(x) (statemap[inum] = x) -#define getstate() statemap[inum] - -#define DATA 1 -#define ADDR 0 - -#define ALTERD 010 +#define ALTERED 010 #define KEEPON 04 #define SKIP 02 #define STOP 01 @@ -161,15 +174,13 @@ int (*signal())(); long lseek(); time_t time(); DINODE *ginode(); +DIRECT *fsck_readdir(); BUFAREA *getblk(); -int dirscan(); -int findino(); int catch(); -int mkentry(); -int chgdd(); -int pass1(), pass1b(), pass2(), pass4(), pass5(); -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[]; @@ -191,7 +202,12 @@ main(argc, argv) 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; @@ -216,11 +232,11 @@ main(argc, argv) } } if (signal(SIGINT, SIG_IGN) != SIG_IGN) - signal(SIGINT, catch); + (void)signal(SIGINT, catch); if (argc) { while (argc-- > 0) { hotroot = 0; - check(*argv++); + checkfilesys(*argv++); } exit(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) && - 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) { @@ -254,22 +271,22 @@ main(argc, argv) } } if (preen) { - int status; + union wait status; while (wait(&status) != -1) - sumstatus |= status; + sumstatus |= status.w_retcode; } passno++; } while (anygtr); if (sumstatus) exit(8); - endfsent(); + (void)endfsent(); exit(0); } blockcheck(name) char *name; { - struct ostat stslash, stblock, stchar; + struct stat stslash, stblock, stchar; char *raw; int looped = 0; @@ -294,7 +311,7 @@ retry: hotroot++; raw = unrawname(name); } - check(raw); + checkfilesys(raw); return (1); } else { error("%s is not a character device\n", raw); @@ -313,73 +330,274 @@ retry: return (0); } -char * -unrawname(cp) - char *cp; +checkfilesys(filesys) + char *filesys; { - char *dp = rindex(cp, '/'); - struct ostat stb; - if (dp == 0) - return (cp); - if (stat(cp, &stb) < 0) - return (cp); - if ((stb.st_mode&S_IFMT) != S_IFCHR) - return (cp); - if (*(dp+1) != 'r') - return (cp); - strcpy(dp+1, dp+2); - return (cp); -} + devname = filesys; + if (setup(filesys) == 0) { + if (preen) + pfatal("CAN'T CHECK FILE SYSTEM."); + return; + } +/* 1: scan inodes tallying blocks used */ + if (preen == 0) { + printf("** Last Mounted on %s\n", sblock.fs_fsmnt); + if (hotroot) + printf("** Root file system\n"); + printf("** Phase 1 - Check Blocks and Sizes\n"); + } + pass1(); -char * -rawname(cp) - char *cp; -{ - static char rawbuf[32]; - char *dp = rindex(cp, '/'); +/* 1b: locate first references to duplicates, if any */ + if (enddup != &duplist[0]) { + if (preen) + pfatal("INTERNAL ERROR: dups with -p"); + printf("** Phase 1b - Rescan For More DUPS\n"); + pass1b(); + } - if (dp == 0) - return (0); - *dp = 0; - strcpy(rawbuf, cp); - *dp = '/'; - strcat(rawbuf, "/r"); - strcat(rawbuf, dp+1); - return (rawbuf); +/* 2: traverse directories from root to mark all connected directories */ + if (preen == 0) + printf("** Phase 2 - Check Pathnames\n"); + pass2(); + +/* 3: scan inodes looking for disconnected directories */ + if (preen == 0) + printf("** Phase 3 - Check Connectivity\n"); + pass3(); + +/* 4: scan inodes looking for disconnected files; check reference counts */ + if (preen == 0) + printf("** Phase 4 - Check Reference Counts\n"); + pass4(); + +/* 5: check resource counts in cylinder groups */ + if (preen == 0) + printf("** Phase 5 - Check Cyl groups\n"); + pass5(); + + if (fixcg) { + if (preen == 0) + printf("** Phase 6 - Salvage Cylinder Groups\n"); + makecg(); + n_ffree = sblock.fs_cstotal.cs_nffree; + n_bfree = sblock.fs_cstotal.cs_nbfree; + } + + pwarn("%d files, %d used, %d free (%d frags, %d blocks)\n", + 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) { + (void)time(&sblock.fs_time); + sbdirty(); + } + ckfini(); + free(blockmap); + free(freemap); + free(statemap); + 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); + } } -check(dev) +setup(dev) char *dev; { - register DINODE *dp; - register ino_t *blp; - register int i, n; - ino_t savino; - int b, c; - daddr_t d, s; - - devname = dev; - if (setup(dev) == 0) { + dev_t rootdev; + struct stat statb; + daddr_t super = bflag ? bflag : SBLOCK; + int i, j, c, d, cgd; + long size; + BUFAREA asblk; +# define altsblock asblk.b_un.b_fs + + if (stat("/", &statb) < 0) + errexit("Can't stat root\n"); + rootdev = statb.st_dev; + if (stat(dev, &statb) < 0) { + error("Can't stat %s\n", dev); + return (0); + } + rawflg = 0; + if ((statb.st_mode & S_IFMT) == S_IFBLK) + ; + else if ((statb.st_mode & S_IFMT) == S_IFCHR) + rawflg++; + else { + if (reply("file is not a block or character device; OK") == 0) + return (0); + } + if (rootdev == statb.st_rdev) + hotroot++; + if ((dfile.rfdes = open(dev, 0)) < 0) { + error("Can't open %s\n", dev); + return (0); + } + if (preen == 0) + printf("** %s", dev); + if (nflag || (dfile.wfdes = open(dev, 1)) < 0) { + dfile.wfdes = -1; if (preen) - pfatal("CAN'T CHECK DEVICE."); - return; + pfatal("NO WRITE ACCESS"); + printf(" (NO WRITE)"); } -/* 1 */ - if (preen==0) { - if (hotroot) - printf("** Root file system\n"); - printf("** Phase 1 - Check Blocks and Sizes\n"); + if (preen == 0) + printf("\n"); + fixcg = 0; inosumbad = 0; offsumbad = 0; frsumbad = 0; sbsumbad = 0; + dfile.mod = 0; + n_files = n_blks = n_ffree = n_bfree = 0; + muldup = enddup = &duplist[0]; + badlnp = &badlncnt[0]; + lfdir = 0; + rplyflag = 0; + initbarea(&sblk); + initbarea(&fileblk); + initbarea(&inoblk); + initbarea(&cgblk); + initbarea(&asblk); + /* + * Read in the super block and its summary info. + */ + if (bread(&dfile, (char *)&sblock, super, (long)SBSIZE) == 0) + return (0); + sblk.b_bno = super; + sblk.b_size = SBSIZE; + /* + * run a few consistency checks of the super block + */ + if (sblock.fs_magic != FS_MAGIC) + { badsb("MAGIC NUMBER WRONG"); return (0); } + if (sblock.fs_ncg < 1) + { 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_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_sbsize > SBSIZE) + { badsb("SIZE PREPOSTEROUSLY LARGE"); 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 */ + /* + * read in the summary info. + */ + 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, (unsigned)size); + if (bread(&dfile, (char *)sblock.fs_csp[j], + fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), + size) == 0) + return (0); } - pfunc = pass1; - inum = 0; - n_blks += howmany(sblock.fs_cssize, sblock.fs_bsize) * sblock.fs_frag; + /* + * allocate and initialize the necessary maps + */ + bmapsz = roundup(howmany(fmax, NBBY), sizeof(short)); + blockmap = calloc((unsigned)bmapsz, sizeof (char)); + if (blockmap == NULL) { + printf("cannot alloc %d bytes for blockmap\n", bmapsz); + goto badsb; + } + freemap = calloc((unsigned)bmapsz, sizeof (char)); + if (freemap == NULL) { + printf("cannot alloc %d bytes for freemap\n", bmapsz); + goto badsb; + } + statemap = calloc((unsigned)(imax + 1), sizeof(char)); + if (statemap == NULL) { + printf("cannot alloc %d bytes for statemap\n", imax + 1); + goto badsb; + } + lncntp = (short *)calloc((unsigned)(imax + 1), sizeof(short)); + if (lncntp == NULL) { + printf("cannot alloc %d bytes for lncntp\n", + (imax + 1) * sizeof(short)); + goto badsb; + } + for (c = 0; c < sblock.fs_ncg; c++) { + cgd = cgdmin(&sblock, c); + if (c == 0) { + d = cgbase(&sblock, c); + cgd += howmany(sblock.fs_cssize, sblock.fs_fsize); + } else + d = cgsblock(&sblock, c); + for (; d < cgd; d++) + setbmap(d); + } + + return (1); + +badsb: + ckfini(); + return (0); +# undef altsblock +} + +pass1() +{ + register int c, i, n, j; + register DINODE *dp; + 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) { + pfatal("CG %d: BAD MAGIC NUMBER\n", c); + bzero((char *)&cgrp, (int)sblock.fs_cgsize); + } 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++; @@ -387,43 +605,98 @@ check(dev) if (!isset(cgrp.cg_iused, i)) { if (debug) printf("%d bad, not used\n", - inum); + inumber); inosumbad++; } n--; - lastino = inum; - if (ftypeok(dp) == 0) { - pfatal("UNKNOWN FILE TYPE I=%u", inum); - if (reply("CLEAR") == 1) { - zapino(dp); - inodirty(); - inosumbad++; - } - continue; + lastino = inumber; + if (!preen && BADBLK && + reply("HOLD BAD BLOCK") == 1) { + dp->di_size = sblock.fs_fsize; + dp->di_mode = IFREG|0600; + inodirty(); + } else if (ftypeok(dp) == 0) + goto unknown; + if (dp->di_size < 0) { + if (debug) + printf("bad size %d:", + dp->di_size); + goto unknown; } + ndb = howmany(dp->di_size, sblock.fs_bsize); + if (SPECIAL) + ndb++; + for (j = ndb; j < NDADDR; j++) + if (dp->di_db[j] != 0) { + if (debug) + printf("bad direct addr: %d\n", + dp->di_db[j]); + goto unknown; + } + for (j = 0, ndb -= NDADDR; ndb > 0; j++) + ndb /= NINDIR(&sblock); + for (; j < NIADDR; j++) + if (dp->di_ib[j] != 0) { + if (debug) + printf("bad indirect addr: %d\n", + dp->di_ib[j]); + goto unknown; + } n_files++; - if (setlncnt(dp->di_nlink) <= 0) { + lncntp[inumber] = dp->di_nlink; + if (dp->di_nlink <= 0) { if (badlnp < &badlncnt[MAXLNCNT]) - *badlnp++ = inum; + *badlnp++ = inumber; else { pfatal("LINK COUNT TABLE OVERFLOW"); if (reply("CONTINUE") == 0) errexit(""); } } - setstate(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: + pfatal("UNKNOWN FILE TYPE I=%u", inumber); + if (reply("CLEAR") == 1) { + zapino(dp); + inodirty(); + inosumbad++; + } } else { if (isset(cgrp.cg_iused, i)) { if (debug) printf("%d bad, marked used\n", - inum); + inumber); inosumbad++; n--; } - if (dp->di_mode != 0) { - pfatal("PARTIALLY ALLOCATED INODE I=%u", inum); + partial = 0; + for (j = 0; j < NDADDR; j++) + if (dp->di_db[j] != 0) + partial++; + for (j = 0; j < NIADDR; j++) + if (dp->di_ib[j] != 0) + partial++; + if (partial || dp->di_mode != 0 || + dp->di_size != 0) { + pfatal("PARTIALLY ALLOCATED INODE I=%u", + inumber); if (reply("CLEAR") == 1) { zapino(dp); inodirty(); @@ -438,51 +711,147 @@ check(dev) c, cgrp.cg_cs.cs_nifree, n); inosumbad++; } + if (cgrp.cg_cs.cs_nbfree != sblock.fs_cs(&sblock, c).cs_nbfree + || cgrp.cg_cs.cs_nffree != sblock.fs_cs(&sblock, c).cs_nffree + || cgrp.cg_cs.cs_nifree != sblock.fs_cs(&sblock, c).cs_nifree + || cgrp.cg_cs.cs_ndir != sblock.fs_cs(&sblock, c).cs_ndir) + sbsumbad++; } -/* 1b */ - if (enddup != &duplist[0]) { - if (preen) - pfatal("INTERNAL ERROR: dups with -p"); - printf("** Phase 1b - Rescan For More DUPS\n"); - pfunc = pass1b; - inum = 0; - for (c = 0; c < sblock.fs_ncg; c++) { - for (i = 0; i < sblock.fs_ipg; i++, inum++) { - dp = ginode(); - if (dp == NULL) - continue; - if (getstate() != USTATE && - (ckinode(dp, ADDR) & STOP)) - goto out1b; +} + +pass1check(idesc) + register struct inodesc *idesc; +{ + register daddr_t *dlp; + int res = KEEPON; + int anyout, nfrags; + daddr_t blkno = idesc->id_blkno; + + 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) { + pwarn("EXCESSIVE BAD BLKS I=%u", + idesc->id_number); + if (preen) + printf(" (SKIPPING)\n"); + else if (reply("CONTINUE") == 0) + errexit(""); + return (STOP); + } + res = SKIP; + } else if (getbmap(blkno)) { + blkerr(idesc->id_number, "DUP", blkno); + if (++dupblk >= MAXDUP) { + pwarn("EXCESSIVE DUP BLKS I=%u", + idesc->id_number); + if (preen) + printf(" (SKIPPING)\n"); + else if (reply("CONTINUE") == 0) + errexit(""); + return (STOP); } + if (enddup >= &duplist[DUPTBLSIZE]) { + pfatal("DUP TABLE OVERFLOW."); + if (reply("CONTINUE") == 0) + errexit(""); + return (STOP); + } + for (dlp = duplist; dlp < muldup; dlp++) + if (*dlp == blkno) { + *enddup++ = blkno; + break; + } + if (dlp >= muldup) { + *enddup++ = *muldup; + *muldup++ = blkno; + } + } else { + n_blks++; + setbmap(blkno); + } + idesc->id_filesize++; + } + return (res); +} + +pass1b() +{ + register int c, i; + register DINODE *dp; + struct inodesc idesc; + ino_t inumber; + + 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 (i = 0; i < sblock.fs_ipg; i++, inumber++) { + dp = ginode(inumber); + if (dp == NULL) + continue; + idesc.id_number = inumber; + if (statemap[inumber] != USTATE && + (ckinode(dp, &idesc) & STOP)) + goto out1b; } } out1b: flush(&dfile, &inoblk); -/* 2 */ - if (preen == 0) - printf("** Phase 2 - Check Pathnames\n"); - inum = ROOTINO; - thisname = pathp = pathname; - pfunc = pass2; - switch (getstate()) { +} + +pass1bcheck(idesc) + register struct inodesc *idesc; +{ + register daddr_t *dlp; + int nfrags, res = KEEPON; + daddr_t blkno = idesc->id_blkno; + + for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { + if (outrange(blkno, 1)) + res = SKIP; + for (dlp = duplist; dlp < muldup; dlp++) + if (*dlp == blkno) { + blkerr(idesc->id_number, "DUP", blkno); + *dlp = *--muldup; + *muldup = blkno; + if (muldup == duplist) + return (STOP); + } + } + return (res); +} + +pass2() +{ + register DINODE *dp; + struct inodesc rootdesc; + + bzero((char *)&rootdesc, sizeof(struct inodesc)); + rootdesc.id_type = ADDR; + rootdesc.id_func = pass2check; + rootdesc.id_number = ROOTINO; + pathp = pathname; + switch (statemap[ROOTINO]) { case USTATE: errexit("ROOT INODE UNALLOCATED. TERMINATING.\n"); case FSTATE: pfatal("ROOT INODE NOT DIRECTORY"); - if (reply("FIX") == 0 || (dp = ginode()) == NULL) + if (reply("FIX") == 0 || (dp = ginode(ROOTINO)) == NULL) errexit(""); dp->di_mode &= ~IFMT; dp->di_mode |= IFDIR; inodirty(); inosumbad++; - setstate(DSTATE); + statemap[ROOTINO] = DSTATE; /* fall into ... */ case DSTATE: - descend(); + descend(&rootdesc, ROOTINO); break; case CLEAR: @@ -490,62 +859,249 @@ out1b: printf("\n"); if (reply("CONTINUE") == 0) errexit(""); - setstate(DSTATE); - descend(); + statemap[ROOTINO] = DSTATE; + descend(&rootdesc, ROOTINO); } -/* 3 */ - if (preen == 0) - printf("** Phase 3 - Check Connectivity\n"); - for (inum = ROOTINO; inum <= lastino; inum++) { - if (getstate() == DSTATE) { - pfunc = findino; - srchname = ".."; - savino = inum; - do { - orphan = inum; - if ((dp = ginode()) == NULL) +} + +pass2check(idesc) + struct inodesc *idesc; +{ + register DIRECT *dirp = idesc->id_dirp; + char *curpathloc; + int n, entrysize, ret = 0; + DINODE *dp; + DIRECT proto; + + /* + * check for "." + */ + if (idesc->id_entryno != 0) + goto chk1; + if (dirp->d_ino != 0 && 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); + } + bcopy(dirp->d_name, pathp, dirp->d_namlen + 1); + pathp += dirp->d_namlen; + idesc->id_entryno++; + n = 0; + if (dirp->d_ino > imax || dirp->d_ino <= 0) { + direrr(dirp->d_ino, "I OUT OF RANGE"); + n = reply("REMOVE"); + } else { +again: + switch (statemap[dirp->d_ino]) { + case USTATE: + direrr(dirp->d_ino, "UNALLOCATED"); + n = reply("REMOVE"); + break; + + case CLEAR: + direrr(dirp->d_ino, "DUP/BAD"); + if ((n = reply("REMOVE")) == 1) + break; + if ((dp = ginode(dirp->d_ino)) == NULL) + break; + statemap[dirp->d_ino] = DIRCT ? DSTATE : FSTATE; + goto again; + + case FSTATE: + lncntp[dirp->d_ino]--; + break; + + case DSTATE: + descend(idesc, dirp->d_ino); + if (statemap[dirp->d_ino] != CLEAR) { + lncntp[dirp->d_ino]--; + } else { + dirp->d_ino = 0; + ret |= ALTERED; + } + break; + } + } + pathp = curpathloc; + *pathp = '\0'; + if (n == 0) + return (ret|KEEPON); + dirp->d_ino = 0; + return (ret|KEEPON|ALTERED); +} + +pass3() +{ + register DINODE *dp; + 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 = ".."; + idesc.id_parent = inumber; + loopcnt = 0; + do { + orphan = idesc.id_parent; + if ((dp = ginode(orphan)) == NULL) break; - filsize = dp->di_size; - parentdir = 0; - ckinode(dp, DATA); - if ((inum = parentdir) == 0) + idesc.id_parent = 0; + idesc.id_filesize = dp->di_size; + idesc.id_number = orphan; + (void)ckinode(dp, &idesc); + if (idesc.id_parent == 0) break; - } while (getstate() == DSTATE); - inum = orphan; - if (linkup() == 1) { - thisname = pathp = pathname; - *pathp++ = '?'; - pfunc = pass2; - descend(); + if (loopcnt >= sblock.fs_cstotal.cs_ndir) + break; + 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; } } -/* 4 */ - if (preen == 0) - printf("** Phase 4 - Check Reference Counts\n"); - pfunc = pass4; - for (inum = ROOTINO; inum <= lastino; inum++) { - switch (getstate()) { +} + +pass4() +{ + register ino_t inumber, *blp; + int n; + struct inodesc idesc; + + 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: - if (n = getlncnt()) - adjust((short)n); + n = lncntp[inumber]; + if (n) + adjust(&idesc, (short)n); else { for (blp = badlncnt;blp < badlnp; blp++) - if (*blp == inum) { - clri("UNREF", 1); + if (*blp == inumber) { + clri(&idesc, "UNREF", 1); break; } } break; case DSTATE: - clri("UNREF", 1); + clri(&idesc, "UNREF", 1); break; case CLEAR: - clri("BAD/DUP", 1); + clri(&idesc, "BAD/DUP", 1); break; } } @@ -559,38 +1115,66 @@ out1b: } } flush(&dfile, &fileblk); +} -/* 5 */ - if (preen == 0) - printf("** Phase 5 - Check Cyl groups\n"); - copy(blockmap, freemap, (unsigned)bmapsz); +pass4check(idesc) + register struct inodesc *idesc; +{ + register daddr_t *dlp; + int nfrags, res = KEEPON; + daddr_t blkno = idesc->id_blkno; + + for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { + if (outrange(blkno, 1)) + res = SKIP; + else if (getbmap(blkno)) { + for (dlp = duplist; dlp < enddup; dlp++) + if (*dlp == blkno) { + *dlp = *--enddup; + return (KEEPON); + } + clrbmap(blkno); + n_blks--; + } + } + return (res); +} + +pass5() +{ + register int c, n, i, b, d; + short bo[MAXCPG][NRPOS]; + long botot[MAXCPG]; + long frsum[MAXFRAG]; + int blk; + daddr_t cbase; + int blockbits = (1<> (b % NBBY)) & - (0xff >> (NBBY - sblock.fs_frag))); - if (blk != 0) - fragacct(&sblock, blk, frsum, 1); + continue; } + for (d = 0; d < sblock.fs_frag; d++) + if ((blk & (1<= MAXBAD) { + printf("EXCESSIVE BAD BLKS IN BIT MAPS."); + if (reply("CONTINUE") == 0) + errexit(""); + return (STOP); + } } - printf(s, a1, a2, a3); -} - -preendie() -{ - - printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname); - exit(8); -} - -/* - * Pwarn is like printf when not preening, - * or a warning (preceded by filename) when preening. - */ -/* VARARGS1 */ -pwarn(s, a1, a2, a3, a4, a5) - char *s; -{ - - if (preen) - printf("%s: ", devname); - printf(s, a1, a2, a3, a4, a5); + for (; size > 0; blk++, size--) + if (getfmap(blk)) { + fixcg = 1; + ++dupblk; + } else { + n_ffree++; + setfmap(blk); + } + return (KEEPON); } -ckinode(dp, flg) +ckinode(dp, idesc) DINODE *dp; - register flg; + register struct inodesc *idesc; { register daddr_t *ap; - register ret; - int (*func)(), n, ndb, size, offset; + int ret, n, ndb, offset; + DINODE dino; if (SPECIAL) return (KEEPON); - func = (flg == ADDR) ? pfunc : dirscan; - ndb = howmany(dp->di_size, sblock.fs_bsize); - for (ap = &dp->di_db[0]; ap < &dp->di_db[NDADDR]; ap++) { - if (--ndb == 0 && (offset = blkoff(&sblock, dp->di_size)) != 0) - size = numfrags(&sblock, fragroundup(&sblock, offset)); + dino = *dp; + 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) + 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 - size = sblock.fs_frag; - if (*ap && (ret = (*func)(*ap, size)) & STOP) + ret = dirscan(idesc); + if (ret & STOP) return (ret); } - for (ap = &dp->di_ib[0], n = 1; n <= 2; ap++, n++) { - if (*ap && (ret = iblock(*ap, n, flg, dp->di_size - sblock.fs_bsize * NDADDR)) & STOP) - return (ret); + idesc->id_numfrags = sblock.fs_frag; + for (ap = &dino.di_ib[0], n = 1; n <= 2; ap++, n++) { + if (*ap) { + idesc->id_blkno = *ap; + ret = iblock(idesc, n, + dino.di_size - sblock.fs_bsize * NDADDR); + if (ret & STOP) + return (ret); + } } return (KEEPON); } -iblock(blk, ilevel, flg, isize) - daddr_t blk; +iblock(idesc, ilevel, isize) + struct inodesc *idesc; register ilevel; - int isize; + long isize; { register daddr_t *ap; register daddr_t *aplim; - register int i, n; - int (*func)(), nif; + int i, n, (*func)(), nif; 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; - if (outrange(blk)) /* protect thyself */ + if (outrange(idesc->id_blkno, idesc->id_numfrags)) /* protect thyself */ 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) { @@ -808,349 +1349,243 @@ iblock(blk, ilevel, flg, isize) } if (nif > NINDIR(&sblock)) nif = NINDIR(&sblock); - aplim = & ib.b_un.b_indir[nif]; + 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) - n = iblock(*ap, ilevel, flg, isize - i * NINDIR(&sblock) * sblock.fs_bsize); + n = iblock(idesc, ilevel, + isize - i*NINDIR(&sblock)*sblock.fs_bsize); else - n = (*func)(*ap, sblock.fs_frag); + n = (*func)(idesc); if (n & STOP) return (n); } return (KEEPON); } -pass1(blk, size) - daddr_t blk; - int size; -{ - register daddr_t *dlp; - int res = KEEPON; - - for (; size > 0; blk++, size--) { - if (outrange(blk)) { - blkerr("BAD", blk); - if (++badblk >= MAXBAD) { - printf("EXCESSIVE BAD BLKS I=%u", inum); - if (reply("CONTINUE") == 0) - errexit(""); - return (STOP); - } - res = SKIP; - } else if (getbmap(blk)) { - blkerr("DUP", blk); - if (++dupblk >= MAXDUP) { - printf("EXCESSIVE DUP BLKS I=%u", inum); - if (reply("CONTINUE") == 0) - errexit(""); - return (STOP); - } - if (enddup >= &duplist[DUPTBLSIZE]) { - printf("DUP TABLE OVERFLOW."); - if (reply("CONTINUE") == 0) - errexit(""); - return (STOP); - } - for (dlp = duplist; dlp < muldup; dlp++) - if (*dlp == blk) { - *enddup++ = blk; - break; - } - if (dlp >= muldup) { - *enddup++ = *muldup; - *muldup++ = blk; - } - } else { - n_blks++; - setbmap(blk); - } - filsize++; - } - return (res); -} - -pass1b(blk, size) - daddr_t blk; - int size; -{ - register daddr_t *dlp; - int res = KEEPON; - - for (; size > 0; blk++, size--) { - if (outrange(blk)) - res = SKIP; - for (dlp = duplist; dlp < muldup; dlp++) - if (*dlp == blk) { - blkerr("DUP", blk); - *dlp = *--muldup; - *muldup = blk; - if (muldup == duplist) - return (STOP); - } - } - return (res); -} - -pass2(dirp) - register DIRECT *dirp; -{ - register char *p; - register n; - DINODE *dp; - - if ((inum = dirp->d_ino) == 0) - return (KEEPON); - thisname = pathp; - for (p = dirp->d_name; p < &dirp->d_name[MAXNAMLEN]; ) - if ((*pathp++ = *p++) == 0) { - --pathp; - break; - } - *pathp = 0; - n = 0; - if (inum > imax || inum <= 0) - n = direrr("I OUT OF RANGE"); - else { -again: - switch (getstate()) { - case USTATE: - n = direrr("UNALLOCATED"); - break; - - case CLEAR: - if ((n = direrr("DUP/BAD")) == 1) - break; - if ((dp = ginode()) == NULL) - break; - setstate(DIRCT ? DSTATE : FSTATE); - goto again; - - case FSTATE: - declncnt(); - break; - - case DSTATE: - declncnt(); - descend(); - break; - } - } - pathp = thisname; - if (n == 0) - return (KEEPON); - dirp->d_ino = 0; - return (KEEPON|ALTERD); -} - -pass4(blk, size) - daddr_t blk; -{ - register daddr_t *dlp; - int res = KEEPON; - - for (; size > 0; blk++, size--) { - if (outrange(blk)) - res = SKIP; - else if (getbmap(blk)) { - for (dlp = duplist; dlp < enddup; dlp++) - if (*dlp == blk) { - *dlp = *--enddup; - return (KEEPON); - } - clrbmap(blk); - n_blks--; - } - } - return (res); -} - -pass5(blk, size) - daddr_t blk; - int size; -{ - int res = KEEPON; - - for (; size > 0; blk++, size--) { - if (outrange(blk)) { - fixcg = 1; - if (preen) - pfatal("BAD BLOCKS IN BIT MAPS."); - if (++badblk >= MAXBAD) { - printf("EXCESSIVE BAD BLKS IN BIT MAPS."); - if (reply("CONTINUE") == 0) - errexit(""); - return (STOP); - } - } else if (getfmap(blk)) { - fixcg = 1; - if (++dupblk >= DUPTBLSIZE) { - printf("EXCESSIVE DUP BLKS IN BIT MAPS."); - if (reply("CONTINUE") == 0) - errexit(""); - return (STOP); - } - } else { - n_ffree++; - setfmap(blk); - } - } - return (res); -} - -outrange(blk) +outrange(blk, cnt) daddr_t blk; + int cnt; { register int c; - c = dtog(&sblock, blk); - if (blk >= fmax || blk < cgdmin(&sblock, c)) { + if ((unsigned)(blk+cnt) > fmax) return (1); + c = dtog(&sblock, blk); + if (blk < cgdmin(&sblock, c)) { + if ((blk+cnt) > cgsblock(&sblock, c)) { + if (debug) { + printf("blk %d < cgdmin %d;", + blk, cgdmin(&sblock, c)); + printf(" blk+cnt %d > cgsbase %d\n", + blk+cnt, cgsblock(&sblock, c)); + } + return (1); + } + } else { + if ((blk+cnt) > cgbase(&sblock, c+1)) { + if (debug) { + printf("blk %d >= cgdmin %d;", + blk, cgdmin(&sblock, c)); + printf(" blk+cnt %d > sblock.fs_fpg %d\n", + blk+cnt, sblock.fs_fpg); + } + return (1); + } } return (0); } -blkerr(s, blk) - daddr_t blk; +blkerr(ino, s, blk) + ino_t ino; char *s; + daddr_t blk; { - pfatal("%ld %s I=%u", blk, s, inum); + + pfatal("%ld %s I=%u", blk, s, ino); printf("\n"); - setstate(CLEAR); /* mark for possible clearing */ + statemap[ino] = CLEAR; } -descend() +descend(parentino, inumber) + struct inodesc *parentino; + ino_t inumber; { register DINODE *dp; - register char *savname; - off_t savsize; + struct inodesc curino; - setstate(FSTATE); - if ((dp = ginode()) == NULL) + bzero((char *)&curino, sizeof(struct inodesc)); + statemap[inumber] = FSTATE; + if ((dp = ginode(inumber)) == NULL) 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; -}; - -dirscan(blk, nf) - daddr_t blk; - int nf; +dirscan(idesc) + register struct inodesc *idesc; { register DIRECT *dp; - struct dirstuff dirp; - int blksiz, dsize, n; + int dsize, n; + long blksiz; char dbuf[DIRBLKSIZ]; - if (outrange(blk)) { - 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); } - blksiz = nf * sblock.fs_fsize; - dirp.loc = 0; - dirp.blkno = blk; - dirp.blksiz = blksiz; - 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; - copy(dp, dbuf, dsize); - if ((n = (*pfunc)(dbuf)) & ALTERD) { - if (getblk(&fileblk, blk, blksiz) != NULL) { - copy(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 - n &= ~ALTERD; + n &= ~ALTERED; } if (n & STOP) return (n); } - return (filsize > 0 ? KEEPON : STOP); + return (idesc->id_filesize > 0 ? KEEPON : STOP); } /* * get next entry in a directory. */ DIRECT * -readdir(dirp) - register struct dirstuff *dirp; +fsck_readdir(idesc) + register struct inodesc *idesc; { register DIRECT *dp, *ndp; + 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; } - for (;;) { - if (filsize <= 0 || dirp->loc >= dirp->blksiz) - 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 (dirp->loc < dirp->blksiz && - (ndp->d_ino > imax || ndp->d_namlen > MAXNAMLEN || - ndp->d_reclen <= 0 || - ndp->d_reclen > DIRBLKSIZ - (dirp->loc % DIRBLKSIZ))) { - pwarn("DIRECTORY CORRUPTED"); - if (preen) - printf(" (SALVAGED)\n"); - else if (reply("SALVAGE") == 0) { - dirp->loc += - DIRBLKSIZ - (dirp->loc % DIRBLKSIZ); - filsize -= DIRBLKSIZ - (dirp->loc % DIRBLKSIZ); - return(dp); - } - dirp->loc -= dp->d_reclen; - filsize += dp->d_reclen; - dp->d_reclen = DIRBLKSIZ - (dirp->loc % DIRBLKSIZ); + 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_name[0] = '\0'; + if (dofix(idesc)) dirty(&fileblk); - continue; - } return (dp); } +dpok: + if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) + return NULL; + 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); + } + return (dp); +} + +/* + * 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(s) +direrr(ino, s) + ino_t ino; char *s; { register DINODE *dp; pwarn("%s ", s); - pinode(); + pinode(ino); 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 - 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; - if ((dp = ginode()) == NULL) + if ((dp = ginode(idesc->id_number)) == NULL) 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", - (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) { @@ -1167,149 +1602,31 @@ adjust(lcnt) } } -clri(s, flg) +clri(idesc, s, flg) + register struct inodesc *idesc; char *s; + int flg; { 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"); - pinode(); + pinode(idesc->id_number); } if (preen || reply("CLEAR") == 1) { if (preen) printf(" (CLEARED)\n"); n_files--; - pfunc = pass4; - ckinode(dp, ADDR); + (void)ckinode(dp, idesc); zapino(dp); - setstate(USTATE); + statemap[idesc->id_number] = USTATE; inodirty(); inosumbad++; } } -setup(dev) - char *dev; -{ - dev_t rootdev; - struct ostat statb; - int super = bflag ? bflag : SBLOCK; - - bflag = 0; - if (stat("/", &statb) < 0) - errexit("Can't stat root\n"); - rootdev = statb.st_dev; - if (stat(dev, &statb) < 0) { - error("Can't stat %s\n", dev); - return (0); - } - rawflg = 0; - if ((statb.st_mode & S_IFMT) == S_IFBLK) - ; - else if ((statb.st_mode & S_IFMT) == S_IFCHR) - rawflg++; - else { - if (reply("file is not a block or character device; OK") == 0) - return (0); - } - if (rootdev == statb.st_rdev) - hotroot++; - if ((dfile.rfdes = open(dev, 0)) < 0) { - error("Can't open %s\n", dev); - return (0); - } - if (preen == 0) - printf("** %s", dev); - if (nflag || (dfile.wfdes = open(dev, 1)) < 0) { - dfile.wfdes = -1; - if (preen) - pfatal("NO WRITE ACCESS"); - printf(" (NO WRITE)"); - } - if (preen == 0) - printf("\n"); - fixcg = 0; inosumbad = 0; offsumbad = 0; frsumbad = 0; - dfile.mod = 0; - n_files = n_blks = n_ffree = n_bfree = 0; - muldup = enddup = &duplist[0]; - badlnp = &badlncnt[0]; - lfdir = 0; - rplyflag = 0; - initbarea(&sblk); - initbarea(&fileblk); - initbarea(&inoblk); - initbarea(&cgblk); - if (bread(&dfile, &sblock, super, SBSIZE) == 0) - return (0); - sblk.b_bno = super; - sblk.b_size = SBSIZE; - /* - * run a few consistency checks of the super block - */ - if (sblock.fs_magic != FS_MAGIC) - { badsb("MAGIC NUMBER WRONG"); return (0); } - if (sblock.fs_ncg < 1) - { 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_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) - { badsb("SIZE PREPOSTEROUSLY LARGE"); return (0); } - /* rest we COULD repair... */ - if (sblock.fs_sblkno != SBLOCK) - { badsb("SBLKNO CORRUPTED"); return (0); } - if (sblock.fs_cblkno != - roundup(howmany(BBSIZE + SBSIZE, sblock.fs_fsize), sblock.fs_frag)) - { badsb("CBLKNO CORRUPTED"); return (0); } - if (sblock.fs_iblkno != sblock.fs_cblkno + sblock.fs_frag) - { badsb("IBLKNO CORRUPTED"); return (0); } - if (sblock.fs_dblkno != - sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock)) - { badsb("DBLKNO CORRUPTED"); return (0); } - if (sblock.fs_cgsize != fragroundup(&sblock, - sizeof(struct cg) + howmany(sblock.fs_fpg, NBBY))) - { badsb("CGSIZE INCORRECT"); return (0); } - if (sblock.fs_cssize != sblock.fs_ncg * sizeof(struct csum)) - { badsb("CSSIZE INCORRECT"); return (0); } - fmax = sblock.fs_size; - imax = sblock.fs_ncg * sblock.fs_ipg; - /* - * allocate the necessary maps - */ - bmapsz = roundup(howmany(fmax, NBBY), sizeof(short)); - blockmap = (char *)calloc(bmapsz, sizeof (char)); - freemap = (char *)calloc(bmapsz, sizeof (char)); - statemap = (char *)calloc(imax+1, sizeof(char)); - lncntp = (short *)calloc(imax+1, sizeof(short)); - - startinum = imax + 1; - return (1); - -badsb: - ckfini(); - return (0); -} - badsb(s) char *s; { @@ -1322,20 +1639,27 @@ badsb(s) } DINODE * -ginode() +ginode(inumber) + ino_t inumber; { daddr_t iblk; + static ino_t startinum = 0; /* blk num of first in raw area */ + - if (inum < ROOTINO || inum > imax) + if (inumber < ROOTINO || inumber > imax) { + if (debug && inumber > imax) + printf("inumber out of range (%d)\n", inumber); 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); } - 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) @@ -1348,9 +1672,12 @@ ftypeok(dp) case IFBLK: case IFCHR: case IFLNK: + case IFSOCK: return (1); default: + if (debug) + printf("bad file type 0%o\n", dp->di_mode); return (0); } } @@ -1402,9 +1729,9 @@ getline(fp, loc, maxlen) BUFAREA * getblk(bp, blk, size) - daddr_t blk; register BUFAREA *bp; - int size; + daddr_t blk; + long size; { register struct filecntl *fcp; daddr_t dblk; @@ -1429,7 +1756,7 @@ flush(fcp, bp) { 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; } @@ -1456,19 +1783,20 @@ ckfini() 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(); - 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) { @@ -1487,20 +1815,12 @@ pinode() printf("MTIME=%12.12s %4.4s ", p+4, p+20); } -copy(fp, tp, size) - register char *tp, *fp; - unsigned size; -{ - - while (size--) - *tp++ = *fp++; -} - makecg() { int c, blk; - daddr_t dbase, d, dmin, dmax; + daddr_t dbase, d, dlower, dupper, dmax; long i, j, s; + ino_t inumber; register struct csum *cs; register DINODE *dp; @@ -1508,12 +1828,6 @@ makecg() sblock.fs_cstotal.cs_nffree = 0; sblock.fs_cstotal.cs_nifree = 0; sblock.fs_cstotal.cs_ndir = 0; - for (i = 0; i < howmany(sblock.fs_cssize, sblock.fs_bsize); i++) { - sblock.fs_csp[i] = (struct csum *)calloc(1, sblock.fs_bsize); - bread(&dfile, (char *)sblock.fs_csp[i], - fsbtodb(&sblock, sblock.fs_csaddr + (i * sblock.fs_frag)), - sblock.fs_bsize); - } for (c = 0; c < sblock.fs_ncg; c++) { dbase = cgbase(&sblock, c); dmax = dbase + sblock.fs_fpg; @@ -1522,28 +1836,32 @@ makecg() clrbit(cgrp.cg_free, dmax - dbase); dmax++; } - dmin = sblock.fs_dblkno; + 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; - cgrp.cg_ncyl = sblock.fs_cpg; + if (c == sblock.fs_ncg - 1) + cgrp.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg; + else + cgrp.cg_ncyl = sblock.fs_cpg; cgrp.cg_niblk = sblock.fs_ipg; cgrp.cg_ndblk = dmax - dbase; cgrp.cg_cs.cs_ndir = 0; cgrp.cg_cs.cs_nffree = 0; cgrp.cg_cs.cs_nbfree = 0; cgrp.cg_cs.cs_nifree = 0; - cgrp.cg_rotor = dmin; - cgrp.cg_frotor = dmin; + cgrp.cg_rotor = 0; + cgrp.cg_frotor = 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); - dp = ginode(); + dp = ginode(inumber); if (dp == NULL) continue; if (ALLOC) { @@ -1569,16 +1887,16 @@ makecg() cgrp.cg_b[s][i] = 0; } if (c == 0) { - dmin += howmany(sblock.fs_cssize, sblock.fs_bsize) * - sblock.fs_frag; + dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); } - for (d = 0; d < dmin; d++) + for (d = dlower; d < dupper; d++) clrbit(cgrp.cg_free, d); - for (; (d + sblock.fs_frag) <= dmax - dbase; d += sblock.fs_frag) { + for (d = 0; (d + sblock.fs_frag) <= dmax - dbase; + d += sblock.fs_frag) { j = 0; for (i = 0; i < sblock.fs_frag; i++) { - if (!getbmap(dbase+d+i)) { - setbit(cgrp.cg_free, d+i); + if (!getbmap(dbase + d + i)) { + setbit(cgrp.cg_free, d + i); j++; } else clrbit(cgrp.cg_free, d+i); @@ -1590,95 +1908,63 @@ makecg() [cbtorpos(&sblock, d)]++; } else if (j > 0) { cgrp.cg_cs.cs_nffree += j; - blk = ((cgrp.cg_free[d / NBBY] >> (d % NBBY)) & - (0xff >> (NBBY - sblock.fs_frag))); + blk = blkmap(&sblock, cgrp.cg_free, d); fragacct(&sblock, blk, cgrp.cg_frsum, 1); } } for (j = d; d < dmax - dbase; d++) { - if (!getbmap(dbase+d)) { + if (!getbmap(dbase + d)) { setbit(cgrp.cg_free, d); cgrp.cg_cs.cs_nffree++; } else clrbit(cgrp.cg_free, d); } + for (; d % sblock.fs_frag != 0; d++) + clrbit(cgrp.cg_free, d); if (j != d) { - blk = ((cgrp.cg_free[j / NBBY] >> (j % NBBY)) & - (0xff >> (NBBY - sblock.fs_frag))); + blk = blkmap(&sblock, cgrp.cg_free, j); fragacct(&sblock, blk, cgrp.cg_frsum, 1); } - for (; d < MAXBPG(&sblock); d++) - clrbit(cgrp.cg_free, d); + for (d /= sblock.fs_frag; d < MAXBPG(&sblock); d ++) + clrblock(&sblock, cgrp.cg_free, d); sblock.fs_cstotal.cs_nffree += cgrp.cg_cs.cs_nffree; sblock.fs_cstotal.cs_nbfree += cgrp.cg_cs.cs_nbfree; 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; i < howmany(sblock.fs_cssize, sblock.fs_bsize); i++) { - bwrite(&dfile, (char *)sblock.fs_csp[i], - fsbtodb(&sblock, sblock.fs_csaddr + (i * sblock.fs_frag)), - sblock.fs_bsize); + for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, 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); } sblock.fs_ronly = 0; sblock.fs_fmod = 0; sbdirty(); } -/* - * update the frsum fields to reflect addition or deletion - * of some frags - */ -fragacct(fs, fragmap, fraglist, cnt) - struct fs *fs; - int fragmap; - long fraglist[]; - int cnt; +findino(idesc) + struct inodesc *idesc; { - int inblk; - register int field, subfield; - register int siz, pos; - - inblk = (int)(fragtbl[fs->fs_frag][fragmap] << 1); - fragmap <<= 1; - for (siz = 1; siz < fs->fs_frag; siz++) { - if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0) - continue; - field = around[siz]; - subfield = inside[siz]; - for (pos = siz; pos <= fs->fs_frag; pos++) { - if ((fragmap & field) == subfield) { - fraglist[siz] += cnt; - pos += siz; - field <<= siz; - subfield <<= siz; - } - field <<= 1; - subfield <<= 1; - } - } -} + register DIRECT *dirp = idesc->id_dirp; -findino(dirp) - register DIRECT *dirp; -{ 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); } -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; @@ -1693,45 +1979,39 @@ mkentry(dirp) 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; - 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; - return (ALTERD|STOP); + return (ALTERED|STOP); } return (KEEPON); } -linkup() +linkup(orphan, pdir) + ino_t orphan; + ino_t pdir; { 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; - pdir = parentdir; pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); - pinode(); + pinode(orphan); if (preen && dp->di_size == 0) return (0); if (preen) @@ -1739,28 +2019,26 @@ linkup() else if (reply("RECONNECT") == 0) return (0); - orphan = inum; + pathp = pathname; + *pathp++ = '/'; + *pathp = '\0'; if (lfdir == 0) { - inum = ROOTINO; - if ((dp = ginode()) == NULL) { - inum = orphan; + if ((dp = ginode(ROOTINO)) == NULL) return (0); - } - pfunc = findino; 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); } } - inum = lfdir; - if ((dp = ginode()) == NULL || !DIRCT || getstate() != FSTATE) { - inum = orphan; + if ((dp = ginode(lfdir)) == NULL || + !DIRCT || statemap[lfdir] != FSTATE) { pfatal("SORRY. NO lost+found DIRECTORY"); printf("\n\n"); return (0); @@ -1769,27 +2047,36 @@ linkup() 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); } - declncnt(); + lncntp[orphan]--; + *pathp++ = '/'; + pathp += lftempname(pathp, orphan); 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(); - setlncnt(getlncnt()+1); + lncntp[lfdir]++; } - inum = orphan; pwarn("DIR I=%u CONNECTED. ", orphan); printf("PARENT WAS I=%u\n", pdir); if (preen == 0) @@ -1798,32 +2085,57 @@ linkup() 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) - daddr_t blk; register struct filecntl *fcp; - register size; 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); - 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) - daddr_t blk; register struct filecntl *fcp; - register size; char *buf; + daddr_t blk; + long size; { 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); - else if (write(fcp->wfdes, buf, size) == size) { + else if (write(fcp->wfdes, buf, (int)size) == size) { fcp->mod = 1; return (1); } @@ -1838,31 +2150,136 @@ catch() exit(12); } +char * +unrawname(cp) + char *cp; +{ + char *dp = rindex(cp, '/'); + struct stat stb; + + if (dp == 0) + return (cp); + if (stat(cp, &stb) < 0) + return (cp); + if ((stb.st_mode&S_IFMT) != S_IFCHR) + return (cp); + if (*(dp+1) != 'r') + return (cp); + (void)strcpy(dp+1, dp+2); + return (cp); +} + +char * +rawname(cp) + char *cp; +{ + static char rawbuf[32]; + char *dp = rindex(cp, '/'); + + if (dp == 0) + return (0); + *dp = 0; + (void)strcpy(rawbuf, cp); + *dp = '/'; + (void)strcat(rawbuf, "/r"); + (void)strcat(rawbuf, dp+1); + return (rawbuf); +} + /* - * block operations + * determine whether an inode should be fixed. */ - -isblock(fs, cp, h) - struct fs *fs; - unsigned char *cp; - int h; +dofix(idesc) + register struct inodesc *idesc; { - unsigned char mask; - - switch (fs->fs_frag) { - case 8: - return (cp[h] == 0xff); - case 4: - mask = 0x0f << ((h & 0x1) << 2); - return ((cp[h >> 1] & mask) == mask); - case 2: - mask = 0x03 << ((h & 0x3) << 1); - return ((cp[h >> 2] & mask) == mask); - case 1: - mask = 0x01 << (h & 0x7); - return ((cp[h >> 3] & mask) == mask); - default: - error("isblock bad fs_frag %d\n", fs->fs_frag); + + 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; +{ + + printf(s1, s2, s3, s4); +} + +/* VARARGS1 */ +errexit(s1, s2, s3, s4) + char *s1; +{ + error(s1, s2, s3, s4); + exit(8); +} + +/* + * An inconsistency occured which shouldn't during normal operations. + * Die if preening, otherwise just printf. + */ +/* VARARGS1 */ +pfatal(s, a1, a2, a3) + char *s; +{ + + if (preen) { + printf("%s: ", devname); + printf(s, a1, a2, a3); + printf("\n"); + preendie(); } + printf(s, a1, a2, a3); +} + +preendie() +{ + + printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname); + exit(8); +} + +/* + * Pwarn is like printf when not preening, + * or a warning (preceded by filename) when preening. + */ +/* VARARGS1 */ +pwarn(s, a1, a2, a3, a4, a5, a6) + char *s; +{ + + if (preen) + printf("%s: ", devname); + printf(s, a1, a2, a3, a4, a5, a6); +} + +#ifndef lint +/* + * Stub for routines from kernel. + */ +panic(s) + char *s; +{ + + pfatal("INTERNAL INCONSISTENCY: %s\n", s); + exit(12); } +#endif