116259Smckusick #ifndef lint 2*17943Smckusick static char version[] = "@(#)dir.c 3.4 (Berkeley) 02/11/85"; 316259Smckusick #endif 416259Smckusick 516259Smckusick #include <sys/param.h> 616259Smckusick #include <sys/inode.h> 716259Smckusick #include <sys/fs.h> 816259Smckusick #define KERNEL 916259Smckusick #include <sys/dir.h> 1016259Smckusick #undef KERNEL 1116259Smckusick #include "fsck.h" 1216259Smckusick 1316259Smckusick #define MINDIRSIZE (sizeof (struct dirtemplate)) 1416259Smckusick 1516259Smckusick char *endpathname = &pathname[BUFSIZ - 2]; 1616259Smckusick char *lfname = "lost+found"; 1716259Smckusick 1816259Smckusick DIRECT *fsck_readdir(); 1916259Smckusick 2016259Smckusick descend(parentino, inumber) 2116259Smckusick struct inodesc *parentino; 2216259Smckusick ino_t inumber; 2316259Smckusick { 2416259Smckusick register DINODE *dp; 2516259Smckusick struct inodesc curino; 2616259Smckusick 2716259Smckusick bzero((char *)&curino, sizeof(struct inodesc)); 2817936Smckusick if (statemap[inumber] != DSTATE) 2917936Smckusick errexit("BAD INODE %d TO DESCEND", statemap[inumber]); 3017936Smckusick statemap[inumber] = DFOUND; 31*17943Smckusick dp = ginode(inumber); 3216259Smckusick if (dp->di_size == 0) { 3316259Smckusick direrr(inumber, "ZERO LENGTH DIRECTORY"); 3416259Smckusick if (reply("REMOVE") == 1) 3517936Smckusick statemap[inumber] = DCLEAR; 3616259Smckusick return; 3716259Smckusick } 3816259Smckusick if (dp->di_size < MINDIRSIZE) { 3916259Smckusick direrr(inumber, "DIRECTORY TOO SHORT"); 4016259Smckusick dp->di_size = MINDIRSIZE; 4116259Smckusick if (reply("FIX") == 1) 4216259Smckusick inodirty(); 4316259Smckusick } 4416259Smckusick curino.id_type = DATA; 4516259Smckusick curino.id_func = parentino->id_func; 4616259Smckusick curino.id_parent = parentino->id_number; 4716259Smckusick curino.id_number = inumber; 4816259Smckusick curino.id_filesize = dp->di_size; 4916259Smckusick (void)ckinode(dp, &curino); 5016259Smckusick } 5116259Smckusick 5216259Smckusick dirscan(idesc) 5316259Smckusick register struct inodesc *idesc; 5416259Smckusick { 5516259Smckusick register DIRECT *dp; 5616259Smckusick int dsize, n; 5716259Smckusick long blksiz; 5816259Smckusick char dbuf[DIRBLKSIZ]; 5916259Smckusick 6016259Smckusick if (idesc->id_type != DATA) 6116259Smckusick errexit("wrong type to dirscan %d\n", idesc->id_type); 6216259Smckusick blksiz = idesc->id_numfrags * sblock.fs_fsize; 6316259Smckusick if (outrange(idesc->id_blkno, idesc->id_numfrags)) { 6416259Smckusick idesc->id_filesize -= blksiz; 6516259Smckusick return (SKIP); 6616259Smckusick } 6716259Smckusick idesc->id_loc = 0; 6816259Smckusick for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 6916259Smckusick dsize = dp->d_reclen; 7016259Smckusick bcopy((char *)dp, dbuf, dsize); 7116259Smckusick idesc->id_dirp = (DIRECT *)dbuf; 7216259Smckusick if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 7316259Smckusick if (getblk(&fileblk, idesc->id_blkno, blksiz) != NULL) { 7416259Smckusick bcopy(dbuf, (char *)dp, dsize); 7516259Smckusick dirty(&fileblk); 7616259Smckusick sbdirty(); 7716259Smckusick } else 7816259Smckusick n &= ~ALTERED; 7916259Smckusick } 8016259Smckusick if (n & STOP) 8116259Smckusick return (n); 8216259Smckusick } 8316259Smckusick return (idesc->id_filesize > 0 ? KEEPON : STOP); 8416259Smckusick } 8516259Smckusick 8616259Smckusick /* 8716259Smckusick * get next entry in a directory. 8816259Smckusick */ 8916259Smckusick DIRECT * 9016259Smckusick fsck_readdir(idesc) 9116259Smckusick register struct inodesc *idesc; 9216259Smckusick { 9316259Smckusick register DIRECT *dp, *ndp; 9416259Smckusick long size, blksiz; 9516259Smckusick 9616259Smckusick blksiz = idesc->id_numfrags * sblock.fs_fsize; 9716259Smckusick if (getblk(&fileblk, idesc->id_blkno, blksiz) == NULL) { 9816259Smckusick idesc->id_filesize -= blksiz - idesc->id_loc; 9916259Smckusick return NULL; 10016259Smckusick } 10116259Smckusick if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 10216259Smckusick idesc->id_loc < blksiz) { 10316259Smckusick dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc); 10416259Smckusick if (dircheck(idesc, dp)) 10516259Smckusick goto dpok; 10616259Smckusick idesc->id_loc += DIRBLKSIZ; 10716259Smckusick idesc->id_filesize -= DIRBLKSIZ; 10816259Smckusick dp->d_reclen = DIRBLKSIZ; 10916259Smckusick dp->d_ino = 0; 11016259Smckusick dp->d_namlen = 0; 11116259Smckusick dp->d_name[0] = '\0'; 11217930Smckusick if (dofix(idesc, "DIRECTORY CORRUPTED")) 11316259Smckusick dirty(&fileblk); 11416259Smckusick return (dp); 11516259Smckusick } 11616259Smckusick dpok: 11716259Smckusick if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 11816259Smckusick return NULL; 11916259Smckusick dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc); 12016259Smckusick idesc->id_loc += dp->d_reclen; 12116259Smckusick idesc->id_filesize -= dp->d_reclen; 12216259Smckusick if ((idesc->id_loc % DIRBLKSIZ) == 0) 12316259Smckusick return (dp); 12416259Smckusick ndp = (DIRECT *)(dirblk.b_buf + idesc->id_loc); 12516259Smckusick if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 12616259Smckusick dircheck(idesc, ndp) == 0) { 12716259Smckusick size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 12816259Smckusick dp->d_reclen += size; 12916259Smckusick idesc->id_loc += size; 13016259Smckusick idesc->id_filesize -= size; 13117930Smckusick if (dofix(idesc, "DIRECTORY CORRUPTED")) 13216259Smckusick dirty(&fileblk); 13316259Smckusick } 13416259Smckusick return (dp); 13516259Smckusick } 13616259Smckusick 13716259Smckusick /* 13816259Smckusick * Verify that a directory entry is valid. 13916259Smckusick * This is a superset of the checks made in the kernel. 14016259Smckusick */ 14116259Smckusick dircheck(idesc, dp) 14216259Smckusick struct inodesc *idesc; 14316259Smckusick register DIRECT *dp; 14416259Smckusick { 14516259Smckusick register int size; 14616259Smckusick register char *cp; 14716259Smckusick int spaceleft; 14816259Smckusick 14916259Smckusick size = DIRSIZ(dp); 15016259Smckusick spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 15116259Smckusick if (dp->d_ino < imax && 15216259Smckusick dp->d_reclen != 0 && 15316259Smckusick dp->d_reclen <= spaceleft && 15416259Smckusick (dp->d_reclen & 0x3) == 0 && 15516259Smckusick dp->d_reclen >= size && 15616259Smckusick idesc->id_filesize >= size && 15716259Smckusick dp->d_namlen <= MAXNAMLEN) { 15816259Smckusick if (dp->d_ino == 0) 15916259Smckusick return (1); 16016259Smckusick for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++) 16116259Smckusick if (*cp == 0 || (*cp++ & 0200)) 16216259Smckusick return (0); 16316259Smckusick if (*cp == 0) 16416259Smckusick return (1); 16516259Smckusick } 16616259Smckusick return (0); 16716259Smckusick } 16816259Smckusick 16916259Smckusick direrr(ino, s) 17016259Smckusick ino_t ino; 17116259Smckusick char *s; 17216259Smckusick { 17316259Smckusick register DINODE *dp; 17416259Smckusick 17516259Smckusick pwarn("%s ", s); 17616259Smckusick pinode(ino); 17716259Smckusick printf("\n"); 178*17943Smckusick if (ino < ROOTINO || ino > imax) { 179*17943Smckusick pfatal("NAME=%s\n", pathname); 180*17943Smckusick return; 181*17943Smckusick } 182*17943Smckusick dp = ginode(ino); 183*17943Smckusick if (ftypeok(dp)) 18417930Smckusick pfatal("%s=%s\n", DIRCT(dp) ? "DIR" : "FILE", pathname); 18516259Smckusick else 18616259Smckusick pfatal("NAME=%s\n", pathname); 18716259Smckusick } 18816259Smckusick 18916259Smckusick adjust(idesc, lcnt) 19016259Smckusick register struct inodesc *idesc; 19116259Smckusick short lcnt; 19216259Smckusick { 19316259Smckusick register DINODE *dp; 19416259Smckusick 195*17943Smckusick dp = ginode(idesc->id_number); 19616259Smckusick if (dp->di_nlink == lcnt) { 19716259Smckusick if (linkup(idesc->id_number, (ino_t)0) == 0) 19816259Smckusick clri(idesc, "UNREF", 0); 19917936Smckusick } else { 20017930Smckusick pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 20117930Smckusick (DIRCT(dp) ? "DIR" : "FILE")); 20216259Smckusick pinode(idesc->id_number); 20316259Smckusick printf(" COUNT %d SHOULD BE %d", 20416259Smckusick dp->di_nlink, dp->di_nlink-lcnt); 20516259Smckusick if (preen) { 20616259Smckusick if (lcnt < 0) { 20716259Smckusick printf("\n"); 20817930Smckusick pfatal("LINK COUNT INCREASING"); 20916259Smckusick } 21016259Smckusick printf(" (ADJUSTED)\n"); 21116259Smckusick } 21216259Smckusick if (preen || reply("ADJUST") == 1) { 21316259Smckusick dp->di_nlink -= lcnt; 21416259Smckusick inodirty(); 21516259Smckusick } 21616259Smckusick } 21716259Smckusick } 21816259Smckusick 21916259Smckusick mkentry(idesc) 22016259Smckusick struct inodesc *idesc; 22116259Smckusick { 22216259Smckusick register DIRECT *dirp = idesc->id_dirp; 22316259Smckusick DIRECT newent; 22416259Smckusick int newlen, oldlen; 22516259Smckusick 22616259Smckusick newent.d_namlen = 11; 22716259Smckusick newlen = DIRSIZ(&newent); 22816259Smckusick if (dirp->d_ino != 0) 22916259Smckusick oldlen = DIRSIZ(dirp); 23016259Smckusick else 23116259Smckusick oldlen = 0; 23216259Smckusick if (dirp->d_reclen - oldlen < newlen) 23316259Smckusick return (KEEPON); 23416259Smckusick newent.d_reclen = dirp->d_reclen - oldlen; 23516259Smckusick dirp->d_reclen = oldlen; 23616259Smckusick dirp = (struct direct *)(((char *)dirp) + oldlen); 23716259Smckusick dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 23816259Smckusick dirp->d_reclen = newent.d_reclen; 23916259Smckusick dirp->d_namlen = lftempname(dirp->d_name, idesc->id_parent); 24016259Smckusick return (ALTERED|STOP); 24116259Smckusick } 24216259Smckusick 24316259Smckusick chgdd(idesc) 24416259Smckusick struct inodesc *idesc; 24516259Smckusick { 24616259Smckusick register DIRECT *dirp = idesc->id_dirp; 24716259Smckusick 24816259Smckusick if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' && 24916259Smckusick dirp->d_name[2] == 0) { 25016259Smckusick dirp->d_ino = lfdir; 25116259Smckusick return (ALTERED|STOP); 25216259Smckusick } 25316259Smckusick return (KEEPON); 25416259Smckusick } 25516259Smckusick 25616259Smckusick linkup(orphan, pdir) 25716259Smckusick ino_t orphan; 25816259Smckusick ino_t pdir; 25916259Smckusick { 26016259Smckusick register DINODE *dp; 26116259Smckusick int lostdir, len; 26216259Smckusick struct inodesc idesc; 26316259Smckusick 26416259Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 265*17943Smckusick dp = ginode(orphan); 26617930Smckusick lostdir = DIRCT(dp); 26716259Smckusick pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 26816259Smckusick pinode(orphan); 26916259Smckusick if (preen && dp->di_size == 0) 27016259Smckusick return (0); 27116259Smckusick if (preen) 27216259Smckusick printf(" (RECONNECTED)\n"); 27316259Smckusick else 27416259Smckusick if (reply("RECONNECT") == 0) 27516259Smckusick return (0); 27616259Smckusick pathp = pathname; 27716259Smckusick *pathp++ = '/'; 27816259Smckusick *pathp = '\0'; 27916259Smckusick if (lfdir == 0) { 280*17943Smckusick dp = ginode(ROOTINO); 28117930Smckusick idesc.id_name = lfname; 28216259Smckusick idesc.id_type = DATA; 28316259Smckusick idesc.id_func = findino; 28416259Smckusick idesc.id_number = ROOTINO; 28516259Smckusick idesc.id_filesize = dp->di_size; 28616259Smckusick (void)ckinode(dp, &idesc); 287*17943Smckusick lfdir = idesc.id_parent; 288*17943Smckusick if (lfdir < ROOTINO || lfdir > imax) 289*17943Smckusick lfdir = 0; 290*17943Smckusick if (lfdir == 0) { 29116259Smckusick pfatal("SORRY. NO lost+found DIRECTORY"); 29216259Smckusick printf("\n\n"); 29316259Smckusick return (0); 29416259Smckusick } 29516259Smckusick } 296*17943Smckusick dp = ginode(lfdir); 297*17943Smckusick if (!DIRCT(dp) || statemap[lfdir] != DFOUND) { 29816259Smckusick pfatal("SORRY. NO lost+found DIRECTORY"); 29916259Smckusick printf("\n\n"); 30016259Smckusick return (0); 30116259Smckusick } 30216259Smckusick if (fragoff(&sblock, dp->di_size)) { 30316259Smckusick dp->di_size = fragroundup(&sblock, dp->di_size); 30416259Smckusick inodirty(); 30516259Smckusick } 30616259Smckusick len = strlen(lfname); 30716259Smckusick bcopy(lfname, pathp, len + 1); 30816259Smckusick pathp += len; 30916259Smckusick idesc.id_type = DATA; 31016259Smckusick idesc.id_func = mkentry; 31116259Smckusick idesc.id_number = lfdir; 31216259Smckusick idesc.id_filesize = dp->di_size; 31316259Smckusick idesc.id_parent = orphan; /* this is the inode to enter */ 31416259Smckusick idesc.id_fix = DONTKNOW; 31516259Smckusick if ((ckinode(dp, &idesc) & ALTERED) == 0) { 31616259Smckusick pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 31716259Smckusick printf("\n\n"); 31816259Smckusick return (0); 31916259Smckusick } 32016259Smckusick lncntp[orphan]--; 32116259Smckusick *pathp++ = '/'; 32216259Smckusick pathp += lftempname(pathp, orphan); 32316259Smckusick if (lostdir) { 32416259Smckusick dp = ginode(orphan); 32516259Smckusick idesc.id_type = DATA; 32616259Smckusick idesc.id_func = chgdd; 32716259Smckusick idesc.id_number = orphan; 32816259Smckusick idesc.id_filesize = dp->di_size; 32916259Smckusick idesc.id_fix = DONTKNOW; 33016259Smckusick (void)ckinode(dp, &idesc); 331*17943Smckusick dp = ginode(lfdir); 332*17943Smckusick dp->di_nlink++; 333*17943Smckusick inodirty(); 334*17943Smckusick lncntp[lfdir]++; 33516259Smckusick pwarn("DIR I=%u CONNECTED. ", orphan); 33616259Smckusick printf("PARENT WAS I=%u\n", pdir); 33716259Smckusick if (preen == 0) 33816259Smckusick printf("\n"); 33916259Smckusick } 34016259Smckusick return (1); 34116259Smckusick } 34216259Smckusick 34316259Smckusick /* 34416259Smckusick * generate a temporary name for the lost+found directory. 34516259Smckusick */ 34616259Smckusick lftempname(bufp, ino) 34716259Smckusick char *bufp; 34816259Smckusick ino_t ino; 34916259Smckusick { 35016259Smckusick register ino_t in; 35116259Smckusick register char *cp; 35216259Smckusick int namlen; 35316259Smckusick 35416259Smckusick cp = bufp + 2; 35516259Smckusick for (in = imax; in > 0; in /= 10) 35616259Smckusick cp++; 35716259Smckusick *--cp = 0; 35816259Smckusick namlen = cp - bufp; 35916259Smckusick in = ino; 36016259Smckusick while (cp > bufp) { 36116259Smckusick *--cp = (in % 10) + '0'; 36216259Smckusick in /= 10; 36316259Smckusick } 36416259Smckusick *cp = '#'; 36516259Smckusick return (namlen); 36616259Smckusick } 367