|
|
1.1 ! root 1: /* ! 2: * $Header: /usr.src/local/unmkfs.c,v 1.4 90/07/06 11:43:38 root Exp $ ! 3: * $Log: /usr.src/local/unmkfs.c,v $ ! 4: * Revision 1.4 90/07/06 11:43:38 root ! 5: * steve 7/6/90 ! 6: * Changed usage to ! 7: * /etc/unmkfs [ -prefix ] directory nblocks [ file ] ! 8: * Corrected bug with 14-character filenames, which caused garbage in ! 9: * some lines (because of missing NUL terminator). Changed error messages. ! 10: * Added forward declarations of all functions. ! 11: * This corresponds to V3.0.1 object. ! 12: * ,. ! 13: * ! 14: * Revision 1.3 89/02/24 12:44:05 bin ! 15: * Defined realloc to remove integer pointer pun message. ! 16: * ! 17: * Revision 1.2 89/02/24 12:40:52 bin ! 18: * Change to generate file names for multiple prototypes based on ! 19: * a command-line supplied prefix. ! 20: * ! 21: * Revision 1.1 89/02/24 12:32:32 wgl ! 22: * Initial revision ! 23: * ! 24: */ ! 25: static char *revision = "$Revision 1.1 $"; ! 26: static char *header = ! 27: "$Header: /usr.src/local/unmkfs.c,v 1.4 90/07/06 11:43:38 root Exp $"; ! 28: ! 29: /* ! 30: * Given a directory tree root and a filesystem size, ! 31: * write the fewest mkfs proto files necessary to ! 32: * copy the directory tree onto floppies. ! 33: * Preserve the ownerships, modes, dates, links, and order of links ! 34: * within a directory. ! 35: * Make each fragment root based so that a series of ! 36: * mount /dev/fd0 /f0; cpdir /f0 destination; umount /dev/fd0 ! 37: * can be used to reinstall the original directory. ! 38: * ! 39: * The algorithm for partitioning is empirical and may not work very ! 40: * well for directories other than the pc coherent distribution. ! 41: * Some degree of interaction is probably desirable for getting ! 42: * reasonable partitioning of arbitrary directory trees. ! 43: * ! 44: * Overview: ! 45: * After minimal checks for necessary conditions, ! 46: * Read the source directory tree into a memory ! 47: * resident pseudo file system in which MINODE inumbers ! 48: * identify unique files and replace dp->d_ino in the ! 49: * directories. ! 50: * While the original root directory is not flagged I_DONE, ! 51: * copy those parts of the tree that are not flagged I_DONE. ! 52: * While the copy is too big for the floppy partition ! 53: * prune the copy. ! 54: * For each pruned copy produced, write the mkfs proto. ! 55: * ! 56: * -- rec 26.VI.84 -- invent cpfrag. ! 57: * -- rec 12.IX.84 -- reconstruct cpfrag -> unmkfs. ! 58: * -- norm 04.I.85 -- fix misc. bugs for z8000 ! 59: */ ! 60: #include <stdio.h> ! 61: #include <sys/dir.h> ! 62: #include <assert.h> ! 63: #include <sys/const.h> ! 64: #include <sys/types.h> ! 65: #include <sys/stat.h> ! 66: #include <sys/filsys.h> ! 67: #include <sys/ino.h> ! 68: ! 69: extern char *realloc(); ! 70: extern char edata[]; ! 71: ! 72: #define USAGE "Usage: /etc/unmkfs [ -prefix ] directory nblocks [ file ]\n" ! 73: #define IHASH 128 ! 74: #define MAXFNAME 512 ! 75: #define NDISK 32 ! 76: ! 77: typedef struct MINODE { ! 78: struct MINODE *i_link1; /* dev x ino hash linkage */ ! 79: struct MINODE *i_link2; /* my inumbering hash linkage */ ! 80: char *i_linkname; /* Name of first instance of file in copy */ ! 81: int i_mino; /* My inumber */ ! 82: int i_flag; /* Miscellaneous flags */ ! 83: int i_blks; /* Cumulative block size, includes indirects */ ! 84: int i_inos; /* Cumulative inodes used */ ! 85: int i_size; /* Total data, indir, and inode blocks */ ! 86: int i_isdir; /* Simplify many tests */ ! 87: dev_t i_dev; /* Some fields from stat() */ ! 88: ino_t i_ino; ! 89: int i_mode; ! 90: int i_nlink; ! 91: int i_uid; ! 92: int i_gid; ! 93: int i_rdev; ! 94: time_t i_mtime; ! 95: int i_nent; /* Number of directory entries */ ! 96: struct direct i_elem[]; /* Directory entries */ ! 97: } MINODE; ! 98: ! 99: #define I_DONE 1 /* Inode is done */ ! 100: #define I_COUNT 2 /* Inode is counted */ ! 101: #define I_PUT 8 /* Inode size reported */ ! 102: #define I_DONE1 16 /* Inode has been done once, for directories */ ! 103: #define I_PURGE 32 /* Inode should be purged */ ! 104: #define I_KEEP 64 /* Keep entire subdirectory */ ! 105: #define I_CANFIT 128 /* Subdirectory could fit on disk */ ! 106: #define I_ISMADE 256 /* Inode is made, do link */ ! 107: ! 108: MINODE *disks[NDISK]; ! 109: int dsize; ! 110: int dused; ! 111: int vflag = 1; ! 112: int outf = 0; /* Use file outpre.outsuf instead of stdout */ ! 113: int excess; ! 114: int ndisk; ! 115: int myuid; ! 116: int mygid; ! 117: ! 118: char outpre[64]; /* Settable output file prefix */ ! 119: char outsuf[] = ".p??"; /* Suffix for output file name */ ! 120: ! 121: FILE *ofp; ! 122: ! 123: /* Forward. */ ! 124: MINODE *makeroot(); ! 125: void makedir(); ! 126: void printroot(); ! 127: void printdir(); ! 128: void splat(); ! 129: void makedisk(); ! 130: void mkfs(); ! 131: void insdir(); ! 132: void indent(); ! 133: void uflagroot(); ! 134: void uflagdir(); ! 135: void flagroot(); ! 136: void flagdir(); ! 137: void sizeroot(); ! 138: void sizedir(); ! 139: MINODE *cpyroot(); ! 140: MINODE *cpydir(); ! 141: void keepers(); ! 142: MINODE *select(); ! 143: void purge(); ! 144: void donedir(); ! 145: void markdir(); ! 146: int entermi(); ! 147: int duplmi(); ! 148: MINODE *fetchmi(); ! 149: void freemi(); ! 150: long blkuse(); ! 151: char *string(); ! 152: char *myalloc(); ! 153: void usage(); ! 154: void fatal(); ! 155: ! 156: char fname[MAXFNAME]; /* Filename buffer */ ! 157: char fname1[MAXFNAME]; /* Second file name buffer */ ! 158: char cmdbuf[128]; ! 159: struct stat sbuf; /* Stat buffer */ ! 160: struct stat tbuf; /* Time buffer, leave zero for all times */ ! 161: char *argv0; /* For error recovery */ ! 162: ! 163: main(argc, argv) int argc; char *argv[]; ! 164: { ! 165: int i; ! 166: MINODE *rip, *tip, *sip; ! 167: ! 168: argv0 = argv[0]; ! 169: if (argc > 1 && argv[1][0] == '-') { ! 170: strcpy(outpre, &argv[1][1]); ! 171: outf = 1; ! 172: ++argv; ! 173: --argc; ! 174: } ! 175: if (argc < 3 || argc > 4) ! 176: usage(); ! 177: if ((dsize = atoi(argv[2])) <= 0) ! 178: fatal("illegal size \"%s\"", argv[2]); ! 179: if (argc == 4) { ! 180: if (stat(argv[3], &tbuf) < 0) ! 181: fatal("cannot stat \"%s\"", argv[3]); ! 182: } else ! 183: tbuf.st_mtime = 0; /* make time == 0 to get all files */ ! 184: rip = makeroot(argv[1]); ! 185: while ((rip->i_flag & I_DONE) == 0) { ! 186: tip = cpyroot(rip); ! 187: dused = 4; ! 188: keepers(tip); ! 189: excess = tip->i_size + 2 - dsize; ! 190: while (excess > 0) { ! 191: while ((sip = select(tip)) == NULL) { ! 192: excess += 1; ! 193: } ! 194: flagroot(sip, I_PURGE); ! 195: purge(tip); ! 196: sizeroot(tip); ! 197: excess = tip->i_size + 2 - dsize; ! 198: } ! 199: donedir(tip); ! 200: markdir(rip); ! 201: disks[ndisk] = tip; ! 202: ndisk += 1; ! 203: } ! 204: for (i = 0; i < ndisk; i += 1) ! 205: makedisk(i, argv[1]); ! 206: } ! 207: ! 208: /* ! 209: ** Get the MINODE * corresponding to fname, and call ! 210: ** makedir() to build the in-memory tree. Call sizeroot() ! 211: ** return the MINODE corresponding to the root. ! 212: */ ! 213: MINODE * ! 214: makeroot(cp) char *cp; ! 215: { ! 216: MINODE *rip; ! 217: ! 218: if (strlen(cp) >= MAXFNAME) ! 219: fatal("directory path name too long"); ! 220: strcpy(fname, cp); ! 221: if (stat(fname, &sbuf) < 0) ! 222: fatal("cannot stat \"%s\"", fname); ! 223: if ((sbuf.st_mode&S_IFMT) != S_IFDIR) ! 224: fatal("\"%s\" is not a directory"); ! 225: rip = fetchmi(entermi()); ! 226: if (cp[0] == '/' && cp[1] == '\0') ! 227: fname[0] = 0; ! 228: makedir(rip); ! 229: sizeroot(rip); ! 230: return (rip); ! 231: } ! 232: ! 233: /* ! 234: ** Recursively build a tree of MINODE pointers ! 235: ** for the directory ip. ! 236: */ ! 237: void ! 238: makedir(ip) MINODE *ip; ! 239: { ! 240: int fd; ! 241: int i; ! 242: struct direct *dp1, *dp2; ! 243: MINODE *tip; ! 244: char *cp; ! 245: ! 246: cp = fname + strlen(fname); ! 247: if (cp + DIRSIZ + 2 >= fname + MAXFNAME) ! 248: fatal("directory tree too deep"); ! 249: if ((fd = open(fname, 0)) < 0) ! 250: fatal("cannot open \"%s\"", fname); ! 251: i = ip->i_nent * sizeof(struct direct); ! 252: if (read(fd, ip->i_elem, i) != i) ! 253: fatal("%s: read error", fname); ! 254: close(fd); ! 255: *cp = '/'; ! 256: dp1 = dp2 = ip->i_elem; ! 257: for (i = 0; i < ip->i_nent; i += 1) { ! 258: if (dp2->d_name[0] == '.') { ! 259: if (dp2->d_name[1] == 0 ! 260: || (dp2->d_name[1] == '.' && dp2->d_name[2] == 0)) ! 261: dp2->d_ino = 0; ! 262: } ! 263: if (dp2->d_ino != 0) { ! 264: strncpy(cp+1, dp2->d_name, DIRSIZ); ! 265: if (stat(fname, &sbuf) < 0) ! 266: fatal("cannot stat \"%s\"", fname); ! 267: dp2->d_ino = entermi(); ! 268: } ! 269: if (dp2->d_ino != 0) { ! 270: if (dp1 != dp2) ! 271: *dp1 = *dp2; ! 272: dp1 += 1; ! 273: } ! 274: dp2 += 1; ! 275: } ! 276: ip->i_nent = dp1 - ip->i_elem; ! 277: i = sizeof(MINODE) + ip->i_nent * sizeof(struct direct); ! 278: if (realloc(ip, i) != ip) ! 279: fatal("realloc moved block"); ! 280: dp1 = ip->i_elem; ! 281: for (i = 0; i < ip->i_nent; i += 1) { ! 282: tip = fetchmi(dp1->d_ino); ! 283: if (tip->i_isdir) { ! 284: strncpy(cp+1, dp1->d_name, DIRSIZ); ! 285: makedir(tip); ! 286: } ! 287: dp1 += 1; ! 288: } ! 289: *cp = 0; ! 290: } ! 291: ! 292: void ! 293: printroot(cp, rip) char *cp; MINODE *rip; ! 294: { ! 295: uflagroot(rip, I_PUT); ! 296: strcpy(fname, cp); ! 297: splat(rip); ! 298: if (cp[0] == '/' && cp[1] == 0) ! 299: fname[0] = 0; ! 300: printdir(rip); ! 301: } ! 302: ! 303: void ! 304: printdir(ip) MINODE *ip; ! 305: { ! 306: int i; ! 307: MINODE *tip; ! 308: struct direct *dp; ! 309: char *cp; ! 310: ! 311: dp = ip->i_elem; ! 312: cp = fname + strlen(fname); ! 313: *cp = '/'; ! 314: for (i = 0; i < ip->i_nent; i += 1) { ! 315: tip = fetchmi(dp->d_ino); ! 316: strncpy(cp+1, dp->d_name, DIRSIZ); ! 317: splat(tip); ! 318: if (tip->i_isdir) ! 319: printdir(tip); ! 320: dp += 1; ! 321: } ! 322: *cp = 0; ! 323: } ! 324: ! 325: void ! 326: splat(ip) MINODE *ip; ! 327: { ! 328: printf("(%2d,%2d,%4d) ", ! 329: major(ip->i_dev), minor(ip->i_dev), ip->i_ino); ! 330: if ((ip->i_flag & I_PUT) != 0) ! 331: printf("%6d %4d %6d ", 0, 0, 0); ! 332: else ! 333: printf("%6d %4d %6d ", ip->i_size, ip->i_inos, ip->i_blks); ! 334: printf("%s\n", fname); ! 335: ip->i_flag |= I_PUT; ! 336: } ! 337: ! 338: void ! 339: makedisk(n, cp) char *cp; ! 340: { ! 341: MINODE *ip; ! 342: char outfile[72]; ! 343: ! 344: ip = disks[n]; ! 345: fprintf(stderr, "Disk %d: %d inodes, %d data blocks\n", ! 346: n+1, ip->i_inos, ip->i_blks); ! 347: if (outf == 1) { ! 348: outsuf[2] = (n+1)/10 + '0'; ! 349: outsuf[3] = (n+1)%10 + '0'; ! 350: outsuf[4] = '\0'; ! 351: strcpy(outfile, outpre); ! 352: strcat(outfile, outsuf); ! 353: if ((ofp = fopen(outfile, "w")) == NULL) ! 354: fatal("cannot open output file \"%s\"", outfile); ! 355: } else ! 356: ofp = stdout; ! 357: mkfs(ip->i_inos); ! 358: if (cp[0] == '/' && cp[1] == 0) ! 359: fname[0] = 0; ! 360: else ! 361: strcpy(fname, cp); ! 362: fprintf(ofp, "d--%03o %3d %3d\n", ip->i_mode&0777, ip->i_uid, ! 363: ip->i_gid); ! 364: indent(1); ! 365: insdir(ip); ! 366: indent(-1); ! 367: fprintf(ofp, "$\n"); ! 368: } ! 369: ! 370: void ! 371: mkfs(nino) ! 372: { ! 373: fprintf(ofp, "/dev/null xxxxx xxxxx\n"); ! 374: fprintf(ofp, "%d %d 1 1\n", dsize, nino); ! 375: } ! 376: ! 377: void ! 378: insdir(ip) MINODE *ip; ! 379: { ! 380: int i; ! 381: MINODE *tip; ! 382: struct direct *dp; ! 383: char *cp, *cp1, buf[DIRSIZ+1]; ! 384: char dtype; ! 385: ! 386: cp = fname + strlen(fname); ! 387: cp1 = fname1 + strlen(fname1); ! 388: *cp = '/'; ! 389: *cp1 = '/'; ! 390: dp = ip->i_elem; ! 391: for (i = 0; i < ip->i_nent; i += 1) { ! 392: tip = fetchmi(dp->d_ino); ! 393: strncpy(buf, dp->d_name, DIRSIZ); ! 394: buf[DIRSIZ] = '\0'; ! 395: strcpy(cp+1, buf); ! 396: strcpy(cp1+1, buf); ! 397: indent(0); ! 398: fprintf(ofp, "%-14s", buf); ! 399: if (tip->i_flag & I_ISMADE) { ! 400: fprintf(ofp, " l----- 0 0 %s\n", tip->i_linkname); ! 401: dp += 1; ! 402: continue; ! 403: } ! 404: switch (tip->i_mode & S_IFMT) { ! 405: case S_IFDIR: ! 406: dtype = 'd'; ! 407: break; ! 408: case S_IFCHR: ! 409: dtype = 'c'; ! 410: break; ! 411: case S_IFBLK: ! 412: dtype = 'b'; ! 413: break; ! 414: case S_IFREG: ! 415: dtype = '-'; ! 416: break; ! 417: default: ! 418: fatal("%s: bad file type %d", fname, tip->i_mode&S_IFMT); ! 419: } ! 420: ! 421: fprintf(ofp, " %c%c%c%03o %3d %3d", ! 422: dtype, ! 423: (tip->i_mode&ISUID) ? 'u' : '-', ! 424: (tip->i_mode&ISGID) ? 'g' : '-', ! 425: tip->i_mode&0777, ! 426: tip->i_uid, tip->i_gid); ! 427: switch (tip->i_mode & S_IFMT) { ! 428: case S_IFDIR: ! 429: fputc('\n', ofp); ! 430: indent(1); ! 431: insdir(tip); ! 432: indent(-1); ! 433: indent(0); ! 434: fprintf(ofp, "$\n"); ! 435: break; ! 436: case S_IFCHR: ! 437: case S_IFBLK: ! 438: fprintf(ofp, "%3d %3d\n", major(tip->i_rdev), ! 439: minor(tip->i_rdev)); ! 440: break; ! 441: case S_IFREG: ! 442: fprintf(ofp, " %s\n", fname); ! 443: break; ! 444: } ! 445: if (tip->i_nlink > 1) ! 446: tip->i_linkname = string(fname1); ! 447: tip->i_flag |= I_ISMADE; ! 448: dp += 1; ! 449: } ! 450: *cp = 0; ! 451: *cp1 = 0; ! 452: } ! 453: ! 454: void ! 455: indent(n) int n; ! 456: { ! 457: static int indent; ! 458: ! 459: if (n < 0) ! 460: indent -= 1; ! 461: else if (n > 0) ! 462: indent += 1; ! 463: else for (n = indent; --n >= 0; fprintf(ofp, " ")); ! 464: } ! 465: ! 466: void ! 467: uflagroot(rip, flag) MINODE *rip; ! 468: { ! 469: uflagdir(rip, flag); ! 470: rip->i_flag &= ~flag; ! 471: } ! 472: ! 473: /* ! 474: ** Recursively turn off flag in ip and ! 475: ** all directories below ip. ! 476: */ ! 477: void ! 478: uflagdir(ip, flag) MINODE *ip; ! 479: { ! 480: int i; ! 481: MINODE *tip; ! 482: struct direct *dp; ! 483: ! 484: dp = ip->i_elem; ! 485: for (i = 0; i < ip->i_nent; i += 1) { ! 486: tip = fetchmi(dp->d_ino); ! 487: tip->i_flag &= ~flag; ! 488: if (tip->i_isdir) ! 489: uflagdir(tip, flag); ! 490: dp += 1; ! 491: } ! 492: } ! 493: ! 494: void ! 495: flagroot(ip, flag) MINODE *ip; int flag; ! 496: { ! 497: if (ip->i_isdir) ! 498: flagdir(ip, flag); ! 499: ip->i_flag |= flag; ! 500: } ! 501: ! 502: void ! 503: flagdir(ip, flag) MINODE *ip; int flag; ! 504: { ! 505: int i; ! 506: MINODE *tip; ! 507: struct direct *dp; ! 508: ! 509: dp = ip->i_elem; ! 510: for (i = 0; i < ip->i_nent; i += 1) { ! 511: tip = fetchmi(dp->d_ino); ! 512: if (tip->i_isdir) ! 513: flagdir(tip, flag); ! 514: tip->i_flag |= flag; ! 515: dp += 1; ! 516: } ! 517: } ! 518: ! 519: void ! 520: sizeroot(rip) MINODE *rip; ! 521: { ! 522: uflagroot(rip, I_COUNT); ! 523: sizedir(rip); ! 524: /* Add in bad block inode */ ! 525: rip->i_size = rip->i_blks + (++rip->i_inos+INOPB-1) / INOPB; ! 526: } ! 527: ! 528: /* ! 529: ** For subdirectories not flagged I_COUNT, ! 530: ** add the isize and blksize to that of ip. ! 531: */ ! 532: void ! 533: sizedir(ip) MINODE *ip; ! 534: { ! 535: int i; ! 536: MINODE *tip; ! 537: struct direct *dp; ! 538: ! 539: ip->i_blks = 0; ! 540: ip->i_inos = 0; ! 541: dp = ip->i_elem; ! 542: for (i = 0; i < ip->i_nent; i += 1) { ! 543: tip = fetchmi(dp->d_ino); ! 544: if (tip->i_isdir) ! 545: sizedir(tip); ! 546: if ((tip->i_flag&I_COUNT) == 0) { ! 547: ip->i_inos += tip->i_inos; ! 548: ip->i_blks += tip->i_blks; ! 549: tip->i_flag |= I_COUNT; ! 550: } ! 551: dp += 1; ! 552: } ! 553: ip->i_inos += 1; /* For me */ ! 554: ip->i_blks += blkuse((long)(ip->i_nent+2)*sizeof(struct direct)); ! 555: ip->i_size = ip->i_blks + (ip->i_inos+INOPB-1) / INOPB; ! 556: } ! 557: ! 558: MINODE * ! 559: cpyroot(rip) MINODE *rip; ! 560: { ! 561: uflagdir(rip, I_PURGE|I_KEEP); ! 562: rip = cpydir(rip); ! 563: sizeroot(rip); ! 564: return (rip); ! 565: } ! 566: ! 567: MINODE * ! 568: cpydir(ip) MINODE *ip; ! 569: { ! 570: int i; ! 571: MINODE *nip, *tip; ! 572: struct direct *dp1, *dp2; ! 573: ! 574: nip = fetchmi(duplmi(ip)); ! 575: nip->i_nent = 0; ! 576: dp1 = ip->i_elem; ! 577: dp2 = nip->i_elem; ! 578: for (i = 0; i < ip->i_nent; i += 1) { ! 579: tip = fetchmi(dp1->d_ino); ! 580: if ((tip->i_flag&I_DONE) != 0) ! 581: tip = NULL; ! 582: else if (tip->i_isdir) ! 583: tip = cpydir(tip); ! 584: if (tip != NULL) { ! 585: dp2->d_ino = tip->i_mino; ! 586: strncpy(dp2->d_name, dp1->d_name, DIRSIZ); ! 587: nip->i_nent += 1; ! 588: dp2 += 1; ! 589: } ! 590: dp1 += 1; ! 591: } ! 592: if (nip->i_nent < ip->i_nent) { ! 593: i = sizeof(MINODE) + nip->i_nent * sizeof(struct direct); ! 594: if (realloc(nip, i) != nip) ! 595: fatal("realloc moved block"); ! 596: } ! 597: return (nip); ! 598: } ! 599: ! 600: void ! 601: keepers(ip) MINODE *ip; ! 602: { ! 603: int i; ! 604: MINODE *tip; ! 605: struct direct *dp; ! 606: ! 607: dp = ip->i_elem; ! 608: for (i = 0; i < ip->i_nent; i += 1) { ! 609: tip = fetchmi(dp->d_ino); ! 610: if (tip->i_isdir == 0) { ! 611: dp += 1; ! 612: continue; ! 613: } ! 614: if (tip->i_size < dsize - 4) ! 615: tip->i_flag |= I_CANFIT; ! 616: if (dused + tip->i_size < dsize) { ! 617: tip->i_flag |= I_KEEP; ! 618: dused += tip->i_size; ! 619: } ! 620: dp += 1; ! 621: } ! 622: dp = ip->i_elem; ! 623: for (i = 0; i < ip->i_nent; i += 1) { ! 624: tip = fetchmi(dp->d_ino); ! 625: if (tip->i_isdir != 0 ! 626: && (tip->i_flag & (I_CANFIT|I_KEEP)) == 0) ! 627: keepers(tip); ! 628: dp += 1; ! 629: } ! 630: } ! 631: ! 632: MINODE * ! 633: select(ip) MINODE *ip; ! 634: { ! 635: int i; ! 636: MINODE *uip, *lip, *tip; ! 637: struct direct *dp; ! 638: ! 639: uip = lip = NULL; ! 640: dp = ip->i_elem; ! 641: for (i = 0; i < ip->i_nent; i += 1) { ! 642: tip = fetchmi(dp->d_ino); ! 643: if (tip->i_flag & I_KEEP) { ! 644: dp += 1; ! 645: continue; ! 646: } ! 647: if (tip->i_flag & I_CANFIT) ! 648: return (tip); ! 649: if (tip->i_size == excess) ! 650: return (tip); ! 651: else if (tip->i_size > excess) { ! 652: if (uip == NULL || uip->i_size > tip->i_size) ! 653: uip = tip; ! 654: } else { ! 655: if (lip == NULL || lip->i_size < tip->i_size) ! 656: lip = tip; ! 657: } ! 658: dp += 1; ! 659: } ! 660: if (lip != NULL) ! 661: return (lip); ! 662: if (uip->i_isdir) ! 663: return (select(uip)); ! 664: return (uip); ! 665: } ! 666: ! 667: void ! 668: purge(rip) MINODE *rip; ! 669: { ! 670: int i; ! 671: MINODE *tip; ! 672: struct direct *dp1, *dp2; ! 673: ! 674: assert(rip->i_isdir); ! 675: #if I8086 ! 676: assert((char *)&dp2 > edata + 16); ! 677: #endif ! 678: dp1 = dp2 = rip->i_elem; ! 679: for (i = 0; i < rip->i_nent; i += 1) { ! 680: tip = fetchmi(dp1->d_ino); ! 681: if (tip->i_isdir) { ! 682: purge(tip); ! 683: if ((tip->i_flag & I_PURGE) && tip->i_nent == 0) { ! 684: dp1->d_ino = 0; ! 685: freemi(tip->i_mino); ! 686: } ! 687: } else if (tip->i_flag & I_PURGE) ! 688: dp1->d_ino = 0; ! 689: if (dp1->d_ino != 0) { ! 690: if (dp1 != dp2) ! 691: *dp2 = *dp1; ! 692: dp2 += 1; ! 693: } ! 694: dp1 += 1; ! 695: } ! 696: rip->i_nent = dp2 - rip->i_elem; ! 697: } ! 698: ! 699: void ! 700: donedir(ip) ! 701: MINODE *ip; ! 702: { ! 703: int i; ! 704: MINODE *tip; ! 705: struct direct *dp; ! 706: ! 707: ip->i_link1->i_flag |= I_DONE1; ! 708: dp = ip->i_elem; ! 709: for (i = 0; i < ip->i_nent; i += 1) { ! 710: tip = fetchmi(dp->d_ino); ! 711: if (tip->i_isdir) ! 712: donedir(tip); ! 713: else ! 714: tip->i_flag |= I_DONE|I_DONE1; ! 715: dp += 1; ! 716: } ! 717: } ! 718: ! 719: void ! 720: markdir(ip) MINODE *ip; ! 721: { ! 722: int i; ! 723: MINODE *tip; ! 724: struct direct *dp; ! 725: int flag; ! 726: ! 727: if (ip->i_flag & I_DONE) ! 728: return; ! 729: dp = ip->i_elem; ! 730: flag = I_DONE; ! 731: for (i = 0; i < ip->i_nent; i += 1) { ! 732: tip = fetchmi(dp->d_ino); ! 733: if (tip->i_isdir) ! 734: markdir(tip); ! 735: flag &= tip->i_flag; ! 736: dp += 1; ! 737: } ! 738: if ((flag & I_DONE) != 0 && (ip->i_flag & I_DONE1) != 0) ! 739: ip->i_flag |= I_DONE; ! 740: } ! 741: ! 742: MINODE *ihash1[IHASH]; /* dev x ino hash */ ! 743: MINODE *ihash2[IHASH]; /* mino hash */ ! 744: int minumber = 1; ! 745: ! 746: /* ! 747: ** Return the mino in the hash table ihash1 corresponding to ! 748: ** the statbuf. If not found, enter it and return the resulting ! 749: ** entry. ! 750: */ ! 751: int ! 752: entermi() ! 753: { ! 754: MINODE *ip, **ipp; ! 755: int nent; ! 756: ! 757: ipp = &ihash1[sbuf.st_ino % IHASH]; ! 758: while ((ip = *ipp) != NULL) { ! 759: if (ip->i_ino == sbuf.st_ino ! 760: && ip->i_dev == sbuf.st_dev) ! 761: return (ip->i_mino); ! 762: ipp = &ip->i_link1; ! 763: } ! 764: nent = 0; ! 765: if ((sbuf.st_mode&S_IFMT) == S_IFDIR) ! 766: nent = sbuf.st_size / sizeof(struct direct); ! 767: else if (sbuf.st_mtime < tbuf.st_mtime) ! 768: return 0; ! 769: else if (blkuse(sbuf.st_size) > dsize-5) { ! 770: fprintf(stderr, "unmkfs: file %s too large - omitted\n", fname); ! 771: return 0; ! 772: } ! 773: *ipp = ip = myalloc(sizeof(MINODE) + nent * sizeof(struct direct)); ! 774: ip->i_dev = sbuf.st_dev; ! 775: ip->i_ino = sbuf.st_ino; ! 776: ip->i_mode = sbuf.st_mode; ! 777: ip->i_nlink = sbuf.st_nlink; ! 778: ip->i_uid = sbuf.st_uid; ! 779: ip->i_gid = sbuf.st_gid; ! 780: ip->i_rdev = sbuf.st_rdev; ! 781: ip->i_mtime = sbuf.st_mtime; ! 782: ip->i_blks = blkuse(sbuf.st_size); ! 783: ip->i_inos = 1; ! 784: ip->i_size = ip->i_blks; ! 785: ip->i_nent = nent; ! 786: ip->i_mino = minumber++; ! 787: ip->i_isdir = (nent != 0); ! 788: ipp = &ihash2[ip->i_mino % IHASH]; ! 789: ip->i_link2 = *ipp; ! 790: *ipp = ip; ! 791: return (ip->i_mino); ! 792: } ! 793: ! 794: int ! 795: duplmi(ip) MINODE *ip; ! 796: { ! 797: MINODE *nip, **ipp; ! 798: ! 799: nip = myalloc(sizeof(MINODE) + ip->i_nent * sizeof(struct direct)); ! 800: nip->i_dev = ip->i_dev; ! 801: nip->i_ino = ip->i_ino; ! 802: nip->i_mode = ip->i_mode; ! 803: nip->i_nlink = ip->i_nlink; ! 804: nip->i_uid = ip->i_uid; ! 805: nip->i_gid = ip->i_gid; ! 806: nip->i_rdev = ip->i_rdev; ! 807: nip->i_blks = ip->i_blks; ! 808: nip->i_inos = ip->i_inos; ! 809: nip->i_size = ip->i_size; ! 810: nip->i_nent = ip->i_nent; ! 811: nip->i_mino = minumber++; ! 812: nip->i_isdir = ip->i_isdir; ! 813: ipp = &ihash2[nip->i_mino % IHASH]; ! 814: nip->i_link2 = *ipp; ! 815: *ipp = nip; ! 816: nip->i_link1 = ip; ! 817: return (nip->i_mino); ! 818: } ! 819: ! 820: /* ! 821: ** Find the entry i ihash2 corresponding to mino. ! 822: ** Die with message if not there. ! 823: */ ! 824: MINODE * ! 825: fetchmi(mino) int mino; ! 826: { ! 827: MINODE *ip, **ipp; ! 828: ! 829: ipp = &ihash2[mino % IHASH]; ! 830: while ((ip = *ipp) != NULL) ! 831: if (ip->i_mino == mino) ! 832: return (ip); ! 833: else ! 834: ipp = &ip->i_link2; ! 835: fatal("nonexistent internal inumber %d", mino); ! 836: } ! 837: ! 838: void ! 839: freemi(mino) int mino; ! 840: { ! 841: MINODE *ip, **ipp; ! 842: ! 843: ipp = &ihash2[mino % IHASH]; ! 844: while ((ip = *ipp) != NULL) ! 845: if (ip->i_mino == mino) { ! 846: *ipp = ip->i_link2; ! 847: free(ip); ! 848: return; ! 849: } else ! 850: ipp = &ip->i_link2; ! 851: fatal("nonexistent internal inumber %d", mino); ! 852: } ! 853: ! 854: /* ! 855: * A corrected disk usage computation ! 856: * for retrofit into /usr/src/cmd/du.c, /usr/src/cmd/ls.c/prsize(), ! 857: * and /usr/src/cmd/quot.c since they are all wrong. ! 858: * ! 859: * And this is not quite right either since it doesn't deal with sparse ! 860: * blocks. ! 861: */ ! 862: long ! 863: blkuse(nb) long nb; ! 864: { ! 865: #undef NBN ! 866: #define NBN 128L ! 867: #define nindir(x) (((x)+NBN-1)/NBN) ! 868: #define nblock(x) (((x)+BSIZE-1)/BSIZE) ! 869: #define min(x, y) ((x)<(y) ? (x) : (y)) ! 870: long bu, ndir, nidir, niidir; ! 871: ! 872: nb = nblock(nb); ! 873: ndir = min(nb, ND); ! 874: nb -= ndir; ! 875: bu = ndir; ! 876: if (nb) { ! 877: nidir = min(nb, NBN); ! 878: nb -= nidir; ! 879: bu += nidir + 1; ! 880: if (nb) { ! 881: niidir = min(nb, NBN*NBN); ! 882: nb -= niidir; ! 883: bu += niidir + 1 + nindir(niidir); ! 884: if (nb) ! 885: bu += nb + 1 + nindir(nindir(nb)) + nindir(nb); ! 886: } ! 887: } ! 888: return (bu); ! 889: } ! 890: ! 891: char * ! 892: string(cp) char *cp; ! 893: { ! 894: char *sp; ! 895: ! 896: sp = myalloc(strlen(cp)+1); ! 897: strcpy(sp, cp); ! 898: return (sp); ! 899: } ! 900: ! 901: char * ! 902: myalloc(nb) int nb; ! 903: { ! 904: char *p; ! 905: ! 906: if ((p = malloc(nb)) == NULL) ! 907: fatal("out of space"); ! 908: while (--nb >= 0) ! 909: p[nb] = 0; ! 910: return (p); ! 911: } ! 912: ! 913: void ! 914: usage() ! 915: { ! 916: fprintf(stderr, USAGE); ! 917: exit(1); ! 918: } ! 919: ! 920: void ! 921: fatal(args) char *args; ! 922: { ! 923: fprintf(stderr, "%s: %r\n", argv0, &args); ! 924: exit(1); ! 925: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.