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

Defined functions

adjust defined in line 213; used 2 times
allocdir defined in line 485; used 5 times
chgino defined in line 268; used 2 times
descend defined in line 33; used 7 times
dircheck defined in line 165; used 2 times
direrr defined in line 193; used 12 times
dirscan defined in line 73; used 3 times
expanddir defined in line 435; used 1 times
freedir defined in line 533; used 1 times
fsck_readdir defined in line 113; used 3 times
lftempname defined in line 549; used 1 times
linkup defined in line 279; used 2 times
makeentry defined in line 404; used 2 times
mkentry defined in line 243; used 1 times

Defined variables

dirhead defined in line 28; used 4 times
emptydir defined in line 21; used 6 times
endpathname defined in line 19; never used
lfname defined in line 20; used 6 times
sccsid defined in line 8; never used

Defined macros

MINDIRSIZE defined in line 17; used 2 times
Last modified: 1996-05-09
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4173
Valid CSS Valid XHTML 1.0 Strict