|
|
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.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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.