|
|
1.1 ! root 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.4 (Berkeley) 5/7/88"; ! 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: BUFAREA *getdirblk(); ! 28: ! 29: descend(parentino, inumber) ! 30: struct inodesc *parentino; ! 31: ino_t inumber; ! 32: { ! 33: register DINODE *dp; ! 34: struct inodesc curino; ! 35: ! 36: bzero((char *)&curino, sizeof(struct inodesc)); ! 37: if (statemap[inumber] != DSTATE) ! 38: errexit("BAD INODE %d TO DESCEND", statemap[inumber]); ! 39: statemap[inumber] = DFOUND; ! 40: dp = ginode(inumber); ! 41: if (dp->di_size == 0) { ! 42: direrr(inumber, "ZERO LENGTH DIRECTORY"); ! 43: if (reply("REMOVE") == 1) ! 44: statemap[inumber] = DCLEAR; ! 45: return; ! 46: } ! 47: if (dp->di_size < MINDIRSIZE) { ! 48: direrr(inumber, "DIRECTORY TOO SHORT"); ! 49: dp->di_size = MINDIRSIZE; ! 50: if (reply("FIX") == 1) ! 51: inodirty(); ! 52: } ! 53: if ((dp->di_size & (DIRBLKSIZ - 1)) != 0) { ! 54: pwarn("DIRECTORY %s: LENGTH %d NOT MULTIPLE OF %d", ! 55: pathname, dp->di_size, DIRBLKSIZ); ! 56: dp->di_size = roundup(dp->di_size, DIRBLKSIZ); ! 57: if (preen) ! 58: printf(" (ADJUSTED)\n"); ! 59: if (preen || reply("ADJUST") == 1) ! 60: inodirty(); ! 61: } ! 62: curino.id_type = DATA; ! 63: curino.id_func = parentino->id_func; ! 64: curino.id_parent = parentino->id_number; ! 65: curino.id_number = inumber; ! 66: (void)ckinode(dp, &curino); ! 67: if (curino.id_entryno < 2) { ! 68: direrr(inumber, "NULL DIRECTORY"); ! 69: if (reply("REMOVE") == 1) ! 70: statemap[inumber] = DCLEAR; ! 71: } ! 72: } ! 73: ! 74: dirscan(idesc) ! 75: register struct inodesc *idesc; ! 76: { ! 77: register DIRECT *dp; ! 78: register BUFAREA *bp; ! 79: int dsize, n; ! 80: long blksiz; ! 81: char dbuf[DIRBLKSIZ]; ! 82: ! 83: if (idesc->id_type != DATA) ! 84: errexit("wrong type to dirscan %d\n", idesc->id_type); ! 85: if (idesc->id_entryno == 0 && ! 86: (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) ! 87: idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); ! 88: blksiz = idesc->id_numfrags * sblock.fs_fsize; ! 89: if (outrange(idesc->id_blkno, idesc->id_numfrags)) { ! 90: idesc->id_filesize -= blksiz; ! 91: return (SKIP); ! 92: } ! 93: idesc->id_loc = 0; ! 94: for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { ! 95: dsize = dp->d_reclen; ! 96: bcopy((char *)dp, dbuf, dsize); ! 97: idesc->id_dirp = (DIRECT *)dbuf; ! 98: if ((n = (*idesc->id_func)(idesc)) & ALTERED) { ! 99: bp = getdirblk(idesc->id_blkno, blksiz); ! 100: bcopy(dbuf, (char *)dp, dsize); ! 101: dirty(bp); ! 102: sbdirty(); ! 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: register BUFAREA *bp; ! 119: long size, blksiz; ! 120: ! 121: blksiz = idesc->id_numfrags * sblock.fs_fsize; ! 122: bp = getdirblk(idesc->id_blkno, blksiz); ! 123: if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && ! 124: idesc->id_loc < blksiz) { ! 125: dp = (DIRECT *)(bp->b_un.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(bp); ! 136: return (dp); ! 137: } ! 138: dpok: ! 139: if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) ! 140: return NULL; ! 141: dp = (DIRECT *)(bp->b_un.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 *)(bp->b_un.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(bp); ! 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: if ((ckinode(dp, &idesc) & FOUND) != 0) { ! 310: lfdir = idesc.id_parent; ! 311: } else { ! 312: pwarn("NO lost+found DIRECTORY"); ! 313: if (preen || reply("CREATE")) { ! 314: lfdir = allocdir(ROOTINO, 0); ! 315: if (lfdir != 0) { ! 316: if (makeentry(ROOTINO, lfdir, lfname) != 0) { ! 317: if (preen) ! 318: printf(" (CREATED)\n"); ! 319: } else { ! 320: freedir(lfdir, ROOTINO); ! 321: lfdir = 0; ! 322: if (preen) ! 323: printf("\n"); ! 324: } ! 325: } ! 326: } ! 327: } ! 328: if (lfdir == 0) { ! 329: pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); ! 330: printf("\n\n"); ! 331: return (0); ! 332: } ! 333: } ! 334: dp = ginode(lfdir); ! 335: if (!DIRCT(dp)) { ! 336: pfatal("lost+found IS NOT A DIRECTORY"); ! 337: if (reply("REALLOCATE") == 0) ! 338: return (0); ! 339: oldlfdir = lfdir; ! 340: if ((lfdir = allocdir(ROOTINO, 0)) == 0) { ! 341: pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); ! 342: return (0); ! 343: } ! 344: idesc.id_type = DATA; ! 345: idesc.id_func = chgino; ! 346: idesc.id_number = ROOTINO; ! 347: idesc.id_parent = lfdir; /* new inumber for lost+found */ ! 348: idesc.id_name = lfname; ! 349: if ((ckinode(ginode(ROOTINO), &idesc) & ALTERED) == 0) { ! 350: pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); ! 351: return (0); ! 352: } ! 353: inodirty(); ! 354: idesc.id_type = ADDR; ! 355: idesc.id_func = pass4check; ! 356: idesc.id_number = oldlfdir; ! 357: adjust(&idesc, lncntp[oldlfdir] + 1); ! 358: lncntp[oldlfdir] = 0; ! 359: dp = ginode(lfdir); ! 360: } ! 361: if (statemap[lfdir] != DFOUND) { ! 362: pfatal("SORRY. NO lost+found DIRECTORY\n\n"); ! 363: return (0); ! 364: } ! 365: len = strlen(lfname); ! 366: bcopy(lfname, pathp, len + 1); ! 367: pathp += len; ! 368: len = lftempname(tempname, orphan); ! 369: if (makeentry(lfdir, orphan, tempname) == 0) { ! 370: pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); ! 371: printf("\n\n"); ! 372: return (0); ! 373: } ! 374: lncntp[orphan]--; ! 375: *pathp++ = '/'; ! 376: bcopy(tempname, pathp, len + 1); ! 377: pathp += len; ! 378: if (lostdir) { ! 379: dp = ginode(orphan); ! 380: idesc.id_type = DATA; ! 381: idesc.id_func = chgino; ! 382: idesc.id_number = orphan; ! 383: idesc.id_fix = DONTKNOW; ! 384: idesc.id_name = ".."; ! 385: idesc.id_parent = lfdir; /* new value for ".." */ ! 386: (void)ckinode(dp, &idesc); ! 387: dp = ginode(lfdir); ! 388: dp->di_nlink++; ! 389: inodirty(); ! 390: lncntp[lfdir]++; ! 391: pwarn("DIR I=%u CONNECTED. ", orphan); ! 392: printf("PARENT WAS I=%u\n", pdir); ! 393: if (preen == 0) ! 394: printf("\n"); ! 395: } ! 396: return (1); ! 397: } ! 398: ! 399: /* ! 400: * make an entry in a directory ! 401: */ ! 402: makeentry(parent, ino, name) ! 403: ino_t parent, ino; ! 404: char *name; ! 405: { ! 406: DINODE *dp; ! 407: struct inodesc idesc; ! 408: ! 409: if (parent < ROOTINO || parent >= imax || ino < ROOTINO || ino >= imax) ! 410: return (0); ! 411: bzero(&idesc, sizeof(struct inodesc)); ! 412: idesc.id_type = DATA; ! 413: idesc.id_func = mkentry; ! 414: idesc.id_number = parent; ! 415: idesc.id_parent = ino; /* this is the inode to enter */ ! 416: idesc.id_fix = DONTKNOW; ! 417: idesc.id_name = name; ! 418: dp = ginode(parent); ! 419: if (dp->di_size % DIRBLKSIZ) { ! 420: dp->di_size = roundup(dp->di_size, DIRBLKSIZ); ! 421: inodirty(); ! 422: } ! 423: if ((ckinode(dp, &idesc) & ALTERED) != 0) ! 424: return (1); ! 425: if (expanddir(dp) == 0) ! 426: return (0); ! 427: return (ckinode(dp, &idesc) & ALTERED); ! 428: } ! 429: ! 430: /* ! 431: * Attempt to expand the size of a directory ! 432: */ ! 433: expanddir(dp) ! 434: register DINODE *dp; ! 435: { ! 436: daddr_t lastbn, newblk; ! 437: register BUFAREA *bp; ! 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: bp = getdirblk(dp->di_db[lastbn + 1], ! 450: dblksize(&sblock, dp, lastbn + 1)); ! 451: if (bp->b_errs != NULL) ! 452: goto bad; ! 453: bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ); ! 454: bp = getdirblk(newblk, sblock.fs_bsize); ! 455: if (bp->b_errs != NULL) ! 456: goto bad; ! 457: bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ); ! 458: for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; ! 459: cp < &bp->b_un.b_buf[sblock.fs_bsize]; ! 460: cp += DIRBLKSIZ) ! 461: bcopy((char *)&emptydir, cp, sizeof emptydir); ! 462: dirty(bp); ! 463: bp = getdirblk(dp->di_db[lastbn + 1], ! 464: dblksize(&sblock, dp, lastbn + 1)); ! 465: if (bp->b_errs != NULL) ! 466: goto bad; ! 467: bcopy((char *)&emptydir, bp->b_un.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(bp); ! 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: register BUFAREA *bp; ! 495: ! 496: ino = allocino(request, IFDIR|0755); ! 497: dirhead.dot_ino = ino; ! 498: dirhead.dotdot_ino = parent; ! 499: dp = ginode(ino); ! 500: bp = getdirblk(dp->di_db[0], sblock.fs_fsize); ! 501: if (bp->b_errs != NULL) { ! 502: freeino(ino); ! 503: return (0); ! 504: } ! 505: bcopy((char *)&dirhead, bp->b_un.b_buf, sizeof dirhead); ! 506: for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; ! 507: cp < &bp->b_un.b_buf[sblock.fs_fsize]; ! 508: cp += DIRBLKSIZ) ! 509: bcopy((char *)&emptydir, cp, sizeof emptydir); ! 510: dirty(bp); ! 511: dp->di_nlink = 2; ! 512: inodirty(); ! 513: if (ino == ROOTINO) { ! 514: lncntp[ino] = dp->di_nlink; ! 515: return(ino); ! 516: } ! 517: if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { ! 518: freeino(ino); ! 519: return (0); ! 520: } ! 521: statemap[ino] = statemap[parent]; ! 522: if (statemap[ino] == DSTATE) { ! 523: lncntp[ino] = dp->di_nlink; ! 524: lncntp[parent]++; ! 525: } ! 526: dp = ginode(parent); ! 527: dp->di_nlink++; ! 528: inodirty(); ! 529: return (ino); ! 530: } ! 531: ! 532: /* ! 533: * free a directory inode ! 534: */ ! 535: freedir(ino, parent) ! 536: ino_t ino, parent; ! 537: { ! 538: DINODE *dp; ! 539: ! 540: if (ino != parent) { ! 541: dp = ginode(parent); ! 542: dp->di_nlink--; ! 543: inodirty(); ! 544: } ! 545: freeino(ino); ! 546: } ! 547: ! 548: /* ! 549: * generate a temporary name for the lost+found directory. ! 550: */ ! 551: lftempname(bufp, ino) ! 552: char *bufp; ! 553: ino_t ino; ! 554: { ! 555: register ino_t in; ! 556: register char *cp; ! 557: int namlen; ! 558: ! 559: cp = bufp + 2; ! 560: for (in = imax; in > 0; in /= 10) ! 561: cp++; ! 562: *--cp = 0; ! 563: namlen = cp - bufp; ! 564: in = ino; ! 565: while (cp > bufp) { ! 566: *--cp = (in % 10) + '0'; ! 567: in /= 10; ! 568: } ! 569: *cp = '#'; ! 570: return (namlen); ! 571: } ! 572: ! 573: /* ! 574: * Get a directory block. ! 575: * Insure that it is held until another is requested. ! 576: */ ! 577: BUFAREA * ! 578: getdirblk(blkno, size) ! 579: daddr_t blkno; ! 580: long size; ! 581: { ! 582: static BUFAREA *pbp = 0; ! 583: ! 584: if (pbp != 0) ! 585: pbp->b_flags &= ~B_INUSE; ! 586: pbp = getdatablk(blkno, size); ! 587: return (pbp); ! 588: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.