|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1986, 1988, 1990 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: static char sccsid[] = "@(#)db_dump.c 4.30 (Berkeley) 6/1/90"; ! 22: #endif /* not lint */ ! 23: ! 24: #include <sys/param.h> ! 25: #include <sys/time.h> ! 26: #include <sys/stat.h> ! 27: #include <netinet/in.h> ! 28: #include <netdb.h> ! 29: #include <stdio.h> ! 30: #include <syslog.h> ! 31: #include <arpa/nameser.h> ! 32: #include "ns.h" ! 33: #include "db.h" ! 34: #include "pathnames.h" ! 35: ! 36: extern char *p_type(), *p_class(); ! 37: ! 38: #ifdef DUMPFILE ! 39: char *dumpfile = DUMPFILE; ! 40: #else ! 41: char *dumpfile = _PATH_DUMPFILE; ! 42: #endif ! 43: ! 44: extern char *cache_file; ! 45: ! 46: /* ! 47: * Dump current cache in a format similar to RFC 883. ! 48: * ! 49: * We try to be careful and determine whether the operation succeeded ! 50: * so that the new cache file can be installed. ! 51: */ ! 52: ! 53: #define DB_ROOT_TIMBUF 3600 ! 54: ! 55: doachkpt() ! 56: { ! 57: extern int errno; ! 58: FILE *fp; ! 59: char tmpcheckfile[256]; ! 60: ! 61: /* nowhere to checkpoint cache... */ ! 62: if (cache_file == NULL) { ! 63: #ifdef DEBUG ! 64: if (debug >= 3) ! 65: fprintf(ddt,"doachkpt(to where?)\n"); ! 66: #endif ! 67: return; ! 68: } ! 69: ! 70: #ifdef DEBUG ! 71: if (debug >= 3) ! 72: fprintf(ddt,"doachkpt()\n"); ! 73: #endif ! 74: ! 75: (void) sprintf(tmpcheckfile, "%s.chk", cache_file); ! 76: if ((fp = fopen(tmpcheckfile, "w")) == NULL) { ! 77: #ifdef DEBUG ! 78: if (debug >= 3) ! 79: fprintf(ddt,"doachkpt(can't open %s for write)\n", tmpcheckfile); ! 80: #endif ! 81: return; ! 82: } ! 83: ! 84: (void) gettime(&tt); ! 85: fprintf(fp, "; Dumped at %s", ctime(&tt.tv_sec)); ! 86: fflush(fp); ! 87: if (ferror(fp)) { ! 88: #ifdef DEBUG ! 89: if (debug >= 3) ! 90: fprintf(ddt,"doachkpt(write to checkpoint file failed)\n"); ! 91: #endif ! 92: return; ! 93: } ! 94: ! 95: if (fcachetab != NULL) { ! 96: int n; ! 97: if ((n = scan_root(hashtab)) < MINROOTS) { ! 98: syslog(LOG_ERR, "%d root hints... (too low)", n); ! 99: fprintf(fp, "; ---- Root hint cache dump ----\n"); ! 100: (void) db_dump(fcachetab, fp, DB_Z_CACHE, ""); ! 101: } ! 102: } ! 103: ! 104: if (hashtab != NULL) { ! 105: fprintf(fp, "; ---- Cache dump ----\n"); ! 106: if (db_dump(hashtab, fp, DB_Z_CACHE, "") == NODBFILE) { ! 107: #ifdef DEBUG ! 108: if (debug >= 3) ! 109: fprintf(ddt,"doachkpt(checkpoint failed)\n"); ! 110: #endif ! 111: (void) fclose(fp); ! 112: return; ! 113: } ! 114: } ! 115: ! 116: (void) fsync(fileno(fp)); ! 117: if (fclose(fp) == EOF) { ! 118: #ifdef DEBUG ! 119: if (debug >= 3) ! 120: fprintf(ddt,"doachkpt(close failed)\n"); ! 121: #endif ! 122: return; ! 123: } ! 124: ! 125: if (rename(tmpcheckfile, cache_file)) { ! 126: #ifdef DEBUG ! 127: if (debug >= 3) ! 128: fprintf(ddt,"doachkpt(install %s to %s failed, %d)\n", ! 129: tmpcheckfile,cache_file, errno); ! 130: #endif ! 131: } ! 132: } ! 133: ! 134: /* ! 135: * What we do is scan the root hint cache to make sure there are at least ! 136: * MINROOTS root pointers with non-0 TTL's so that the checkpoint will not ! 137: * lose the root. Failing this, all pointers are written out w/ TTL ~0 ! 138: * (root pointers timed out and prime_cache() not done or failed). ! 139: */ ! 140: #define TIMBUF 300 ! 141: ! 142: int ! 143: scan_root(htp) ! 144: struct hashbuf *htp; ! 145: { ! 146: register struct databuf *dp; ! 147: register struct namebuf *np; ! 148: struct timeval soon; ! 149: int roots = 0; ! 150: ! 151: #ifdef DEBUG ! 152: if (debug) ! 153: fprintf(ddt,"scan_root(0x%x)\n", htp); ! 154: #endif ! 155: ! 156: /* metric by which we determine whether a root NS pointer is still */ ! 157: /* valid (will be written out if we do a dump). we also add some */ ! 158: /* time buffer for safety... */ ! 159: (void) gettime(&soon); ! 160: soon.tv_sec += TIMBUF; ! 161: ! 162: for (np = htp->h_tab[0]; np != NULL; np = np->n_next) { ! 163: if (np->n_dname[0] == '\0') { ! 164: dp = np->n_data; ! 165: while (dp != NULL) { ! 166: if (dp->d_type == T_NS && ! 167: dp->d_ttl > soon.tv_sec) { ! 168: roots++; ! 169: if (roots >= MINROOTS) ! 170: return (roots); ! 171: } ! 172: dp = dp->d_next; ! 173: } ! 174: } ! 175: } ! 176: return (roots); ! 177: } ! 178: ! 179: #ifdef notdef ! 180: mark_cache(htp, ttl) ! 181: struct hashbuf *htp; ! 182: int ttl; ! 183: { ! 184: register struct databuf *dp; ! 185: register struct namebuf *np; ! 186: struct namebuf **npp, **nppend; ! 187: struct timeval soon; ! 188: ! 189: #ifdef DEBUG ! 190: if (debug) ! 191: fprintf(ddt,"mark_cache()\n"); ! 192: #endif ! 193: ! 194: (void) gettime(&soon); ! 195: soon.tv_sec += TIMBUF; ! 196: ! 197: npp = htp->h_tab; ! 198: nppend = npp + htp->h_size; ! 199: while (npp < nppend) { ! 200: for (np = *npp++; np != NULL; np = np->n_next) { ! 201: if (np->n_data == NULL) ! 202: continue; ! 203: for (dp = np->n_data; dp != NULL; dp = dp->d_next) { ! 204: if (dp->d_ttl < soon.tv_sec) ! 205: dp->d_ttl = ttl; ! 206: } ! 207: } ! 208: } ! 209: ! 210: npp = htp->h_tab; ! 211: nppend = npp + htp->h_size; ! 212: while (npp < nppend) { ! 213: for (np = *npp++; np != NULL; np = np->n_next) { ! 214: if (np->n_hash == NULL) ! 215: continue; ! 216: mark_cache(np->n_hash, ttl); ! 217: } ! 218: } ! 219: } ! 220: #endif notdef ! 221: ! 222: /* ! 223: * Dump current data base in a format similar to RFC 883. ! 224: */ ! 225: ! 226: doadump() ! 227: { ! 228: FILE *fp; ! 229: ! 230: #ifdef DEBUG ! 231: if (debug >= 3) ! 232: fprintf(ddt,"doadump()\n"); ! 233: #endif ! 234: ! 235: if ((fp = fopen(dumpfile, "w")) == NULL) ! 236: return; ! 237: gettime(&tt); ! 238: fprintf(fp, "; Dumped at %s", ctime(&tt.tv_sec)); ! 239: fprintf(fp, "; --- Cache & Data ---\n"); ! 240: if (hashtab != NULL) ! 241: (void) db_dump(hashtab, fp, DB_Z_ALL, ""); ! 242: fprintf(fp, "; --- Hints ---\n"); ! 243: if (fcachetab != NULL) ! 244: (void) db_dump(fcachetab, fp, DB_Z_ALL, ""); ! 245: (void) fclose(fp); ! 246: } ! 247: ! 248: #ifdef ALLOW_UPDATES ! 249: /* Create a disk database to back up zones ! 250: */ ! 251: zonedump(zp) ! 252: register struct zoneinfo *zp; ! 253: { ! 254: FILE *fp; ! 255: char *fname; ! 256: struct hashbuf *htp; ! 257: char *op; ! 258: struct stat st; ! 259: ! 260: /* Only dump zone if there is a cache specified */ ! 261: if (zp->z_source && *(zp->z_source)) { ! 262: #ifdef DEBUG ! 263: if (debug) ! 264: fprintf(ddt, "zonedump(%s)\n", zp->z_source); ! 265: #endif ! 266: ! 267: if ((fp = fopen(zp->z_source, "w")) == NULL) ! 268: return; ! 269: if (op = index(zp->z_origin, '.')) ! 270: op++; ! 271: gettime(&tt); ! 272: htp = hashtab; ! 273: if (nlookup(zp->z_origin, &htp, &fname, 0) != NULL) { ! 274: db_dump(htp, fp, zp-zones, (op == NULL ? "" : op)); ! 275: #ifdef ALLOW_UPDATES ! 276: zp->hasChanged = 0; /* Checkpointed */ ! 277: #endif ALLOW_UPDATES ! 278: } ! 279: (void) fclose(fp); ! 280: if (stat(zp->z_source, &st) == 0) ! 281: zp->z_ftime = st.st_mtime; ! 282: } ! 283: #ifdef DEBUG ! 284: else if (debug) ! 285: fprintf(ddt, "zonedump: no zone to dump\n"); ! 286: #endif ! 287: } ! 288: #endif ! 289: ! 290: int ! 291: db_dump(htp, fp, zone, origin) ! 292: int zone; ! 293: struct hashbuf *htp; ! 294: FILE *fp; ! 295: char *origin; ! 296: { ! 297: register struct databuf *dp; ! 298: register struct namebuf *np; ! 299: struct namebuf **npp, **nppend; ! 300: char dname[MAXDNAME]; ! 301: u_long n; ! 302: u_long addr; ! 303: u_short i; ! 304: int j; ! 305: register u_char *cp; ! 306: u_char *end; ! 307: char *proto; ! 308: extern char *inet_ntoa(), *protocolname(), *servicename(); ! 309: int found_data, tab, printed_origin = 0; ! 310: ! 311: npp = htp->h_tab; ! 312: nppend = npp + htp->h_size; ! 313: while (npp < nppend) { ! 314: for (np = *npp++; np != NULL; np = np->n_next) { ! 315: if (np->n_data == NULL) ! 316: continue; ! 317: /* Blecch - can't tell if there is data here for the ! 318: * right zone, so can't print name yet ! 319: */ ! 320: found_data = 0; ! 321: /* we want a snapshot in time... */ ! 322: for (dp = np->n_data; dp != NULL; dp = dp->d_next) { ! 323: /* Is the data for this zone? */ ! 324: if (zone != DB_Z_ALL && dp->d_zone != zone) ! 325: continue; ! 326: if (dp->d_zone == DB_Z_CACHE && ! 327: dp->d_ttl <= tt.tv_sec && ! 328: (dp->d_flags & DB_F_HINT) == 0) ! 329: continue; ! 330: if (!printed_origin) { ! 331: fprintf(fp, "$ORIGIN %s.\n", origin); ! 332: printed_origin++; ! 333: } ! 334: tab = 0; ! 335: if (!found_data) { ! 336: if (np->n_dname[0] == 0) { ! 337: if (origin[0] == 0) ! 338: fprintf(fp, ".\t"); ! 339: else ! 340: fprintf(fp, ".%s.\t", origin); /* ??? */ ! 341: } else ! 342: fprintf(fp, "%s\t", np->n_dname); ! 343: if (strlen(np->n_dname) < 8) ! 344: tab = 1; ! 345: found_data++; ! 346: } else { ! 347: (void) putc('\t', fp); ! 348: tab = 1; ! 349: } ! 350: if (dp->d_zone == DB_Z_CACHE) { ! 351: if (dp->d_flags & DB_F_HINT && ! 352: (long)(dp->d_ttl - tt.tv_sec) < DB_ROOT_TIMBUF) ! 353: fprintf(fp, "%d\t", DB_ROOT_TIMBUF); ! 354: else ! 355: fprintf(fp, "%d\t", ! 356: (int)(dp->d_ttl - tt.tv_sec)); ! 357: } else if (dp->d_ttl != 0 && ! 358: dp->d_ttl != zones[dp->d_zone].z_minimum) ! 359: fprintf(fp, "%d\t", (int)dp->d_ttl); ! 360: else if (tab) ! 361: (void) putc('\t', fp); ! 362: fprintf(fp, "%s\t%s\t", p_class(dp->d_class), ! 363: p_type(dp->d_type)); ! 364: cp = (u_char *)dp->d_data; ! 365: /* ! 366: * Print type specific data ! 367: */ ! 368: switch (dp->d_type) { ! 369: case T_A: ! 370: switch (dp->d_class) { ! 371: case C_IN: ! 372: case C_HS: ! 373: GETLONG(n, cp); ! 374: n = htonl(n); ! 375: fprintf(fp, "%s", ! 376: inet_ntoa(*(struct in_addr *)&n)); ! 377: break; ! 378: } ! 379: if (dp->d_nstime) ! 380: fprintf(fp, "\t; %d", dp->d_nstime); ! 381: fprintf(fp, "\n"); ! 382: break; ! 383: case T_CNAME: ! 384: case T_MB: ! 385: case T_MG: ! 386: case T_MR: ! 387: case T_PTR: ! 388: if (cp[0] == '\0') ! 389: fprintf(fp, ".\n"); ! 390: else ! 391: fprintf(fp, "%s.\n", cp); ! 392: break; ! 393: ! 394: case T_NS: ! 395: cp = (u_char *)dp->d_data; ! 396: if (cp[0] == '\0') ! 397: fprintf(fp, ".\t"); ! 398: else ! 399: fprintf(fp, "%s.", cp); ! 400: if (dp->d_nstime) ! 401: fprintf(fp, "\t; %d???", dp->d_nstime); ! 402: fprintf(fp, "\n"); ! 403: break; ! 404: ! 405: case T_HINFO: ! 406: if (n = *cp++) { ! 407: fprintf(fp, "\"%.*s\"", (int)n, cp); ! 408: cp += n; ! 409: } else ! 410: fprintf(fp, "\"\""); ! 411: if (n = *cp++) ! 412: fprintf(fp, " \"%.*s\"", (int)n, cp); ! 413: else ! 414: fprintf(fp, " \"\""); ! 415: (void) putc('\n', fp); ! 416: break; ! 417: ! 418: case T_SOA: ! 419: fprintf(fp, "%s.", cp); ! 420: cp += strlen(cp) + 1; ! 421: fprintf(fp, " %s. (\n", cp); ! 422: cp += strlen(cp) + 1; ! 423: GETLONG(n, cp); ! 424: fprintf(fp, "\t\t%lu", n); ! 425: GETLONG(n, cp); ! 426: fprintf(fp, " %lu", n); ! 427: GETLONG(n, cp); ! 428: fprintf(fp, " %lu", n); ! 429: GETLONG(n, cp); ! 430: fprintf(fp, " %lu", n); ! 431: GETLONG(n, cp); ! 432: fprintf(fp, " %lu )\n", n); ! 433: break; ! 434: ! 435: case T_MX: ! 436: GETSHORT(n, cp); ! 437: fprintf(fp,"%lu", n); ! 438: fprintf(fp," %s.\n", cp); ! 439: break; ! 440: ! 441: case T_TXT: ! 442: end = (u_char *)dp->d_data + dp->d_size; ! 443: (void) putc('"', fp); ! 444: while (cp < end) { ! 445: if (n = *cp++) { ! 446: for (j = n ; j > 0 && cp < end ; j--) ! 447: if (*cp == '\n') { ! 448: (void) putc('\\', fp); ! 449: (void) putc(*cp++, fp); ! 450: } else ! 451: (void) putc(*cp++, fp); ! 452: } ! 453: } ! 454: (void) fputs("\"\n", fp); ! 455: break; ! 456: ! 457: case T_UINFO: ! 458: fprintf(fp, "\"%s\"\n", cp); ! 459: break; ! 460: ! 461: case T_UID: ! 462: case T_GID: ! 463: if (dp->d_size == sizeof(u_long)) { ! 464: GETLONG(n, cp); ! 465: fprintf(fp, "%lu\n", n); ! 466: } ! 467: break; ! 468: ! 469: case T_WKS: ! 470: GETLONG(addr, cp); ! 471: addr = htonl(addr); ! 472: fprintf(fp,"%s ", ! 473: inet_ntoa(*(struct in_addr *)&addr)); ! 474: proto = protocolname(*cp); ! 475: cp += sizeof(char); ! 476: fprintf(fp, "%s ", proto); ! 477: i = 0; ! 478: while(cp < (u_char *)dp->d_data + dp->d_size) { ! 479: j = *cp++; ! 480: do { ! 481: if (j & 0200) ! 482: fprintf(fp," %s", ! 483: servicename(i, proto)); ! 484: j <<= 1; ! 485: } while(++i & 07); ! 486: } ! 487: fprintf(fp,"\n"); ! 488: break; ! 489: ! 490: case T_MINFO: ! 491: fprintf(fp, "%s.", cp); ! 492: cp += strlen(cp) + 1; ! 493: fprintf(fp, " %s.\n", cp); ! 494: break; ! 495: #ifdef ALLOW_T_UNSPEC ! 496: case T_UNSPEC: ! 497: /* Dump binary data out in an ASCII-encoded ! 498: format */ ! 499: { ! 500: /* Allocate more than enough space: ! 501: * actually need 5/4 size + 20 or so ! 502: */ ! 503: int TmpSize = 2 * dp->d_size + 30; ! 504: char *TmpBuf = (char *) malloc(TmpSize); ! 505: if (TmpBuf == NULL) { ! 506: #ifdef DEBUG ! 507: if (debug) ! 508: fprintf(ddt, "Dump T_UNSPEC: malloc returned NULL\n"); ! 509: #endif DEBUG ! 510: syslog(LOG_ERR, "Dump T_UNSPEC: malloc: %m"); ! 511: } ! 512: if (btoa(cp, dp->d_size, TmpBuf, ! 513: TmpSize) == CONV_OVERFLOW) { ! 514: #ifdef DEBUG ! 515: if (debug) ! 516: fprintf(ddt, "Dump T_UNSPEC: Output buffer overflow\n"); ! 517: #endif DEBUG ! 518: syslog(LOG_ERR, "Dump T_UNSPEC: Output buffer overflow\n"); ! 519: } else ! 520: fprintf(fp, "%s\n", TmpBuf); ! 521: } ! 522: break; ! 523: #endif ALLOW_T_UNSPEC ! 524: default: ! 525: fprintf(fp, "???\n"); ! 526: } ! 527: } ! 528: } ! 529: } ! 530: if (ferror(fp)) ! 531: return(NODBFILE); ! 532: ! 533: npp = htp->h_tab; ! 534: nppend = npp + htp->h_size; ! 535: while (npp < nppend) { ! 536: for (np = *npp++; np != NULL; np = np->n_next) { ! 537: if (np->n_hash == NULL) ! 538: continue; ! 539: getname(np, dname, sizeof(dname)); ! 540: if (db_dump(np->n_hash, fp, zone, dname) == NODBFILE) ! 541: return(NODBFILE); ! 542: } ! 543: } ! 544: return(OK); ! 545: } ! 546: ! 547: #ifdef ALLOW_T_UNSPEC ! 548: /* ! 549: * Subroutines to convert between 8 bit binary bytes and printable ASCII. ! 550: * Computes the number of bytes, and three kinds of simple checksums. ! 551: * Incoming bytes are collected into 32-bit words, then printed in base 85: ! 552: * exp(85,5) > exp(2,32) ! 553: * The ASCII characters used are between '!' and 'u'; ! 554: * 'z' encodes 32-bit zero; 'x' is used to mark the end of encoded data. ! 555: * ! 556: * Originally by Paul Rutter (philabs!per) and Joe Orost (petsd!joe) for ! 557: * the atob/btoa programs, released with the compress program, in mod.sources. ! 558: * Modified by Mike Schwartz 8/19/86 for use in BIND. ! 559: */ ! 560: ! 561: /* Make sure global variable names are unique */ ! 562: #define Ceor T_UNSPEC_Ceor ! 563: #define Csum T_UNSPEC_Csum ! 564: #define Crot T_UNSPEC_Crot ! 565: #define word T_UNSPEC_word ! 566: #define bcount T_UNSPEC_bcount ! 567: ! 568: static long int Ceor, Csum, Crot, word, bcount; ! 569: ! 570: #define EN(c) ((int) ((c) + '!')) ! 571: #define DE(c) ((c) - '!') ! 572: #define AddToBuf(bufp, c) **bufp = c; (*bufp)++; ! 573: #define streq(s0, s1) strcmp(s0, s1) == 0 ! 574: #define times85(x) ((((((x<<2)+x)<<2)+x)<<2)+x) ! 575: ! 576: ! 577: /* Decode ASCII-encoded byte c into binary representation and ! 578: * place into *bufp, advancing bufp ! 579: */ ! 580: static int ! 581: byte_atob(c, bufp) ! 582: register c; ! 583: char **bufp; ! 584: { ! 585: if (c == 'z') { ! 586: if (bcount != 0) ! 587: return(CONV_BADFMT); ! 588: else { ! 589: putbyte(0, bufp); ! 590: putbyte(0, bufp); ! 591: putbyte(0, bufp); ! 592: putbyte(0, bufp); ! 593: } ! 594: } else if ((c >= '!') && (c < ('!' + 85))) { ! 595: if (bcount == 0) { ! 596: word = DE(c); ! 597: ++bcount; ! 598: } else if (bcount < 4) { ! 599: word = times85(word); ! 600: word += DE(c); ! 601: ++bcount; ! 602: } else { ! 603: word = times85(word) + DE(c); ! 604: putbyte((int)((word >> 24) & 255), bufp); ! 605: putbyte((int)((word >> 16) & 255), bufp); ! 606: putbyte((int)((word >> 8) & 255), bufp); ! 607: putbyte((int)(word & 255), bufp); ! 608: word = 0; ! 609: bcount = 0; ! 610: } ! 611: } else ! 612: return(CONV_BADFMT); ! 613: return(CONV_SUCCESS); ! 614: } ! 615: ! 616: /* Compute checksum info and place c into *bufp, advancing bufp */ ! 617: static ! 618: putbyte(c, bufp) ! 619: register c; ! 620: char **bufp; ! 621: { ! 622: Ceor ^= c; ! 623: Csum += c; ! 624: Csum += 1; ! 625: if ((Crot & 0x80000000)) { ! 626: Crot <<= 1; ! 627: Crot += 1; ! 628: } else { ! 629: Crot <<= 1; ! 630: } ! 631: Crot += c; ! 632: AddToBuf(bufp, c); ! 633: } ! 634: ! 635: /* Read the ASCII-encoded data from inbuf, of length inbuflen, and convert ! 636: it into T_UNSPEC (binary data) in outbuf, not to exceed outbuflen bytes; ! 637: outbuflen must be divisible by 4. (Note: this is because outbuf is filled ! 638: in 4 bytes at a time. If the actual data doesn't end on an even 4-byte ! 639: boundary, there will be no problem...it will be padded with 0 bytes, and ! 640: numbytes will indicate the correct number of bytes. The main point is ! 641: that since the buffer is filled in 4 bytes at a time, even if there is ! 642: not a full 4 bytes of data at the end, there has to be room to 0-pad the ! 643: data, so the buffer must be of size divisible by 4). Place the number of ! 644: output bytes in numbytes, and return a failure/success status */ ! 645: int ! 646: atob(inbuf, inbuflen, outbuf, outbuflen, numbytes) ! 647: char *inbuf; ! 648: int inbuflen; ! 649: char *outbuf; ! 650: int outbuflen; ! 651: int *numbytes; ! 652: { ! 653: int inc, nb; ! 654: long int oeor, osum, orot; ! 655: char *inp, *outp = outbuf, *endoutp = &outbuf[outbuflen]; ! 656: ! 657: if ( (outbuflen % 4) != 0) ! 658: return(CONV_BADBUFLEN); ! 659: Ceor = Csum = Crot = word = bcount = 0; ! 660: for (inp = inbuf, inc = 0; inc < inbuflen; inp++, inc++) { ! 661: if (outp > endoutp) ! 662: return(CONV_OVERFLOW); ! 663: if (*inp == 'x') { ! 664: inp +=2; ! 665: break; ! 666: } else { ! 667: if (byte_atob(*inp, &outp) == CONV_BADFMT) ! 668: return(CONV_BADFMT); ! 669: } ! 670: } ! 671: ! 672: /* Get byte count and checksum information from end of buffer */ ! 673: if(sscanf(inp, "%ld %lx %lx %lx", numbytes, &oeor, &osum, &orot) != 4) ! 674: return(CONV_BADFMT); ! 675: if ((oeor != Ceor) || (osum != Csum) || (orot != Crot)) ! 676: return(CONV_BADCKSUM); ! 677: return(CONV_SUCCESS); ! 678: } ! 679: ! 680: /* Encode binary byte c into ASCII representation and place into *bufp, ! 681: advancing bufp */ ! 682: static ! 683: byte_btoa(c, bufp) ! 684: register c; ! 685: char **bufp; ! 686: { ! 687: Ceor ^= c; ! 688: Csum += c; ! 689: Csum += 1; ! 690: if ((Crot & 0x80000000)) { ! 691: Crot <<= 1; ! 692: Crot += 1; ! 693: } else { ! 694: Crot <<= 1; ! 695: } ! 696: Crot += c; ! 697: ! 698: word <<= 8; ! 699: word |= c; ! 700: if (bcount == 3) { ! 701: if (word == 0) { ! 702: AddToBuf(bufp, 'z'); ! 703: } else { ! 704: register int tmp = 0; ! 705: register long int tmpword = word; ! 706: ! 707: if (tmpword < 0) { ! 708: /* Because some don't support unsigned long */ ! 709: tmp = 32; ! 710: tmpword -= (long)(85 * 85 * 85 * 85 * 32); ! 711: } ! 712: if (tmpword < 0) { ! 713: tmp = 64; ! 714: tmpword -= (long)(85 * 85 * 85 * 85 * 32); ! 715: } ! 716: AddToBuf(bufp, ! 717: EN((tmpword / (long)(85 * 85 * 85 * 85)) + tmp)); ! 718: tmpword %= (long)(85 * 85 * 85 * 85); ! 719: AddToBuf(bufp, EN(tmpword / (85 * 85 * 85))); ! 720: tmpword %= (85 * 85 * 85); ! 721: AddToBuf(bufp, EN(tmpword / (85 * 85))); ! 722: tmpword %= (85 * 85); ! 723: AddToBuf(bufp, EN(tmpword / 85)); ! 724: tmpword %= 85; ! 725: AddToBuf(bufp, EN(tmpword)); ! 726: } ! 727: bcount = 0; ! 728: } else { ! 729: bcount += 1; ! 730: } ! 731: } ! 732: ! 733: ! 734: /* ! 735: * Encode the binary data from inbuf, of length inbuflen, into a ! 736: * null-terminated ASCII representation in outbuf, not to exceed outbuflen ! 737: * bytes. Return success/failure status ! 738: */ ! 739: int ! 740: btoa(inbuf, inbuflen, outbuf, outbuflen) ! 741: char *inbuf; ! 742: int inbuflen; ! 743: char *outbuf; ! 744: int outbuflen; ! 745: { ! 746: long int inc, nb; ! 747: long int oeor, osum, orot; ! 748: char *inp, *outp = outbuf, *endoutp = &outbuf[outbuflen -1]; ! 749: ! 750: Ceor = Csum = Crot = word = bcount = 0; ! 751: for (inp = inbuf, inc = 0; inc < inbuflen; inp++, inc++) { ! 752: byte_btoa((unsigned char) (*inp), &outp); ! 753: if (outp >= endoutp) ! 754: return(CONV_OVERFLOW); ! 755: } ! 756: while (bcount != 0) { ! 757: byte_btoa(0, &outp); ! 758: if (outp >= endoutp) ! 759: return(CONV_OVERFLOW); ! 760: } ! 761: /* Put byte count and checksum information at end of buffer, delimited ! 762: by 'x' */ ! 763: (void) sprintf(outp, "x %ld %lx %lx %lx", inbuflen, Ceor, Csum, Crot); ! 764: if (&outp[strlen(outp) - 1] >= endoutp) ! 765: return(CONV_OVERFLOW); ! 766: else ! 767: return(CONV_SUCCESS); ! 768: } ! 769: #endif ALLOW_T_UNSPEC
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.