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