1: /*
   2:  * Copyright (c) 1980 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifndef lint
   8: static char sccsid[] = "@(#)dir.c	5.1 (Berkeley) 6/5/85";
   9: #endif not lint
  10: 
  11: #include <sys/param.h>
  12: #include <sys/inode.h>
  13: #include <sys/fs.h>
  14: #define KERNEL
  15: #include <sys/dir.h>
  16: #undef KERNEL
  17: #include "fsck.h"
  18: 
  19: #define MINDIRSIZE  (sizeof (struct dirtemplate))
  20: 
  21: char    *endpathname = &pathname[BUFSIZ - 2];
  22: char    *lfname = "lost+found";
  23: struct  dirtemplate emptydir = { 0, DIRBLKSIZ };
  24: struct  dirtemplate dirhead = { 0, 12, 1, ".", 0, DIRBLKSIZ - 12, 2, ".." };
  25: 
  26: DIRECT  *fsck_readdir();
  27: 
  28: descend(parentino, inumber)
  29:     struct inodesc *parentino;
  30:     ino_t inumber;
  31: {
  32:     register DINODE *dp;
  33:     struct inodesc curino;
  34: 
  35:     bzero((char *)&curino, sizeof(struct inodesc));
  36:     if (statemap[inumber] != DSTATE)
  37:         errexit("BAD INODE %d TO DESCEND", statemap[inumber]);
  38:     statemap[inumber] = DFOUND;
  39:     dp = ginode(inumber);
  40:     if (dp->di_size == 0) {
  41:         direrr(inumber, "ZERO LENGTH DIRECTORY");
  42:         if (reply("REMOVE") == 1)
  43:             statemap[inumber] = DCLEAR;
  44:         return;
  45:     }
  46:     if (dp->di_size < MINDIRSIZE) {
  47:         direrr(inumber, "DIRECTORY TOO SHORT");
  48:         dp->di_size = MINDIRSIZE;
  49:         if (reply("FIX") == 1)
  50:             inodirty();
  51:     }
  52:     if ((dp->di_size & (DIRBLKSIZ - 1)) != 0) {
  53:         pwarn("DIRECTORY %s: LENGTH %d NOT MULTIPLE OF %d",
  54:             pathname, dp->di_size, DIRBLKSIZ);
  55:         dp->di_size = roundup(dp->di_size, DIRBLKSIZ);
  56:         if (preen)
  57:             printf(" (ADJUSTED)\n");
  58:         if (preen || reply("ADJUST") == 1)
  59:             inodirty();
  60:     }
  61:     curino.id_type = DATA;
  62:     curino.id_func = parentino->id_func;
  63:     curino.id_parent = parentino->id_number;
  64:     curino.id_number = inumber;
  65:     (void)ckinode(dp, &curino);
  66: }
  67: 
  68: dirscan(idesc)
  69:     register struct inodesc *idesc;
  70: {
  71:     register DIRECT *dp;
  72:     int dsize, n;
  73:     long blksiz;
  74:     char dbuf[DIRBLKSIZ];
  75: 
  76:     if (idesc->id_type != DATA)
  77:         errexit("wrong type to dirscan %d\n", idesc->id_type);
  78:     if (idesc->id_entryno == 0 &&
  79:         (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0)
  80:         idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ);
  81:     blksiz = idesc->id_numfrags * sblock.fs_fsize;
  82:     if (outrange(idesc->id_blkno, idesc->id_numfrags)) {
  83:         idesc->id_filesize -= blksiz;
  84:         return (SKIP);
  85:     }
  86:     idesc->id_loc = 0;
  87:     for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
  88:         dsize = dp->d_reclen;
  89:         bcopy((char *)dp, dbuf, dsize);
  90:         idesc->id_dirp = (DIRECT *)dbuf;
  91:         if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
  92:             getblk(&fileblk, idesc->id_blkno, blksiz);
  93:             if (fileblk.b_errs != NULL) {
  94:                 n &= ~ALTERED;
  95:             } else {
  96:                 bcopy(dbuf, (char *)dp, dsize);
  97:                 dirty(&fileblk);
  98:                 sbdirty();
  99:             }
 100:         }
 101:         if (n & STOP)
 102:             return (n);
 103:     }
 104:     return (idesc->id_filesize > 0 ? KEEPON : STOP);
 105: }
 106: 
 107: /*
 108:  * get next entry in a directory.
 109:  */
 110: DIRECT *
 111: fsck_readdir(idesc)
 112:     register struct inodesc *idesc;
 113: {
 114:     register DIRECT *dp, *ndp;
 115:     long size, blksiz;
 116: 
 117:     blksiz = idesc->id_numfrags * sblock.fs_fsize;
 118:     getblk(&fileblk, idesc->id_blkno, blksiz);
 119:     if (fileblk.b_errs != NULL) {
 120:         idesc->id_filesize -= blksiz - idesc->id_loc;
 121:         return NULL;
 122:     }
 123:     if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
 124:         idesc->id_loc < blksiz) {
 125:         dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
 126:         if (dircheck(idesc, dp))
 127:             goto dpok;
 128:         idesc->id_loc += DIRBLKSIZ;
 129:         idesc->id_filesize -= DIRBLKSIZ;
 130:         dp->d_reclen = DIRBLKSIZ;
 131:         dp->d_ino = 0;
 132:         dp->d_namlen = 0;
 133:         dp->d_name[0] = '\0';
 134:         if (dofix(idesc, "DIRECTORY CORRUPTED"))
 135:             dirty(&fileblk);
 136:         return (dp);
 137:     }
 138: dpok:
 139:     if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
 140:         return NULL;
 141:     dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
 142:     idesc->id_loc += dp->d_reclen;
 143:     idesc->id_filesize -= dp->d_reclen;
 144:     if ((idesc->id_loc % DIRBLKSIZ) == 0)
 145:         return (dp);
 146:     ndp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
 147:     if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
 148:         dircheck(idesc, ndp) == 0) {
 149:         size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
 150:         dp->d_reclen += size;
 151:         idesc->id_loc += size;
 152:         idesc->id_filesize -= size;
 153:         if (dofix(idesc, "DIRECTORY CORRUPTED"))
 154:             dirty(&fileblk);
 155:     }
 156:     return (dp);
 157: }
 158: 
 159: /*
 160:  * Verify that a directory entry is valid.
 161:  * This is a superset of the checks made in the kernel.
 162:  */
 163: dircheck(idesc, dp)
 164:     struct inodesc *idesc;
 165:     register DIRECT *dp;
 166: {
 167:     register int size;
 168:     register char *cp;
 169:     int spaceleft;
 170: 
 171:     size = DIRSIZ(dp);
 172:     spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
 173:     if (dp->d_ino < imax &&
 174:         dp->d_reclen != 0 &&
 175:         dp->d_reclen <= spaceleft &&
 176:         (dp->d_reclen & 0x3) == 0 &&
 177:         dp->d_reclen >= size &&
 178:         idesc->id_filesize >= size &&
 179:         dp->d_namlen <= MAXNAMLEN) {
 180:         if (dp->d_ino == 0)
 181:             return (1);
 182:         for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++)
 183:             if (*cp == 0 || (*cp++ & 0200))
 184:                 return (0);
 185:         if (*cp == 0)
 186:             return (1);
 187:     }
 188:     return (0);
 189: }
 190: 
 191: direrr(ino, s)
 192:     ino_t ino;
 193:     char *s;
 194: {
 195:     register DINODE *dp;
 196: 
 197:     pwarn("%s ", s);
 198:     pinode(ino);
 199:     printf("\n");
 200:     if (ino < ROOTINO || ino > imax) {
 201:         pfatal("NAME=%s\n", pathname);
 202:         return;
 203:     }
 204:     dp = ginode(ino);
 205:     if (ftypeok(dp))
 206:         pfatal("%s=%s\n", DIRCT(dp) ? "DIR" : "FILE", pathname);
 207:     else
 208:         pfatal("NAME=%s\n", pathname);
 209: }
 210: 
 211: adjust(idesc, lcnt)
 212:     register struct inodesc *idesc;
 213:     short lcnt;
 214: {
 215:     register DINODE *dp;
 216: 
 217:     dp = ginode(idesc->id_number);
 218:     if (dp->di_nlink == lcnt) {
 219:         if (linkup(idesc->id_number, (ino_t)0) == 0)
 220:             clri(idesc, "UNREF", 0);
 221:     } else {
 222:         pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname :
 223:             (DIRCT(dp) ? "DIR" : "FILE"));
 224:         pinode(idesc->id_number);
 225:         printf(" COUNT %d SHOULD BE %d",
 226:             dp->di_nlink, dp->di_nlink-lcnt);
 227:         if (preen) {
 228:             if (lcnt < 0) {
 229:                 printf("\n");
 230:                 pfatal("LINK COUNT INCREASING");
 231:             }
 232:             printf(" (ADJUSTED)\n");
 233:         }
 234:         if (preen || reply("ADJUST") == 1) {
 235:             dp->di_nlink -= lcnt;
 236:             inodirty();
 237:         }
 238:     }
 239: }
 240: 
 241: mkentry(idesc)
 242:     struct inodesc *idesc;
 243: {
 244:     register DIRECT *dirp = idesc->id_dirp;
 245:     DIRECT newent;
 246:     int newlen, oldlen;
 247: 
 248:     newent.d_namlen = 11;
 249:     newlen = DIRSIZ(&newent);
 250:     if (dirp->d_ino != 0)
 251:         oldlen = DIRSIZ(dirp);
 252:     else
 253:         oldlen = 0;
 254:     if (dirp->d_reclen - oldlen < newlen)
 255:         return (KEEPON);
 256:     newent.d_reclen = dirp->d_reclen - oldlen;
 257:     dirp->d_reclen = oldlen;
 258:     dirp = (struct direct *)(((char *)dirp) + oldlen);
 259:     dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */
 260:     dirp->d_reclen = newent.d_reclen;
 261:     dirp->d_namlen = strlen(idesc->id_name);
 262:     bcopy(idesc->id_name, dirp->d_name, dirp->d_namlen + 1);
 263:     return (ALTERED|STOP);
 264: }
 265: 
 266: chgino(idesc)
 267:     struct inodesc *idesc;
 268: {
 269:     register DIRECT *dirp = idesc->id_dirp;
 270: 
 271:     if (bcmp(dirp->d_name, idesc->id_name, dirp->d_namlen + 1))
 272:         return (KEEPON);
 273:     dirp->d_ino = idesc->id_parent;;
 274:     return (ALTERED|STOP);
 275: }
 276: 
 277: linkup(orphan, pdir)
 278:     ino_t orphan;
 279:     ino_t pdir;
 280: {
 281:     register DINODE *dp;
 282:     int lostdir, len;
 283:     ino_t oldlfdir;
 284:     struct inodesc idesc;
 285:     char tempname[BUFSIZ];
 286:     extern int pass4check();
 287: 
 288:     bzero((char *)&idesc, sizeof(struct inodesc));
 289:     dp = ginode(orphan);
 290:     lostdir = DIRCT(dp);
 291:     pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
 292:     pinode(orphan);
 293:     if (preen && dp->di_size == 0)
 294:         return (0);
 295:     if (preen)
 296:         printf(" (RECONNECTED)\n");
 297:     else
 298:         if (reply("RECONNECT") == 0)
 299:             return (0);
 300:     pathp = pathname;
 301:     *pathp++ = '/';
 302:     *pathp = '\0';
 303:     if (lfdir == 0) {
 304:         dp = ginode(ROOTINO);
 305:         idesc.id_name = lfname;
 306:         idesc.id_type = DATA;
 307:         idesc.id_func = findino;
 308:         idesc.id_number = ROOTINO;
 309:         (void)ckinode(dp, &idesc);
 310:         if (idesc.id_parent >= ROOTINO && idesc.id_parent < imax) {
 311:             lfdir = idesc.id_parent;
 312:         } else {
 313:             pwarn("NO lost+found DIRECTORY");
 314:             if (preen || reply("CREATE")) {
 315:                 lfdir = allocdir(ROOTINO, 0);
 316:                 if (lfdir != 0) {
 317:                     if (makeentry(ROOTINO, lfdir, lfname) != 0) {
 318:                         if (preen)
 319:                             printf(" (CREATED)\n");
 320:                     } else {
 321:                         freedir(lfdir, ROOTINO);
 322:                         lfdir = 0;
 323:                         if (preen)
 324:                             printf("\n");
 325:                     }
 326:                 }
 327:             }
 328:         }
 329:         if (lfdir == 0) {
 330:             pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY");
 331:             printf("\n\n");
 332:             return (0);
 333:         }
 334:     }
 335:     dp = ginode(lfdir);
 336:     if (!DIRCT(dp)) {
 337:         pfatal("lost+found IS NOT A DIRECTORY");
 338:         if (reply("REALLOCATE") == 0)
 339:             return (0);
 340:         oldlfdir = lfdir;
 341:         if ((lfdir = allocdir(ROOTINO, 0)) == 0) {
 342:             pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
 343:             return (0);
 344:         }
 345:         idesc.id_type = DATA;
 346:         idesc.id_func = chgino;
 347:         idesc.id_number = ROOTINO;
 348:         idesc.id_parent = lfdir;    /* new inumber for lost+found */
 349:         idesc.id_name = lfname;
 350:         if ((ckinode(ginode(ROOTINO), &idesc) & ALTERED) == 0) {
 351:             pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
 352:             return (0);
 353:         }
 354:         inodirty();
 355:         idesc.id_type = ADDR;
 356:         idesc.id_func = pass4check;
 357:         idesc.id_number = oldlfdir;
 358:         adjust(&idesc, lncntp[oldlfdir] + 1);
 359:         lncntp[oldlfdir] = 0;
 360:         dp = ginode(lfdir);
 361:     }
 362:     if (statemap[lfdir] != DFOUND) {
 363:         pfatal("SORRY. NO lost+found DIRECTORY\n\n");
 364:         return (0);
 365:     }
 366:     len = strlen(lfname);
 367:     bcopy(lfname, pathp, len + 1);
 368:     pathp += len;
 369:     len = lftempname(tempname, orphan);
 370:     if (makeentry(lfdir, orphan, tempname) == 0) {
 371:         pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
 372:         printf("\n\n");
 373:         return (0);
 374:     }
 375:     lncntp[orphan]--;
 376:     *pathp++ = '/';
 377:     bcopy(idesc.id_name, pathp, len + 1);
 378:     pathp += len;
 379:     if (lostdir) {
 380:         dp = ginode(orphan);
 381:         idesc.id_type = DATA;
 382:         idesc.id_func = chgino;
 383:         idesc.id_number = orphan;
 384:         idesc.id_fix = DONTKNOW;
 385:         idesc.id_name = "..";
 386:         idesc.id_parent = lfdir;    /* new value for ".." */
 387:         (void)ckinode(dp, &idesc);
 388:         dp = ginode(lfdir);
 389:         dp->di_nlink++;
 390:         inodirty();
 391:         lncntp[lfdir]++;
 392:         pwarn("DIR I=%u CONNECTED. ", orphan);
 393:         printf("PARENT WAS I=%u\n", pdir);
 394:         if (preen == 0)
 395:             printf("\n");
 396:     }
 397:     return (1);
 398: }
 399: 
 400: /*
 401:  * make an entry in a directory
 402:  */
 403: makeentry(parent, ino, name)
 404:     ino_t parent, ino;
 405:     char *name;
 406: {
 407:     DINODE *dp;
 408:     struct inodesc idesc;
 409: 
 410:     if (parent < ROOTINO || parent >= imax || ino < ROOTINO || ino >= imax)
 411:         return (0);
 412:     bzero(&idesc, sizeof(struct inodesc));
 413:     idesc.id_type = DATA;
 414:     idesc.id_func = mkentry;
 415:     idesc.id_number = parent;
 416:     idesc.id_parent = ino;  /* this is the inode to enter */
 417:     idesc.id_fix = DONTKNOW;
 418:     idesc.id_name = name;
 419:     dp = ginode(parent);
 420:     if (dp->di_size % DIRBLKSIZ) {
 421:         dp->di_size = roundup(dp->di_size, DIRBLKSIZ);
 422:         inodirty();
 423:     }
 424:     if ((ckinode(dp, &idesc) & ALTERED) != 0)
 425:         return (1);
 426:     if (expanddir(dp) == 0)
 427:         return (0);
 428:     return (ckinode(dp, &idesc) & ALTERED);
 429: }
 430: 
 431: /*
 432:  * Attempt to expand the size of a directory
 433:  */
 434: expanddir(dp)
 435:     register DINODE *dp;
 436: {
 437:     daddr_t lastbn, newblk;
 438:     char *cp, firstblk[DIRBLKSIZ];
 439: 
 440:     lastbn = lblkno(&sblock, dp->di_size);
 441:     if (lastbn >= NDADDR - 1)
 442:         return (0);
 443:     if ((newblk = allocblk(sblock.fs_frag)) == 0)
 444:         return (0);
 445:     dp->di_db[lastbn + 1] = dp->di_db[lastbn];
 446:     dp->di_db[lastbn] = newblk;
 447:     dp->di_size += sblock.fs_bsize;
 448:     dp->di_blocks += btodb(sblock.fs_bsize);
 449:     getblk(&fileblk, dp->di_db[lastbn + 1],
 450:         dblksize(&sblock, dp, lastbn + 1));
 451:     if (fileblk.b_errs != NULL)
 452:         goto bad;
 453:     bcopy(dirblk.b_buf, firstblk, DIRBLKSIZ);
 454:     getblk(&fileblk, newblk, sblock.fs_bsize);
 455:     if (fileblk.b_errs != NULL)
 456:         goto bad;
 457:     bcopy(firstblk, dirblk.b_buf, DIRBLKSIZ);
 458:     for (cp = &dirblk.b_buf[DIRBLKSIZ];
 459:          cp < &dirblk.b_buf[sblock.fs_bsize];
 460:          cp += DIRBLKSIZ)
 461:         bcopy((char *)&emptydir, cp, sizeof emptydir);
 462:     dirty(&fileblk);
 463:     getblk(&fileblk, dp->di_db[lastbn + 1],
 464:         dblksize(&sblock, dp, lastbn + 1));
 465:     if (fileblk.b_errs != NULL)
 466:         goto bad;
 467:     bcopy((char *)&emptydir, dirblk.b_buf, sizeof emptydir);
 468:     pwarn("NO SPACE LEFT IN %s", pathname);
 469:     if (preen)
 470:         printf(" (EXPANDED)\n");
 471:     else if (reply("EXPAND") == 0)
 472:         goto bad;
 473:     dirty(&fileblk);
 474:     inodirty();
 475:     return (1);
 476: bad:
 477:     dp->di_db[lastbn] = dp->di_db[lastbn + 1];
 478:     dp->di_db[lastbn + 1] = 0;
 479:     dp->di_size -= sblock.fs_bsize;
 480:     dp->di_blocks -= btodb(sblock.fs_bsize);
 481:     freeblk(newblk, sblock.fs_frag);
 482:     return (0);
 483: }
 484: 
 485: /*
 486:  * allocate a new directory
 487:  */
 488: allocdir(parent, request)
 489:     ino_t parent, request;
 490: {
 491:     ino_t ino;
 492:     char *cp;
 493:     DINODE *dp;
 494: 
 495:     ino = allocino(request, IFDIR|0755);
 496:     dirhead.dot_ino = ino;
 497:     dirhead.dotdot_ino = parent;
 498:     dp = ginode(ino);
 499:     getblk(&fileblk, dp->di_db[0], sblock.fs_fsize);
 500:     if (fileblk.b_errs != NULL) {
 501:         freeino(ino);
 502:         return (0);
 503:     }
 504:     bcopy((char *)&dirhead, dirblk.b_buf, sizeof dirhead);
 505:     for (cp = &dirblk.b_buf[DIRBLKSIZ];
 506:          cp < &dirblk.b_buf[sblock.fs_fsize];
 507:          cp += DIRBLKSIZ)
 508:         bcopy((char *)&emptydir, cp, sizeof emptydir);
 509:     dirty(&fileblk);
 510:     dp->di_nlink = 2;
 511:     inodirty();
 512:     if (ino == ROOTINO) {
 513:         lncntp[ino] = dp->di_nlink;
 514:         return(ino);
 515:     }
 516:     if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) {
 517:         freeino(ino);
 518:         return (0);
 519:     }
 520:     statemap[ino] = statemap[parent];
 521:     if (statemap[ino] == DSTATE) {
 522:         lncntp[ino] = dp->di_nlink;
 523:         lncntp[parent]++;
 524:     }
 525:     dp = ginode(parent);
 526:     dp->di_nlink++;
 527:     inodirty();
 528:     return (ino);
 529: }
 530: 
 531: /*
 532:  * free a directory inode
 533:  */
 534: freedir(ino, parent)
 535:     ino_t ino, parent;
 536: {
 537:     DINODE *dp;
 538: 
 539:     if (ino != parent) {
 540:         dp = ginode(parent);
 541:         dp->di_nlink--;
 542:         inodirty();
 543:     }
 544:     freeino(ino);
 545: }
 546: 
 547: /*
 548:  * generate a temporary name for the lost+found directory.
 549:  */
 550: lftempname(bufp, ino)
 551:     char *bufp;
 552:     ino_t ino;
 553: {
 554:     register ino_t in;
 555:     register char *cp;
 556:     int namlen;
 557: 
 558:     cp = bufp + 2;
 559:     for (in = imax; in > 0; in /= 10)
 560:         cp++;
 561:     *--cp = 0;
 562:     namlen = cp - bufp;
 563:     in = ino;
 564:     while (cp > bufp) {
 565:         *--cp = (in % 10) + '0';
 566:         in /= 10;
 567:     }
 568:     *cp = '#';
 569:     return (namlen);
 570: }

Defined functions

adjust defined in line 211; used 2 times
allocdir defined in line 488; used 5 times
chgino defined in line 266; used 2 times
descend defined in line 28; used 7 times
dircheck defined in line 163; used 2 times
direrr defined in line 191; used 12 times
dirscan defined in line 68; used 2 times
expanddir defined in line 434; used 1 times
freedir defined in line 534; used 1 times
fsck_readdir defined in line 110; used 3 times
lftempname defined in line 550; used 1 times
linkup defined in line 277; used 2 times
makeentry defined in line 403; used 2 times
mkentry defined in line 241; used 1 times

Defined variables

dirhead defined in line 24; used 4 times
emptydir defined in line 23; used 6 times
endpathname defined in line 21; never used
lfname defined in line 22; used 6 times
sccsid defined in line 8; never used

Defined macros

KERNEL defined in line 14; used 1 times
  • in line 16
MINDIRSIZE defined in line 19; used 2 times
Last modified: 1985-10-23
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2057
Valid CSS Valid XHTML 1.0 Strict