1*16259Smckusick #ifndef lint 2*16259Smckusick static char version[] = "@(#)dir.c 3.1 (Berkeley) 03/31/84"; 3*16259Smckusick #endif 4*16259Smckusick 5*16259Smckusick #include <sys/param.h> 6*16259Smckusick #include <sys/inode.h> 7*16259Smckusick #include <sys/fs.h> 8*16259Smckusick #define KERNEL 9*16259Smckusick #include <sys/dir.h> 10*16259Smckusick #undef KERNEL 11*16259Smckusick #include "fsck.h" 12*16259Smckusick 13*16259Smckusick #define MINDIRSIZE (sizeof (struct dirtemplate)) 14*16259Smckusick 15*16259Smckusick char *endpathname = &pathname[BUFSIZ - 2]; 16*16259Smckusick char *lfname = "lost+found"; 17*16259Smckusick 18*16259Smckusick DIRECT *fsck_readdir(); 19*16259Smckusick 20*16259Smckusick descend(parentino, inumber) 21*16259Smckusick struct inodesc *parentino; 22*16259Smckusick ino_t inumber; 23*16259Smckusick { 24*16259Smckusick register DINODE *dp; 25*16259Smckusick struct inodesc curino; 26*16259Smckusick 27*16259Smckusick bzero((char *)&curino, sizeof(struct inodesc)); 28*16259Smckusick statemap[inumber] = FSTATE; 29*16259Smckusick if ((dp = ginode(inumber)) == NULL) 30*16259Smckusick return; 31*16259Smckusick if (dp->di_size == 0) { 32*16259Smckusick direrr(inumber, "ZERO LENGTH DIRECTORY"); 33*16259Smckusick if (reply("REMOVE") == 1) 34*16259Smckusick statemap[inumber] = CLEAR; 35*16259Smckusick return; 36*16259Smckusick } 37*16259Smckusick if (dp->di_size < MINDIRSIZE) { 38*16259Smckusick direrr(inumber, "DIRECTORY TOO SHORT"); 39*16259Smckusick dp->di_size = MINDIRSIZE; 40*16259Smckusick if (reply("FIX") == 1) 41*16259Smckusick inodirty(); 42*16259Smckusick } 43*16259Smckusick curino.id_type = DATA; 44*16259Smckusick curino.id_func = parentino->id_func; 45*16259Smckusick curino.id_parent = parentino->id_number; 46*16259Smckusick curino.id_number = inumber; 47*16259Smckusick curino.id_filesize = dp->di_size; 48*16259Smckusick (void)ckinode(dp, &curino); 49*16259Smckusick } 50*16259Smckusick 51*16259Smckusick dirscan(idesc) 52*16259Smckusick register struct inodesc *idesc; 53*16259Smckusick { 54*16259Smckusick register DIRECT *dp; 55*16259Smckusick int dsize, n; 56*16259Smckusick long blksiz; 57*16259Smckusick char dbuf[DIRBLKSIZ]; 58*16259Smckusick 59*16259Smckusick if (idesc->id_type != DATA) 60*16259Smckusick errexit("wrong type to dirscan %d\n", idesc->id_type); 61*16259Smckusick blksiz = idesc->id_numfrags * sblock.fs_fsize; 62*16259Smckusick if (outrange(idesc->id_blkno, idesc->id_numfrags)) { 63*16259Smckusick idesc->id_filesize -= blksiz; 64*16259Smckusick return (SKIP); 65*16259Smckusick } 66*16259Smckusick idesc->id_loc = 0; 67*16259Smckusick for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 68*16259Smckusick dsize = dp->d_reclen; 69*16259Smckusick bcopy((char *)dp, dbuf, dsize); 70*16259Smckusick idesc->id_dirp = (DIRECT *)dbuf; 71*16259Smckusick if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 72*16259Smckusick if (getblk(&fileblk, idesc->id_blkno, blksiz) != NULL) { 73*16259Smckusick bcopy(dbuf, (char *)dp, dsize); 74*16259Smckusick dirty(&fileblk); 75*16259Smckusick sbdirty(); 76*16259Smckusick } else 77*16259Smckusick n &= ~ALTERED; 78*16259Smckusick } 79*16259Smckusick if (n & STOP) 80*16259Smckusick return (n); 81*16259Smckusick } 82*16259Smckusick return (idesc->id_filesize > 0 ? KEEPON : STOP); 83*16259Smckusick } 84*16259Smckusick 85*16259Smckusick /* 86*16259Smckusick * get next entry in a directory. 87*16259Smckusick */ 88*16259Smckusick DIRECT * 89*16259Smckusick fsck_readdir(idesc) 90*16259Smckusick register struct inodesc *idesc; 91*16259Smckusick { 92*16259Smckusick register DIRECT *dp, *ndp; 93*16259Smckusick long size, blksiz; 94*16259Smckusick 95*16259Smckusick blksiz = idesc->id_numfrags * sblock.fs_fsize; 96*16259Smckusick if (getblk(&fileblk, idesc->id_blkno, blksiz) == NULL) { 97*16259Smckusick idesc->id_filesize -= blksiz - idesc->id_loc; 98*16259Smckusick return NULL; 99*16259Smckusick } 100*16259Smckusick if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 101*16259Smckusick idesc->id_loc < blksiz) { 102*16259Smckusick dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc); 103*16259Smckusick if (dircheck(idesc, dp)) 104*16259Smckusick goto dpok; 105*16259Smckusick idesc->id_loc += DIRBLKSIZ; 106*16259Smckusick idesc->id_filesize -= DIRBLKSIZ; 107*16259Smckusick dp->d_reclen = DIRBLKSIZ; 108*16259Smckusick dp->d_ino = 0; 109*16259Smckusick dp->d_namlen = 0; 110*16259Smckusick dp->d_name[0] = '\0'; 111*16259Smckusick if (dofix(idesc)) 112*16259Smckusick dirty(&fileblk); 113*16259Smckusick return (dp); 114*16259Smckusick } 115*16259Smckusick dpok: 116*16259Smckusick if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 117*16259Smckusick return NULL; 118*16259Smckusick dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc); 119*16259Smckusick idesc->id_loc += dp->d_reclen; 120*16259Smckusick idesc->id_filesize -= dp->d_reclen; 121*16259Smckusick if ((idesc->id_loc % DIRBLKSIZ) == 0) 122*16259Smckusick return (dp); 123*16259Smckusick ndp = (DIRECT *)(dirblk.b_buf + idesc->id_loc); 124*16259Smckusick if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 125*16259Smckusick dircheck(idesc, ndp) == 0) { 126*16259Smckusick size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 127*16259Smckusick dp->d_reclen += size; 128*16259Smckusick idesc->id_loc += size; 129*16259Smckusick idesc->id_filesize -= size; 130*16259Smckusick if (dofix(idesc)) 131*16259Smckusick dirty(&fileblk); 132*16259Smckusick } 133*16259Smckusick return (dp); 134*16259Smckusick } 135*16259Smckusick 136*16259Smckusick /* 137*16259Smckusick * Verify that a directory entry is valid. 138*16259Smckusick * This is a superset of the checks made in the kernel. 139*16259Smckusick */ 140*16259Smckusick dircheck(idesc, dp) 141*16259Smckusick struct inodesc *idesc; 142*16259Smckusick register DIRECT *dp; 143*16259Smckusick { 144*16259Smckusick register int size; 145*16259Smckusick register char *cp; 146*16259Smckusick int spaceleft; 147*16259Smckusick 148*16259Smckusick size = DIRSIZ(dp); 149*16259Smckusick spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 150*16259Smckusick if (dp->d_ino < imax && 151*16259Smckusick dp->d_reclen != 0 && 152*16259Smckusick dp->d_reclen <= spaceleft && 153*16259Smckusick (dp->d_reclen & 0x3) == 0 && 154*16259Smckusick dp->d_reclen >= size && 155*16259Smckusick idesc->id_filesize >= size && 156*16259Smckusick dp->d_namlen <= MAXNAMLEN) { 157*16259Smckusick if (dp->d_ino == 0) 158*16259Smckusick return (1); 159*16259Smckusick for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++) 160*16259Smckusick if (*cp == 0 || (*cp++ & 0200)) 161*16259Smckusick return (0); 162*16259Smckusick if (*cp == 0) 163*16259Smckusick return (1); 164*16259Smckusick } 165*16259Smckusick return (0); 166*16259Smckusick } 167*16259Smckusick 168*16259Smckusick direrr(ino, s) 169*16259Smckusick ino_t ino; 170*16259Smckusick char *s; 171*16259Smckusick { 172*16259Smckusick register DINODE *dp; 173*16259Smckusick 174*16259Smckusick pwarn("%s ", s); 175*16259Smckusick pinode(ino); 176*16259Smckusick printf("\n"); 177*16259Smckusick if ((dp = ginode(ino)) != NULL && ftypeok(dp)) 178*16259Smckusick pfatal("%s=%s\n", DIRCT?"DIR":"FILE", pathname); 179*16259Smckusick else 180*16259Smckusick pfatal("NAME=%s\n", pathname); 181*16259Smckusick } 182*16259Smckusick 183*16259Smckusick adjust(idesc, lcnt) 184*16259Smckusick register struct inodesc *idesc; 185*16259Smckusick short lcnt; 186*16259Smckusick { 187*16259Smckusick register DINODE *dp; 188*16259Smckusick 189*16259Smckusick if ((dp = ginode(idesc->id_number)) == NULL) 190*16259Smckusick return; 191*16259Smckusick if (dp->di_nlink == lcnt) { 192*16259Smckusick if (linkup(idesc->id_number, (ino_t)0) == 0) 193*16259Smckusick clri(idesc, "UNREF", 0); 194*16259Smckusick } 195*16259Smckusick else { 196*16259Smckusick pwarn("LINK COUNT %s", 197*16259Smckusick (lfdir==idesc->id_number)?lfname:(DIRCT?"DIR":"FILE")); 198*16259Smckusick pinode(idesc->id_number); 199*16259Smckusick printf(" COUNT %d SHOULD BE %d", 200*16259Smckusick dp->di_nlink, dp->di_nlink-lcnt); 201*16259Smckusick if (preen) { 202*16259Smckusick if (lcnt < 0) { 203*16259Smckusick printf("\n"); 204*16259Smckusick preendie(); 205*16259Smckusick } 206*16259Smckusick printf(" (ADJUSTED)\n"); 207*16259Smckusick } 208*16259Smckusick if (preen || reply("ADJUST") == 1) { 209*16259Smckusick dp->di_nlink -= lcnt; 210*16259Smckusick inodirty(); 211*16259Smckusick } 212*16259Smckusick } 213*16259Smckusick } 214*16259Smckusick 215*16259Smckusick mkentry(idesc) 216*16259Smckusick struct inodesc *idesc; 217*16259Smckusick { 218*16259Smckusick register DIRECT *dirp = idesc->id_dirp; 219*16259Smckusick DIRECT newent; 220*16259Smckusick int newlen, oldlen; 221*16259Smckusick 222*16259Smckusick newent.d_namlen = 11; 223*16259Smckusick newlen = DIRSIZ(&newent); 224*16259Smckusick if (dirp->d_ino != 0) 225*16259Smckusick oldlen = DIRSIZ(dirp); 226*16259Smckusick else 227*16259Smckusick oldlen = 0; 228*16259Smckusick if (dirp->d_reclen - oldlen < newlen) 229*16259Smckusick return (KEEPON); 230*16259Smckusick newent.d_reclen = dirp->d_reclen - oldlen; 231*16259Smckusick dirp->d_reclen = oldlen; 232*16259Smckusick dirp = (struct direct *)(((char *)dirp) + oldlen); 233*16259Smckusick dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 234*16259Smckusick dirp->d_reclen = newent.d_reclen; 235*16259Smckusick dirp->d_namlen = lftempname(dirp->d_name, idesc->id_parent); 236*16259Smckusick return (ALTERED|STOP); 237*16259Smckusick } 238*16259Smckusick 239*16259Smckusick chgdd(idesc) 240*16259Smckusick struct inodesc *idesc; 241*16259Smckusick { 242*16259Smckusick register DIRECT *dirp = idesc->id_dirp; 243*16259Smckusick 244*16259Smckusick if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' && 245*16259Smckusick dirp->d_name[2] == 0) { 246*16259Smckusick dirp->d_ino = lfdir; 247*16259Smckusick return (ALTERED|STOP); 248*16259Smckusick } 249*16259Smckusick return (KEEPON); 250*16259Smckusick } 251*16259Smckusick 252*16259Smckusick linkup(orphan, pdir) 253*16259Smckusick ino_t orphan; 254*16259Smckusick ino_t pdir; 255*16259Smckusick { 256*16259Smckusick register DINODE *dp; 257*16259Smckusick int lostdir, len; 258*16259Smckusick struct inodesc idesc; 259*16259Smckusick 260*16259Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 261*16259Smckusick if ((dp = ginode(orphan)) == NULL) 262*16259Smckusick return (0); 263*16259Smckusick lostdir = DIRCT; 264*16259Smckusick pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 265*16259Smckusick pinode(orphan); 266*16259Smckusick if (preen && dp->di_size == 0) 267*16259Smckusick return (0); 268*16259Smckusick if (preen) 269*16259Smckusick printf(" (RECONNECTED)\n"); 270*16259Smckusick else 271*16259Smckusick if (reply("RECONNECT") == 0) 272*16259Smckusick return (0); 273*16259Smckusick pathp = pathname; 274*16259Smckusick *pathp++ = '/'; 275*16259Smckusick *pathp = '\0'; 276*16259Smckusick if (lfdir == 0) { 277*16259Smckusick if ((dp = ginode(ROOTINO)) == NULL) 278*16259Smckusick return (0); 279*16259Smckusick srchname = lfname; 280*16259Smckusick idesc.id_type = DATA; 281*16259Smckusick idesc.id_func = findino; 282*16259Smckusick idesc.id_number = ROOTINO; 283*16259Smckusick idesc.id_filesize = dp->di_size; 284*16259Smckusick (void)ckinode(dp, &idesc); 285*16259Smckusick if ((lfdir = idesc.id_parent) == 0) { 286*16259Smckusick pfatal("SORRY. NO lost+found DIRECTORY"); 287*16259Smckusick printf("\n\n"); 288*16259Smckusick return (0); 289*16259Smckusick } 290*16259Smckusick } 291*16259Smckusick if ((dp = ginode(lfdir)) == NULL || 292*16259Smckusick !DIRCT || statemap[lfdir] != FSTATE) { 293*16259Smckusick pfatal("SORRY. NO lost+found DIRECTORY"); 294*16259Smckusick printf("\n\n"); 295*16259Smckusick return (0); 296*16259Smckusick } 297*16259Smckusick if (fragoff(&sblock, dp->di_size)) { 298*16259Smckusick dp->di_size = fragroundup(&sblock, dp->di_size); 299*16259Smckusick inodirty(); 300*16259Smckusick } 301*16259Smckusick len = strlen(lfname); 302*16259Smckusick bcopy(lfname, pathp, len + 1); 303*16259Smckusick pathp += len; 304*16259Smckusick idesc.id_type = DATA; 305*16259Smckusick idesc.id_func = mkentry; 306*16259Smckusick idesc.id_number = lfdir; 307*16259Smckusick idesc.id_filesize = dp->di_size; 308*16259Smckusick idesc.id_parent = orphan; /* this is the inode to enter */ 309*16259Smckusick idesc.id_fix = DONTKNOW; 310*16259Smckusick if ((ckinode(dp, &idesc) & ALTERED) == 0) { 311*16259Smckusick pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 312*16259Smckusick printf("\n\n"); 313*16259Smckusick return (0); 314*16259Smckusick } 315*16259Smckusick lncntp[orphan]--; 316*16259Smckusick *pathp++ = '/'; 317*16259Smckusick pathp += lftempname(pathp, orphan); 318*16259Smckusick if (lostdir) { 319*16259Smckusick dp = ginode(orphan); 320*16259Smckusick idesc.id_type = DATA; 321*16259Smckusick idesc.id_func = chgdd; 322*16259Smckusick idesc.id_number = orphan; 323*16259Smckusick idesc.id_filesize = dp->di_size; 324*16259Smckusick idesc.id_fix = DONTKNOW; 325*16259Smckusick (void)ckinode(dp, &idesc); 326*16259Smckusick if ((dp = ginode(lfdir)) != NULL) { 327*16259Smckusick dp->di_nlink++; 328*16259Smckusick inodirty(); 329*16259Smckusick lncntp[lfdir]++; 330*16259Smckusick } 331*16259Smckusick pwarn("DIR I=%u CONNECTED. ", orphan); 332*16259Smckusick printf("PARENT WAS I=%u\n", pdir); 333*16259Smckusick if (preen == 0) 334*16259Smckusick printf("\n"); 335*16259Smckusick } 336*16259Smckusick return (1); 337*16259Smckusick } 338*16259Smckusick 339*16259Smckusick /* 340*16259Smckusick * generate a temporary name for the lost+found directory. 341*16259Smckusick */ 342*16259Smckusick lftempname(bufp, ino) 343*16259Smckusick char *bufp; 344*16259Smckusick ino_t ino; 345*16259Smckusick { 346*16259Smckusick register ino_t in; 347*16259Smckusick register char *cp; 348*16259Smckusick int namlen; 349*16259Smckusick 350*16259Smckusick cp = bufp + 2; 351*16259Smckusick for (in = imax; in > 0; in /= 10) 352*16259Smckusick cp++; 353*16259Smckusick *--cp = 0; 354*16259Smckusick namlen = cp - bufp; 355*16259Smckusick in = ino; 356*16259Smckusick while (cp > bufp) { 357*16259Smckusick *--cp = (in % 10) + '0'; 358*16259Smckusick in /= 10; 359*16259Smckusick } 360*16259Smckusick *cp = '#'; 361*16259Smckusick return (namlen); 362*16259Smckusick } 363