home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / NETWORK / ISP / bind.4.8.3.lzh / BIND483 / NAMED / db_dump.c < prev    next >
Text File  |  1993-08-24  |  19KB  |  770 lines

  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
  770.