|
|
1.1 ! root 1: /* ! 2: * Archive manager. ! 3: * Also manages libraries for the ! 4: * link editor, ! 5: * including ranlib header updates. ! 6: */ ! 7: #define RUNRSX 0 ! 8: #define FMTRSX 0 /* Achives in COHERENT format */ ! 9: ! 10: #include <stdio.h> ! 11: #include <ar.h> ! 12: #include <canon.h> ! 13: #include <sys/types.h> ! 14: #if !RUNRSX ! 15: #include <sys/stat.h> ! 16: #endif ! 17: ! 18: #define RO 0 ! 19: #define RW 1 ! 20: ! 21: #define NONE 0 ! 22: #define BEFORE 1 ! 23: #define AFTER 2 ! 24: ! 25: #define ALLOK 0 ! 26: #define NOTALL 1 ! 27: #define ERROR 2 ! 28: ! 29: #define aechk() { if(ferror(afp)) ioerr(anp); } ! 30: #define techk() { if(ferror(tfp)) ioerr(tnp); } ! 31: ! 32: char nwork[] = "No work"; ! 33: char found[] = "found"; ! 34: char copen[] = "%s: cannot open"; ! 35: char ccrea[] = "%s: cannot create"; ! 36: char creop[] = "%s: cannot reopen"; ! 37: ! 38: FILE *afp; ! 39: FILE *tfp; ! 40: FILE *rfp; ! 41: struct ar_hdr ahb; ! 42: int nname; ! 43: char **namep; ! 44: char *ctime(); ! 45: int usage(); ! 46: long fsize(); ! 47: long ftell(); ! 48: int cflag; ! 49: int kflag; ! 50: int lflag; ! 51: int sflag; ! 52: int uflag; ! 53: int vflag; ! 54: char *pnp; ! 55: char *anp; ! 56: char *tnp; ! 57: char rnp[] = HDRNAME; ! 58: int xstat = ALLOK; ! 59: int pos = NONE; ! 60: int (*ffp)() = usage; ! 61: ! 62: #if RUNRSX ! 63: struct header fhb; ! 64: time_t fmdate(); ! 65: time_t getmdate(); ! 66: #else ! 67: char state[] = "%s: stat error"; ! 68: #endif ! 69: ! 70: main(argc, argv) ! 71: char *argv[]; ! 72: { ! 73: register char *p; ! 74: register i; ! 75: int usage(), rfunc(); ! 76: ! 77: if (argc < 2) ! 78: usage(); ! 79: key(argv[1]); ! 80: nname = argc-2; ! 81: namep = &argv[2]; ! 82: for (i=2; i<argc; ++i) { ! 83: p = argv[i]; ! 84: if (pos!=NONE && pnp==NULL) { ! 85: pnp = p; ! 86: ++namep; ! 87: --nname; ! 88: } else if (anp == NULL) { ! 89: anp = p; ! 90: ++namep; ! 91: --nname; ! 92: } ! 93: } ! 94: if (anp == NULL) ! 95: usage(); ! 96: if (pos != NONE) { ! 97: if (pnp == NULL) ! 98: usage(); ! 99: if (ffp == usage) ! 100: ffp = rfunc; ! 101: } ! 102: (*ffp)(); ! 103: delexit(xstat); ! 104: } ! 105: ! 106: /* ! 107: * Decode key. ! 108: * Save function name in 'ffp'. ! 109: * Set 'c', 'l', 'k' and 'v' flags. ! 110: */ ! 111: key(p) ! 112: register char *p; ! 113: { ! 114: register c; ! 115: int dfunc(), rfunc(), qfunc(), tfunc(); ! 116: int mfunc(), xfunc(), pfunc(); ! 117: ! 118: while (c = *p++) { ! 119: switch (c) { ! 120: ! 121: case 'd': /* Delete */ ! 122: ffp = dfunc; ! 123: break; ! 124: ! 125: case 'r': /* Replace */ ! 126: ffp = rfunc; ! 127: break; ! 128: ! 129: case 'q': /* Quick append */ ! 130: ffp = qfunc; ! 131: break; ! 132: ! 133: case 't': /* Tabulate */ ! 134: ffp = tfunc; ! 135: break; ! 136: ! 137: case 'p': /* Print */ ! 138: ffp = pfunc; ! 139: break; ! 140: ! 141: case 'm': /* Move */ ! 142: ffp = mfunc; ! 143: break; ! 144: ! 145: case 'x': /* Extract */ ! 146: ffp = xfunc; ! 147: break; ! 148: ! 149: case 'c': /* no create message */ ! 150: ++cflag; ! 151: break; ! 152: ! 153: case 'k': /* keep dates */ ! 154: ++kflag; ! 155: break; ! 156: ! 157: case 'l': /* local temp file */ ! 158: ++lflag; ! 159: break; ! 160: ! 161: case 's': /* ranlib symbol table */ ! 162: ++sflag; ! 163: break; ! 164: ! 165: case 'u': /* update replace */ ! 166: ++uflag; ! 167: break; ! 168: ! 169: case 'v': /* verbose */ ! 170: ++vflag; ! 171: break; ! 172: ! 173: case 'a': /* after position or append */ ! 174: pos = AFTER; ! 175: break; ! 176: ! 177: case 'b': /* before position */ ! 178: case 'i': /* insert */ ! 179: pos = BEFORE; ! 180: break; ! 181: ! 182: default: ! 183: usage(); ! 184: } ! 185: } ! 186: } ! 187: ! 188: /* ! 189: * Replace. ! 190: * Eliminate dead stuff if 'u'. ! 191: * Copy up to insert point. ! 192: * Copy in new files. ! 193: * Copy the rest of the file. ! 194: * Copy back. ! 195: */ ! 196: rfunc() ! 197: { ! 198: register char *qfn; ! 199: register i, nef; ! 200: FILE *qfp; ! 201: ! 202: if (nname == 0) ! 203: diag(1, nwork); ! 204: aopen(RW); ! 205: ropen(); ! 206: if (uflag) { ! 207: update(); ! 208: fseek(afp, (long)sizeof(int), 0); ! 209: if (rfp != NULL) { ! 210: geth(); ! 211: if (eqh(rnp)) ! 212: fseek(afp, (long)ahb.ar_size, 1); ! 213: else ! 214: fseek(afp, (long)sizeof(int), 0); ! 215: } ! 216: } ! 217: topen(); ! 218: while (nef = geth()) { ! 219: if (pos==BEFORE && eqh(pnp)) { ! 220: fseek(afp, (long)-sizeof(struct ar_hdr), 1); ! 221: break; ! 222: } ! 223: if (pos == NONE) { ! 224: for (i=0; i<nname; ++i) { ! 225: if ((qfn=namep[i])!=NULL && eqh(qfn)) ! 226: break; ! 227: } ! 228: if (i != nname) { ! 229: fseek(afp, ahb.ar_size, 1); ! 230: namep[i] = NULL; ! 231: remove(i, qfn); ! 232: if ((qfp = fopen(qfn, "rb")) == NULL) ! 233: diag(1, copen, qfn); ! 234: makeh(qfn, qfp); ! 235: if (vflag) ! 236: printf("%s: in place replace.\n", qfn); ! 237: puth(); ! 238: ffcopy(tfp, tnp, qfp, qfn, fsize(qfp, qfn)); ! 239: fclose(qfp); ! 240: continue; ! 241: } ! 242: } ! 243: mmove(0); ! 244: if (pos==AFTER && eqh(pnp)) ! 245: break; ! 246: } ! 247: if (nef==0 && pos!=NONE) ! 248: diag(1, "%s: not in archive", pnp); ! 249: for (i=0; i<nname; ++i) { ! 250: if ((qfn=namep[i]) == NULL) ! 251: continue; ! 252: remove(i, qfn); ! 253: if ((qfp=fopen(qfn, "rb")) == NULL) ! 254: diag(1, copen, qfn); ! 255: makeh(qfn, qfp); ! 256: if (vflag) ! 257: printf("%s: replaced.\n", qfn); ! 258: puth(); ! 259: ffcopy(tfp, tnp, qfp, qfn, fsize(qfp, qfn)); ! 260: fclose(qfp); ! 261: } ! 262: while (geth()) ! 263: mmove(0); ! 264: tacopy(); ! 265: } ! 266: ! 267: /* ! 268: * Handle the 'u' option. ! 269: * Read through the archive, comparing ! 270: * the dates in the headers to the last ! 271: * modification dates of the files in ! 272: * the command line. Make some files ! 273: * go away. ! 274: */ ! 275: update() ! 276: { ! 277: register char *p; ! 278: register i; ! 279: #if !RUNRSX ! 280: struct stat sb; ! 281: #endif ! 282: ! 283: while (geth()) { ! 284: for (i=0; i<nname; ++i) { ! 285: p = namep[i]; ! 286: if (p!=NULL && eqh(p)) { ! 287: #if RUNRSX ! 288: if (ahb.ar_date >= fmdate(p)) { ! 289: #else ! 290: if (stat(p, &sb) < 0) ! 291: diag(1, state, p); ! 292: if (ahb.ar_date >= sb.st_mtime) { ! 293: #endif ! 294: if (vflag) ! 295: printf("%s: no update.\n", p); ! 296: namep[i] = NULL; ! 297: remove(i, p); ! 298: } ! 299: } ! 300: } ! 301: fseek(afp, ahb.ar_size, 1); ! 302: } ! 303: for (i=0; i<nname && namep[i]==NULL; ++i) ! 304: ; ! 305: if (i >= nname) { ! 306: if (vflag) ! 307: fprintf(stderr, "%s.\n", nwork); ! 308: delexit(ALLOK); ! 309: } ! 310: } ! 311: ! 312: /* ! 313: * Move. ! 314: * Copy stuff before insert. ! 315: * Copy moved stuff. ! 316: * Copy remainder. ! 317: * Copy back to archive. ! 318: */ ! 319: mfunc() ! 320: { ! 321: register nef; ! 322: long s; ! 323: ! 324: aopen(RW); ! 325: ropen(); ! 326: topen(); ! 327: while (nef = geth()) { ! 328: if (pos==BEFORE && eqh(pnp)) ! 329: break; ! 330: mmove(0); ! 331: if (pos==AFTER && eqh(pnp)) ! 332: break; ! 333: } ! 334: if (nef==0 && pos!=NONE) ! 335: diag(1, "%s: not in archive", pnp); ! 336: s = ftell(afp); ! 337: if (pos == BEFORE) ! 338: s -= sizeof(struct ar_hdr); ! 339: fseek(afp, (long)sizeof(int), 0); ! 340: while (geth()) ! 341: mmove(1); ! 342: if (nef) { ! 343: fseek(afp, s, 0); ! 344: while (geth()) ! 345: mmove(0); ! 346: } ! 347: tacopy(); ! 348: } ! 349: ! 350: /* ! 351: * Conditional move to the ! 352: * temp file from the archive ! 353: * file. Used by move and replace ! 354: */ ! 355: mmove(f1) ! 356: register f1; ! 357: { ! 358: register f2, i; ! 359: register long size; ! 360: ! 361: f2 = 0; ! 362: for (i=0; i<nname; ++i) { ! 363: if (eqh(namep[i])) { ! 364: ++f2; ! 365: break; ! 366: } ! 367: } ! 368: if (f1 == f2) { ! 369: if (vflag) ! 370: amsg("copied"); ! 371: size = ahb.ar_size; ! 372: puth(); ! 373: ffcopy(tfp, tnp, afp, anp, size); ! 374: } else { ! 375: if (vflag) ! 376: amsg("skipped"); ! 377: fseek(afp, ahb.ar_size, 1); ! 378: } ! 379: } ! 380: ! 381: /* ! 382: * Print. ! 383: */ ! 384: pfunc() ! 385: { ! 386: aopen(RO); ! 387: while (geth()) { ! 388: if (nname==0 || match()) ! 389: pfile(); ! 390: else ! 391: fseek(afp, ahb.ar_size, 1); ! 392: } ! 393: if (nname != 0) ! 394: notdone(found); ! 395: } ! 396: ! 397: pfile() ! 398: { ! 399: #if FMTRSX ! 400: register char *rb; ! 401: register i; ! 402: long s; ! 403: int n; ! 404: ! 405: if (vflag) ! 406: amsg(NULL); ! 407: if ((rb = malloc(ahb.ar_ufat.f_rsiz)) == NULL) ! 408: diag(1, "Out of space"); ! 409: s = ahb.ar_size; ! 410: while (s != 0) { ! 411: if (ahb.ar_ufat.f_rtyp == R_FIX) ! 412: n = ahb.ar_ufat.f_rsiz; ! 413: else { ! 414: fread(&n, sizeof(int), 1, afp); ! 415: s -= sizeof(int); ! 416: } ! 417: fread(rb, sizeof(char), n, afp); ! 418: for (i=0; i<n; ++i) ! 419: putchar(rb[i]); ! 420: if ((ahb.ar_ufat.f_ratt&FD_CR) != 0) ! 421: putchar('\n'); ! 422: if ((n&01) != 0) { ! 423: ++n; ! 424: fseek(afp, (long)1, 1); ! 425: } ! 426: s -= n; ! 427: } ! 428: free(rb); ! 429: #else ! 430: if (vflag) ! 431: amsg(NULL); ! 432: ffcopy(stdout, "Stdout", afp, anp, ahb.ar_size); ! 433: #endif ! 434: } ! 435: ! 436: /* ! 437: * Delete. ! 438: * Copy archive to temp, deleting ! 439: * members along the way. If all of ! 440: * the files have been deleted then ! 441: * copy back. ! 442: */ ! 443: dfunc() ! 444: { ! 445: register long size; ! 446: ! 447: if (nname == 0) ! 448: diag(1, nwork); ! 449: aopen(RW); ! 450: ropen(); ! 451: topen(); ! 452: while (geth()) { ! 453: if (match()) { ! 454: if (vflag) ! 455: amsg("deleted"); ! 456: fseek(afp, ahb.ar_size, 1); ! 457: continue; ! 458: } ! 459: if (vflag) ! 460: amsg("copied"); ! 461: size = ahb.ar_size; ! 462: puth(); ! 463: ffcopy(tfp, tnp, afp, anp, size); ! 464: } ! 465: if (notdone("deleted")) ! 466: delexit(ERROR); ! 467: tacopy(); ! 468: } ! 469: ! 470: /* ! 471: * Quick insert. ! 472: * Copy archive to temp file. ! 473: * Tack new files onto the end. ! 474: * If no errors, copy back. ! 475: */ ! 476: qfunc() ! 477: { ! 478: register char *qfn; ! 479: register FILE *qfp; ! 480: register i; ! 481: ! 482: if (nname == 0) ! 483: diag(1, nwork); ! 484: aopen(RW); ! 485: if (geth() != 0 && eqh(rnp)) { ! 486: fseek(afp, (long)-sizeof(ahb), 1); ! 487: ahb.ar_date = 0; ! 488: aputh(); ! 489: } ! 490: fseek(afp, (long)0, 2); ! 491: for (i=0; i<nname; ++i) { ! 492: if ((qfn=namep[i]) == NULL) ! 493: continue; ! 494: remove(i, qfn); ! 495: if ((qfp=fopen(qfn, "rb")) == NULL) ! 496: diag(1, copen, qfn); ! 497: makeh(qfn, qfp); ! 498: if (vflag) ! 499: printf("%s: quick insert.\n", qfn); ! 500: aputh(); ! 501: ffcopy(afp, anp, qfp, qfn, fsize(qfp, qfn)); ! 502: fclose(qfp); ! 503: } ! 504: } ! 505: ! 506: /* ! 507: * Table. ! 508: * Read through archive. ! 509: * If good member print its name. ! 510: * If verbose, print extra stuff. ! 511: */ ! 512: tfunc() ! 513: { ! 514: register char *p; ! 515: register c, n; ! 516: ! 517: aopen(RO); ! 518: while (geth()) { ! 519: if (nname==0 || match()) { ! 520: n = 0; ! 521: p = ahb.ar_name; ! 522: while (n<DIRSIZ && (c=*p++)) { ! 523: putchar(c); ! 524: ++n; ! 525: } ! 526: if (vflag) { ! 527: while (n++ < DIRSIZ+1) ! 528: putchar(' '); ! 529: #if FMTRSX ! 530: printf("[%03o,%03o] ", ahb.ar_gid, ahb.ar_uid); ! 531: printf("%06o ", ahb.ar_mode); ! 532: #else ! 533: printf("%5d %5d ", ahb.ar_gid, ahb.ar_uid); ! 534: printf("%03o ", ahb.ar_mode); ! 535: #endif ! 536: printf("%10ld ", ahb.ar_size); ! 537: printf("%s", ctime(&ahb.ar_date)); ! 538: } else ! 539: putchar('\n'); ! 540: } ! 541: fseek(afp, ahb.ar_size, 1); ! 542: } ! 543: if (nname != 0) ! 544: notdone(found); ! 545: } ! 546: ! 547: /* ! 548: * Extract. ! 549: * Read through archive. ! 550: * Extract any files you find. ! 551: * At end, mutter about files ! 552: * that were not there. ! 553: */ ! 554: xfunc() ! 555: { ! 556: register char *p1, *p2; ! 557: register c; ! 558: char fnb[DIRSIZ+1]; ! 559: FILE *xfp; ! 560: ! 561: aopen(RO); ! 562: while (geth()) { ! 563: if (nname==0 || match()) { ! 564: p1 = ahb.ar_name; ! 565: p2 = fnb; ! 566: while (p1<&ahb.ar_name[DIRSIZ] && (c=*p1++)) ! 567: *p2++ = c; ! 568: *p2 = 0; ! 569: if ((xfp=fopen(fnb, "wb")) == NULL) { ! 570: diag(0, ccrea, fnb); ! 571: fseek(afp, ahb.ar_size, 1); ! 572: continue; ! 573: } ! 574: if (vflag) ! 575: amsg("extracting"); ! 576: ffcopy(xfp, fnb, afp, anp, ahb.ar_size); ! 577: #if RUNRSX && FMTRSX ! 578: fseek(xfp, (long)0, 0); ! 579: xfp->v_rtyp = ahb.ar_ufat.f_rtyp; ! 580: xfp->v_ratt = ahb.ar_ufat.f_ratt; ! 581: xfp->v_rsiz = ahb.ar_ufat.f_rsiz; ! 582: xfp->v_hibk = ahb.ar_ufat.f_hibk; ! 583: xfp->v_efbk = ahb.ar_ufat.f_efbk; ! 584: xfp->v_ffby = ahb.ar_ufat.f_ffby; ! 585: #endif ! 586: #if !RUNRSX && !FMTRSX ! 587: chmod(fnb, ahb.ar_mode); ! 588: #endif ! 589: fclose(xfp); ! 590: if (kflag) { ! 591: #if !RUNRSX && !FMTRSX ! 592: time_t times[2]; ! 593: time_t time(); ! 594: ! 595: time(times+0); ! 596: times[1] = ahb.ar_date; ! 597: if (utime(fnb, times) < 0) ! 598: diag(0, "Unable to set time for %s", ! 599: fnb); ! 600: #endif ! 601: } ! 602: } else ! 603: fseek(afp, ahb.ar_size, 1); ! 604: } ! 605: if (nname != 0) ! 606: notdone(found); ! 607: } ! 608: ! 609: /* ! 610: * Make an archive header. ! 611: * Put it in the external archive ! 612: * header buffer 'ahb'. The arg. ! 613: * 'fn' is the file name. The file ! 614: * is open on 'fp'. ! 615: */ ! 616: makeh(fn, fp) ! 617: char *fn; ! 618: FILE *fp; ! 619: { ! 620: register char *p1, *p2; ! 621: register c; ! 622: #if !RUNRSX ! 623: struct stat sb; ! 624: #endif ! 625: ! 626: for (p1=fn; *p1++; ) ! 627: ; ! 628: while (p1 > fn) { ! 629: c = p1[-1]; ! 630: #if RUNRSX ! 631: if (c==':' || c==']') ! 632: break; ! 633: #endif ! 634: #if COHERENT ! 635: if (c == '/') ! 636: break; ! 637: #endif ! 638: #if GEMDOS ! 639: if (c == '\\') ! 640: break; ! 641: #endif ! 642: --p1; ! 643: } ! 644: p2 = ahb.ar_name; ! 645: while (c = *p1++) { ! 646: if (p2 < &ahb.ar_name[DIRSIZ]) ! 647: *p2++ = c; ! 648: } ! 649: while (p2 < &ahb.ar_name[DIRSIZ]) ! 650: *p2++ = 0; ! 651: #if RUNRSX ! 652: if (ratt(fp, &fhb) == 0) ! 653: diag(1, "%s: ratt failed", fn); ! 654: ahb.ar_date = getmdate(&fhb); ! 655: ahb.ar_size = fsize(fp, fn); ! 656: #if FMTRSX ! 657: ahb.ar_uid = fhb.h_prog; ! 658: ahb.ar_gid = fhb.h_proj; ! 659: ahb.ar_mode = fhb.h_fpro; ! 660: ahb.ar_ufat.f_rtyp = fp->v_rtyp; ! 661: ahb.ar_ufat.f_ratt = fp->v_ratt; ! 662: ahb.ar_ufat.f_rsiz = fp->v_rsiz; ! 663: ahb.ar_ufat.f_hibk = fp->v_hibk; ! 664: ahb.ar_ufat.f_efbk = fp->v_efbk; ! 665: ahb.ar_ufat.f_ffby = fp->v_ffby; ! 666: #else ! 667: ahb.ar_uid = 0; ! 668: ahb.ar_gid = 0; ! 669: ahb.ar_mode = 0644; ! 670: #endif ! 671: #else ! 672: #if GEMDOS ! 673: if (stat(fn, &sb) < 0) ! 674: #else ! 675: if (fstat(fileno(fp), &sb) < 0) ! 676: #endif ! 677: diag(1, state, fn); ! 678: if (kflag) ! 679: ahb.ar_date = sb.st_mtime; ! 680: else ! 681: time(&ahb.ar_date); ! 682: ahb.ar_uid = sb.st_uid; ! 683: ahb.ar_gid = sb.st_gid; ! 684: ahb.ar_mode = sb.st_mode&0777; ! 685: ahb.ar_size = sb.st_size; ! 686: #endif ! 687: } ! 688: ! 689: /* ! 690: * Test if the member whose ! 691: * header is held in the archive ! 692: * header buffer is mentioned in ! 693: * the user's list of members. ! 694: * Return the number of matches. ! 695: * All matches are NULLed. ! 696: */ ! 697: match() ! 698: { ! 699: register char *p; ! 700: register i, n; ! 701: ! 702: n = 0; ! 703: for (i=0; i<nname; ++i) { ! 704: if ((p=namep[i]) == NULL) ! 705: continue; ! 706: if (eqh(p)) { ! 707: ++n; ! 708: namep[i] = NULL; ! 709: } ! 710: } ! 711: return (n); ! 712: } ! 713: ! 714: /* ! 715: * Remove all instances of name ! 716: * 'fn' from the list of names that ! 717: * is described by 'namep' and ! 718: * 'nname'. ! 719: * Start at index 'i+1'. ! 720: */ ! 721: remove(i, fn) ! 722: register i; ! 723: register char *fn; ! 724: { ! 725: register char *p; ! 726: ! 727: for (++i; i<nname; ++i) { ! 728: if ((p=namep[i]) == NULL) ! 729: continue; ! 730: if (strcmp(fn, p) == 0) ! 731: namep[i] = NULL; ! 732: } ! 733: } ! 734: ! 735: /* ! 736: * This routine digs through the ! 737: * list of names described by 'namep' ! 738: * and 'nname' looking for names that ! 739: * have not been NULLed out. If any ! 740: * are found it prints a title and ! 741: * the names. The number of names that ! 742: * were found is returned. ! 743: */ ! 744: notdone(s) ! 745: char *s; ! 746: { ! 747: register char *p; ! 748: register i, n; ! 749: ! 750: n = 0; ! 751: for (i=0; i<nname; ++i) { ! 752: p = namep[i]; ! 753: if (p != NULL) { ! 754: if (n++ == 0) ! 755: fprintf(stderr, "Not %s:\n", s); ! 756: fprintf(stderr, "%s\n", p); ! 757: } ! 758: } ! 759: return (n); ! 760: } ! 761: ! 762: /* ! 763: * File to file copy. ! 764: * With ranlib construction. ! 765: */ ! 766: ffcopy(tfp, tfn, ffp, ffn, s) ! 767: FILE *tfp, *ffp; ! 768: char *tfn, *ffn; ! 769: long s; ! 770: { ! 771: register n; ! 772: static char fb[BUFSIZ]; ! 773: ! 774: if (rfp != NULL) raddmod(tfp, ffp); ! 775: while (s != 0) { ! 776: n = (s>BUFSIZ) ? BUFSIZ : s; ! 777: if (fread (fb, sizeof(char), n, ffp) != n) ! 778: ioerr(ffn); ! 779: if (fwrite(fb, sizeof(char), n, tfp) != n) ! 780: ioerr(tfn); ! 781: s -= n; ! 782: } ! 783: } ! 784: ! 785: /* ! 786: * Get the next archive header ! 787: * into 'ahb'. Check for any I/O ! 788: * errors. Return true if a header ! 789: * was read and false on EOF. ! 790: */ ! 791: geth() ! 792: { ! 793: if (fread(&ahb, sizeof(ahb), 1, afp) != 1) { ! 794: aechk(); ! 795: return (0); ! 796: } ! 797: cantime(ahb.ar_date); ! 798: canshort(ahb.ar_gid); ! 799: canshort(ahb.ar_uid); ! 800: canshort(ahb.ar_mode); ! 801: cansize(ahb.ar_size); ! 802: return (1); ! 803: } ! 804: ! 805: /* ! 806: * Write the header in 'ahb' to ! 807: * the temp file. ! 808: */ ! 809: puth() ! 810: { ! 811: cantime(ahb.ar_date); ! 812: canshort(ahb.ar_gid); ! 813: canshort(ahb.ar_uid); ! 814: canshort(ahb.ar_mode); ! 815: cansize(ahb.ar_size); ! 816: fwrite(&ahb, sizeof(ahb), 1, tfp); ! 817: techk(); ! 818: } ! 819: ! 820: /* ! 821: * Write the header in 'ahb' to ! 822: * the archive file. from qfunc. ! 823: */ ! 824: aputh() ! 825: { ! 826: cantime(ahb.ar_date); ! 827: canshort(ahb.ar_gid); ! 828: canshort(ahb.ar_uid); ! 829: canshort(ahb.ar_mode); ! 830: cansize(ahb.ar_size); ! 831: fwrite(&ahb, sizeof(ahb), 1, afp); ! 832: aechk(); ! 833: } ! 834: ! 835: /* ! 836: * Compare a string to the name ! 837: * of the member in the archive header ! 838: * buffer. True return if same. ! 839: */ ! 840: eqh(p) ! 841: char *p; ! 842: { ! 843: register char *p1, *p2; ! 844: register c; ! 845: ! 846: if ((p1 = p) == NULL) ! 847: return (0); ! 848: while (*p1++) ! 849: ; ! 850: while (p1 > p) { ! 851: c = p1[-1]; ! 852: #if RUNRSX ! 853: if (c==':' || c==']') ! 854: break; ! 855: #endif ! 856: #if COHERENT ! 857: if (c == '/') ! 858: break; ! 859: #endif ! 860: #if GEMDOS ! 861: if (c == '\\') ! 862: break; ! 863: #endif ! 864: --p1; ! 865: } ! 866: p2 = ahb.ar_name; ! 867: c = DIRSIZ; ! 868: while (c && *p1 == *p2++) { ! 869: if (*p1++ == 0) ! 870: return (1); ! 871: --c; ! 872: } ! 873: if (c == 0) ! 874: return (1); ! 875: return (0); ! 876: } ! 877: ! 878: /* ! 879: * Open archive. ! 880: * The argument 'aam' is the ! 881: * access mode (RO or RW). ! 882: */ ! 883: aopen(aam) ! 884: { ! 885: int i; ! 886: ! 887: if ((afp=fopen(anp, "rb")) == NULL) { ! 888: if (aam == RO) ! 889: diag(1, copen, anp); ! 890: if ((afp=fopen(anp, "wb"))==NULL ! 891: || (afp=freopen(anp, "wrb", afp))==NULL) ! 892: diag(1, ccrea, anp); ! 893: if (cflag == 0) ! 894: printf("%s: new archive.\n", anp); ! 895: i = ARMAG; ! 896: canint(i); ! 897: fwrite(&i, sizeof(i), 1, afp); ! 898: aechk(); ! 899: return; ! 900: } ! 901: if (aam != RO) { ! 902: fclose(afp); ! 903: if ((afp=fopen(anp, "rwb"))==NULL) ! 904: diag(1, copen, anp); ! 905: } ! 906: fread(&i, sizeof(i), 1, afp); ! 907: aechk(); ! 908: canint(i); ! 909: if (i != ARMAG) ! 910: diag(1, "%s: not an archive", anp); ! 911: } ! 912: ! 913: /* ! 914: * Open tempfile. ! 915: * Stash the name in 'tnp' for ! 916: * the benefit of 'delexit'. ! 917: * Honour the 'l' option w.r.t. ! 918: * file placement. ! 919: */ ! 920: topen() ! 921: { ! 922: int i; ! 923: ! 924: #if COHERENT || GEMDOS ! 925: extern char *tempnam(); ! 926: tnp = tempnam((lflag ? "." : NULL), "v"); ! 927: #endif ! 928: #if RUNRSX ! 929: tnp = "ar.tmp"; ! 930: #endif ! 931: if ((tfp=fopen(tnp, "wb")) == NULL) ! 932: diag(1, ccrea, tnp); ! 933: i = ARMAG; ! 934: canint(i); ! 935: fwrite(&i, sizeof(i), 1, tfp); ! 936: techk(); ! 937: } ! 938: ! 939: /* ! 940: * Copy tempfile back to the ! 941: * archive. ! 942: */ ! 943: tacopy() ! 944: { ! 945: register FILE *xtp; ! 946: int i; ! 947: ! 948: fclose(tfp); ! 949: tfp = NULL; /* Scare off delexit */ ! 950: fclose(afp); ! 951: if ((xtp=fopen(tnp, "rb")) == NULL) ! 952: diag(1, creop, tnp); ! 953: if ((afp=fopen(anp, "wb")) == NULL) ! 954: diag(1, creop, anp); ! 955: if (vflag) ! 956: printf("%s: copy back.\n", anp); ! 957: if (fread(&i, sizeof(i), 1, xtp) != 1) ! 958: ioerr(tnp); ! 959: if (fwrite(&i, sizeof(i), 1, afp) != 1) ! 960: ioerr(anp); ! 961: if (rfp != NULL) rcopy(); ! 962: ffcopy(afp, anp, xtp, tnp, fsize(xtp, tnp)-sizeof(int)); ! 963: tfp = xtp; /* Delete */ ! 964: } ! 965: ! 966: /* ! 967: * Write diagnostic. ! 968: * The flag 'f' marks fatal errors. ! 969: */ ! 970: diag(f, a) ! 971: { ! 972: fprintf(stderr, "%r", &a); ! 973: fprintf(stderr, ".\n"); ! 974: if (f) ! 975: delexit(ERROR); ! 976: xstat = NOTALL; ! 977: } ! 978: ! 979: /* ! 980: * Print a message for a ! 981: * given archive member. The header ! 982: * is in the header buffer. ! 983: */ ! 984: amsg(s) ! 985: char *s; ! 986: { ! 987: register char *p; ! 988: register c; ! 989: ! 990: p = ahb.ar_name; ! 991: while (p<&ahb.ar_name[DIRSIZ] && (c=*p++)!=0) ! 992: putchar(c); ! 993: putchar(':'); ! 994: if (s != NULL) ! 995: printf(" %s.", s); ! 996: putchar('\n'); ! 997: } ! 998: ! 999: /* ! 1000: * Exit. ! 1001: * Delete the tempfile if ! 1002: * present. ! 1003: */ ! 1004: delexit(s) ! 1005: { ! 1006: #if RUNRSX ! 1007: if (tfp != NULL) ! 1008: fmkdl(tfp); ! 1009: #else ! 1010: if (tfp != NULL) ! 1011: unlink(tnp); ! 1012: #endif ! 1013: #ifdef DEBUG ! 1014: if (s) ! 1015: abort(); ! 1016: #endif ! 1017: exit(s); ! 1018: } ! 1019: ! 1020: /* ! 1021: * Mutter about an I/O error ! 1022: * on file 's'. ! 1023: */ ! 1024: ioerr(s) ! 1025: char *s; ! 1026: { ! 1027: diag(1, "%s: I/O error", s); ! 1028: } ! 1029: ! 1030: /* ! 1031: * Print usage message. ! 1032: */ ! 1033: usage() ! 1034: { ! 1035: fprintf(stderr, "Usage: ar options [posname] afile [name ...].\n"); ! 1036: delexit(ERROR); ! 1037: } ! 1038: ! 1039: /* ! 1040: * Compute the size of a file. ! 1041: * In bytes. ! 1042: * The file must not be seeked. ! 1043: */ ! 1044: long ! 1045: fsize(fp, fn) ! 1046: register FILE *fp; ! 1047: char *fn; ! 1048: { ! 1049: #if RUNRSX ! 1050: return (((fp->v_efbk-1)<<9) + fp->v_ffby); ! 1051: #else ! 1052: struct stat sb; ! 1053: ! 1054: #if GEMDOS ! 1055: if (stat(fn, &sb) < 0) ! 1056: #endif ! 1057: #if COHERENT ! 1058: if (fstat(fileno(fp), &sb) < 0) ! 1059: #endif ! 1060: diag(1, state, fn); ! 1061: return (sb.st_size); ! 1062: #endif ! 1063: } ! 1064: ! 1065: #if RUNRSX ! 1066: /* ! 1067: * The following routines simulate ! 1068: * some aspects of Coherent under the ! 1069: * dreaded RSX. ! 1070: */ ! 1071: #define DAY (24L*60L*60L) ! 1072: ! 1073: time_t ! 1074: fmdate(fn) ! 1075: char *fn; ! 1076: { ! 1077: register FILE *fp; ! 1078: register s; ! 1079: ! 1080: if ((fp=fopen(fn, "rb")) == NULL) ! 1081: diag(1, copen, fn); ! 1082: s = ratt(fp, &fhb); ! 1083: fclose(fp); ! 1084: if (s == 0) ! 1085: diag(1, "%s: ratt failed", fn); ! 1086: return (getmdate(&fhb)); ! 1087: } ! 1088: ! 1089: time_t ! 1090: getmdate(fhp) ! 1091: register struct header *fhp; ! 1092: { ! 1093: register i; ! 1094: time_t date; ! 1095: int rsxdate[8]; ! 1096: static char *mtab[] = { ! 1097: "JAN", "FEB", "MAR", "APR", "MAY", "JUN", ! 1098: "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" ! 1099: }; ! 1100: ! 1101: rsxdate[0] = (fhp->i_rvdt[5]-'0')*10+fhp->i_rvdt[6]-'0'; ! 1102: for (i=0; i<12; ++i) { ! 1103: if (cmp3(&fhp->i_rvdt[2], mtab[i])) { ! 1104: rsxdate[1] = i+1; ! 1105: break; ! 1106: } ! 1107: } ! 1108: rsxdate[2] = (fhp->i_rvdt[0]-'0')*10+fhp->i_rvdt[1]-'0'; ! 1109: rsxdate[3] = (fhp->i_rvti[0]-'0')*10+fhp->i_rvti[1]-'0'; ! 1110: rsxdate[4] = (fhp->i_rvti[2]-'0')*10+fhp->i_rvti[3]-'0'; ! 1111: rsxdate[5] = (fhp->i_rvti[4]-'0')*10+fhp->i_rvti[5]-'0'; ! 1112: cvttime(&date, rsxdate); ! 1113: return (date); ! 1114: } ! 1115: ! 1116: cmp3(p1, p2) ! 1117: register char *p1, *p2; ! 1118: { ! 1119: if (*p1++==*p2++ && *p1++==*p2++ && *p1++==*p2++) ! 1120: return (1); ! 1121: return (0); ! 1122: } ! 1123: ! 1124: /* ! 1125: * Convert rsx date to Coherent ! 1126: * format. This routine assumes that ! 1127: * the timezone is CST. ! 1128: * Courtesy of Tom Duff. ! 1129: */ ! 1130: cvttime(date, rsxdate) ! 1131: register long *date; ! 1132: int rsxdate[8]; ! 1133: { ! 1134: register i; ! 1135: ! 1136: *date = 0; ! 1137: for (i=70; i!=rsxdate[0]; i++) { ! 1138: if (i%4==0) ! 1139: *date += 366L*DAY; else ! 1140: *date += 365L*DAY; ! 1141: } ! 1142: for (i=1; i!=rsxdate[1]; i++) ! 1143: switch (i){ ! 1144: case 9: /* Sep */ ! 1145: case 4: /* Apr */ ! 1146: case 6: /* Jun */ ! 1147: case 11: /* Nov */ ! 1148: *date += 30L*DAY; ! 1149: break; ! 1150: ! 1151: case 2: /* Feb */ ! 1152: if (rsxdate[0]%4 == 0) ! 1153: *date += 29L*DAY; else ! 1154: *date += 28L*DAY; ! 1155: break; ! 1156: ! 1157: default: ! 1158: *date += 31L*DAY; ! 1159: } ! 1160: *date += (rsxdate[2]-1)*DAY; ! 1161: *date += rsxdate[3]*60L*60L; ! 1162: *date += rsxdate[4]*60L; ! 1163: *date += rsxdate[5]; ! 1164: *date += 6L*60L*60L; /* adjust cst to gmt */ ! 1165: } ! 1166: #endif ! 1167: ! 1168: /* ! 1169: * Ranlib stuff. ! 1170: * If the current archive has HDRNAME as first module, ! 1171: * then skip it and open rfp for creation of new ranlib header, ! 1172: * otherwise backup and make a vanilla archive. ! 1173: * Unless sflag was set as an option, ! 1174: * in which case make rfp anyway. ! 1175: * Unless HDRNAME matches the name list and ffp == dfunc, ! 1176: * in which case make rfp only if sflag was set. ! 1177: */ ! 1178: ropen() ! 1179: { ! 1180: extern int dfunc(); ! 1181: ! 1182: if (geth() != 0) { /* Must not be end of file */ ! 1183: if (eqh(rnp)) { ! 1184: fseek(afp, (long)ahb.ar_size, 1); ! 1185: if (ffp == dfunc && match()) { ! 1186: if (vflag) ! 1187: amsg("deleted"); ! 1188: } else ! 1189: ++sflag; ! 1190: } else { ! 1191: fseek(afp, (long)-sizeof(ahb), 1); ! 1192: if (sflag && ffp == dfunc) { ! 1193: strcpy(ahb.ar_name, rnp); ! 1194: match(); ! 1195: } ! 1196: } ! 1197: } ! 1198: if (sflag && (rfp = fopen(rnp, "wb")) == NULL) ! 1199: diag(1, ccrea, rnp); ! 1200: } ! 1201: ! 1202: /* ! 1203: * Add the symbols in mfp to the ranlib header, ! 1204: * and seek mfp back to where it began. ! 1205: * The postion of this module in the archive ! 1206: * is -sizeof(arhdr) from current position of afp. ! 1207: */ ! 1208: struct ldheader ldh; ! 1209: struct ldsym lds; ! 1210: struct ar_sym ars; ! 1211: ! 1212: xwrite() ! 1213: { ! 1214: if (fwrite(lds.ls_id, sizeof(lds.ls_id), 1, rfp) != 1 ! 1215: || fwrite(&ars.ar_off, sizeof(ars.ar_off), 1, rfp) != 1) ! 1216: ioerr(rnp); ! 1217: } ! 1218: ! 1219: xread(fp) register FILE *fp; ! 1220: { ! 1221: register int r; ! 1222: union { long l; unsigned u[2]; } u; ! 1223: ! 1224: if ((ldh.l_flag & LF_32) == 0) { ! 1225: r = fread(&lds, sizeof(lds)-sizeof(short), 1, fp); ! 1226: u.l = lds.ls_addr; ! 1227: canshort(u.u[0]); ! 1228: lds.ls_addr = u.u[0]; ! 1229: } else { ! 1230: r = fread(&lds, sizeof(lds), 1, fp); ! 1231: canlong(lds.ls_addr); ! 1232: } ! 1233: canshort(lds.ls_type); ! 1234: return (r); ! 1235: } ! 1236: ! 1237: raddmod(afp, mfp) FILE *afp, *mfp; ! 1238: { ! 1239: fsize_t off, offset; ! 1240: int seg, nsym; ! 1241: ! 1242: ars.ar_off = ftell(afp) - sizeof(ahb) - sizeof(int); ! 1243: cansize(ars.ar_off); ! 1244: off = ftell(mfp); ! 1245: ldh.l_magic = 0; /* in case fread fails */ ! 1246: if (fread(&ldh, sizeof ldh, 1, mfp) != 1) ! 1247: goto done; ! 1248: canshort(ldh.l_magic); ! 1249: if (ldh.l_magic != L_MAGIC) ! 1250: goto done; ! 1251: canshort(ldh.l_flag); ! 1252: if ((ldh.l_flag & LF_32) == 0) ! 1253: ldh.l_tbase = sizeof(ldh) - 2*sizeof(short); ! 1254: else ! 1255: canshort(ldh.l_tbase); ! 1256: offset = ldh.l_tbase - (fsize_t)sizeof(ldh); ! 1257: for (seg=0; seg<L_SYM; seg++) { ! 1258: if (seg==L_BSSI || seg==L_BSSD) ! 1259: continue; ! 1260: cansize(ldh.l_ssize[seg]); ! 1261: offset += ldh.l_ssize[seg]; ! 1262: } ! 1263: fseek(mfp, offset, 1); ! 1264: cansize(ldh.l_ssize[L_SYM]); ! 1265: if ((ldh.l_flag & LF_32) == 0) ! 1266: nsym = ldh.l_ssize[L_SYM] ! 1267: / (sizeof(struct ldsym) - sizeof(short)); ! 1268: else ! 1269: nsym = ldh.l_ssize[L_SYM]/sizeof(struct ldsym); ! 1270: while (nsym--) { ! 1271: if (xread(mfp) == 0) ! 1272: diag(1, "truncated module %.*s", DIRSIZ, ahb.ar_name); ! 1273: if ((lds.ls_type&L_GLOBAL) == 0) ! 1274: continue; ! 1275: if ((lds.ls_type&LR_SEG) != L_REF) ! 1276: xwrite(); ! 1277: } ! 1278: done: ! 1279: fseek(mfp, off, 0); /* back to beginning of module */ ! 1280: } ! 1281: ! 1282: /* ! 1283: * Copy the ranlib header to the output archive ! 1284: * close and null the ranlib file pointer. ! 1285: */ ! 1286: rcopy() ! 1287: { ! 1288: register FILE *fp; ! 1289: fclose(rfp); ! 1290: rfp = NULL; ! 1291: if ((fp = fopen(rnp, "rb")) == NULL) ! 1292: diag(1, creop, rnp); ! 1293: makeh(rnp, fp); ! 1294: time(&ahb.ar_date); ! 1295: ahb.ar_date += (long)(10*365+3)*24*60*60; ! 1296: tfp = afp; ! 1297: puth(); ! 1298: tfp = NULL; ! 1299: ffcopy(afp, anp, fp, rnp, fsize(fp, rnp)); ! 1300: fclose(fp); ! 1301: unlink(rnp); ! 1302: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.