"Fossies" - the Fresh Open Source Software Archive

Member "schily-2021-09-18/tartest/tartest.c" (20 Aug 2021, 15540 Bytes) of package /linux/privat/schily-2021-09-18.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "tartest.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes reports: 2021-08-14_vs_2021-09-18 or 2021-07-29_vs_2021-09-18.

    1 /* @(#)tartest.c    1.24 21/08/20 Copyright 2002-2021 J. Schilling */
    2 #include <schily/mconfig.h>
    3 #ifndef lint
    4 static  UConst char sccsid[] =
    5     "@(#)tartest.c  1.24 21/08/20 Copyright 2002-2021 J. Schilling";
    6 #endif
    7 /*
    8  *  Copyright (c) 2002-2021 J. Schilling
    9  */
   10 /*
   11  * The contents of this file are subject to the terms of the
   12  * Common Development and Distribution License, Version 1.0 only
   13  * (the "License").  You may not use this file except in compliance
   14  * with the License.
   15  *
   16  * See the file CDDL.Schily.txt in this distribution for details.
   17  * A copy of the CDDL is also available via the Internet at
   18  * http://www.opensource.org/licenses/cddl1.txt
   19  *
   20  * When distributing Covered Code, include this CDDL HEADER in each
   21  * file and include the License file CDDL.Schily.txt from this distribution.
   22  */
   23 
   24 #include <schily/stdio.h>
   25 #include <schily/stdlib.h>
   26 
   27 #include "star.h"
   28 #include <schily/standard.h>
   29 #include <schily/string.h>
   30 #include <schily/getargs.h>
   31 #define GT_COMERR       /* #define comerr gtcomerr */
   32 #define GT_ERROR        /* #define error gterror   */
   33 #include <schily/schily.h>
   34 
   35 #include <schily/fcntl.h>           /* O_BINARY */
   36 #include <schily/io.h>              /* for setmode() prototype */
   37 #include <schily/nlsdefs.h>
   38 
   39 LOCAL   void    usage       __PR((int ret));
   40 EXPORT  int main        __PR((int ac, char *av[]));
   41 LOCAL   BOOL    doit        __PR((FILE *f));
   42 LOCAL   BOOL    checkhdr    __PR((TCB *ptb));
   43 LOCAL   BOOL    checkoctal  __PR((char *ptr, int len, char *text));
   44 LOCAL   BOOL    checktype   __PR((TCB *ptb));
   45 LOCAL   BOOL    checkid     __PR((char *ptr, char *text));
   46 LOCAL   BOOL    checkmagic  __PR((char *ptr));
   47 LOCAL   BOOL    checkvers   __PR((char *ptr));
   48 EXPORT  void    stolli      __PR((char *s, Ullong *ull, int len));
   49 LOCAL   Ulong   checksum    __PR((TCB *ptb));
   50 LOCAL   void    pretty_char __PR((char *p, unsigned c));
   51 
   52 LOCAL   BOOL    verbose;
   53 LOCAL   BOOL    signedcksum;
   54 LOCAL   BOOL    is_posix_2001;
   55 
   56 LOCAL void
   57 usage(ret)
   58     int ret;
   59 {
   60     error("Usage:\t%s [options] < file\n", get_progname());
   61     error("Options:\n");
   62     error("\t-help\t\tprint this help\n");
   63     error("\t-version\tPrint version number.\n");
   64     error("\t-v\t\tprint all filenames during verification\n");
   65     error("\n%s checks stdin fore compliance with the POSIX.1-1990 TAR standard\n", get_progname());
   66     exit(ret);
   67     /* NOTREACHED */
   68 }
   69 
   70 EXPORT int
   71 main(ac, av)
   72     int ac;
   73     char    *av[];
   74 {
   75     int     cac = ac;
   76     char    *const *cav = av;
   77     BOOL        help = FALSE;
   78     BOOL        prversion = FALSE;
   79 
   80     save_args(ac, av);
   81 
   82     (void) setlocale(LC_ALL, "");
   83 
   84 #ifdef  USE_NLS
   85 #if !defined(TEXT_DOMAIN)   /* Should be defined by cc -D */
   86 #define TEXT_DOMAIN "tartest"   /* Use this only if it weren't */
   87 #endif
   88     { char  *dir;
   89     dir = searchfileinpath("share/locale", F_OK,
   90                     SIP_ANY_FILE|SIP_NO_PATH, NULL);
   91     if (dir)
   92         (void) bindtextdomain(TEXT_DOMAIN, dir);
   93     else
   94 #if defined(PROTOTYPES) && defined(INS_BASE)
   95     (void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
   96 #else
   97     (void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
   98 #endif
   99     (void) textdomain(TEXT_DOMAIN);
  100     }
  101 #endif  /* USE_NLS */
  102     cac--;
  103     cav++;
  104     if (getallargs(&cac, &cav, "help,h,version,v", &help, &help,
  105                         &prversion, &verbose) < 0) {
  106         errmsgno(EX_BAD, "Bad Option: '%s'.\n", cav[0]);
  107         usage(EX_BAD);
  108     }
  109     if (help)
  110         usage(0);
  111 
  112     printf("tartest %s (%s-%s-%s)\n\n", "1.24",
  113                     HOST_CPU, HOST_VENDOR, HOST_OS);
  114     gtprintf("Copyright (C) 2002-2021 %s\n", _("Jörg Schilling"));
  115     gtprintf("This is free software; see the source for copying conditions.  There is NO\n");
  116     gtprintf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
  117     if (prversion)
  118         exit(0);
  119 
  120     gtprintf("\nTesting for POSIX.1-1990 TAR compliance...\n");
  121 
  122     setmode(fileno(stdin), O_BINARY);
  123 
  124     if (!doit(stdin)) {
  125         gtprintf(">>> Archive is not POSIX.1-1990 TAR standard compliant.\n");
  126         return (1);
  127     }
  128     gtprintf("No deviations from POSIX.1-1990 TAR standard found.\n");
  129     return (0);
  130 }
  131 
  132 LOCAL BOOL
  133 doit(f)
  134     FILE    *f;
  135 {
  136     BOOL    ret = TRUE;
  137     BOOL    r;
  138     TCB tcb;
  139     TCB *ptb;
  140     char    name[257];
  141     char    lname[101];
  142     Ullong  checks;
  143     Ullong  hsum;
  144     Ullong  size;
  145     Ullong  blockno = 0;
  146     int i;
  147 
  148     ptb = &tcb;
  149     for (;;) {
  150         r = TRUE;
  151         fillbytes(ptb, TBLOCK, '\0');
  152         if (fileread(f, ptb, TBLOCK) != TBLOCK) {
  153             gtprintf("Hard EOF at block %lld\n", blockno);
  154             return (FALSE);
  155         }
  156 
  157         stolli(ptb->ustar_dbuf.t_chksum, &checks, 8);
  158         hsum = checksum(ptb);
  159         if (hsum == 0) {
  160             /*
  161              * Check EOF
  162              */
  163             gtprintf("Found 1st EOF block at %lld\n", blockno);
  164             blockno++;
  165             if (fileread(f, ptb, TBLOCK) != TBLOCK) {
  166                 gtprintf(
  167                 "Hard EOF at block %lld (second EOF block missing)\n",
  168                     blockno);
  169                 return (FALSE);
  170             }
  171             hsum = checksum(ptb);
  172             if (hsum != 0) {
  173                 gtprintf(
  174                     "Second EOF block missing at %lld\n",
  175                     blockno);
  176                 return (FALSE);
  177             }
  178             gtprintf("Found 2nd EOF block at %lld\n", blockno);
  179             return (ret);
  180         }
  181         if (checks != hsum) {
  182             gtprintf("Bad Checksum %0llo != %0llo at block %lld\n",
  183                             checks, hsum, blockno);
  184             signedcksum = TRUE;
  185             hsum = checksum(ptb);
  186             if (checks == hsum) {
  187                 gtprintf("Warning: archive uses signed checksums.\n");
  188                 return (FALSE);
  189             }
  190             if (blockno != 0) {
  191                 if (is_posix_2001) {
  192                     gtprintf(
  193                     "The archive may either be corrupted or using the POSIX.1-2001 size field.\n");
  194                 } else {
  195                     gtprintf(
  196                     "Warning: Corrupted TAR archive.\n");
  197                 }
  198             }
  199             return (FALSE);
  200         }
  201         blockno++;
  202 
  203         stolli(ptb->ustar_dbuf.t_size, &size, 12);
  204 
  205         if (ptb->ustar_dbuf.t_prefix[0]) {
  206             js_snprintf(name, sizeof (name), "%.155s/%.100s",
  207                 ptb->ustar_dbuf.t_prefix,
  208                 ptb->ustar_dbuf.t_name);
  209         } else {
  210             strncpy(name, ptb->ustar_dbuf.t_name, 100);
  211             name[100] = '\0';
  212         }
  213         strncpy(lname, ptb->ustar_dbuf.t_linkname, 100);
  214         lname[100] = '\0';
  215 
  216         r = checkhdr(ptb);
  217         if (!r)
  218             ret = FALSE;
  219 
  220         /*
  221          * Handle the size field acording to POSIX.1-1990.
  222          */
  223         i = tarblocks(size);
  224         switch ((int)(ptb->ustar_dbuf.t_typeflag & 0xFF)) {
  225 
  226         case '\0':  /* Old plain file */
  227         case '0':   /* Ustar plain file */
  228         case '7':   /* Contiguous file */
  229             break;
  230 
  231         case '1':   /* Hard link */
  232         case '2':   /* Symbolic link */
  233             if (i != 0) {
  234                 gtprintf(
  235                 "Warning: t_size field: %0llu, should be 0 for %s link\n",
  236                     size,
  237                     ptb->ustar_dbuf.t_typeflag == '1'?
  238                     "hard":"symbolic");
  239                 ret = r = FALSE;
  240             }
  241             i = 0;
  242             break;
  243         case '3':   /* Character special */
  244         case '4':   /* Block special */
  245         case '5':   /* Directory */
  246         case '6':   /* FIFO  (named pipe) */
  247             i = 0;
  248             break;
  249         }
  250 
  251         if (!r || verbose) {
  252             gtprintf("*** %sFilename '%s'\n",
  253                         r == FALSE ?
  254                         "Failing ":"", name);
  255             if (lname[0]) {
  256                 gtprintf("*** %sLinkname '%s'\n",
  257                         r == FALSE ?
  258                         "Failing ":"", lname);
  259             }
  260         }
  261 
  262         /*
  263          * Skip file content.
  264          */
  265         while (--i >= 0) {
  266             if (fileread(f, ptb, TBLOCK) != TBLOCK) {
  267                 gtprintf("Hard EOF at block %lld\n", blockno);
  268                 return (FALSE);
  269             }
  270             blockno++;
  271         }
  272     }
  273 
  274 }
  275 
  276 LOCAL BOOL
  277 checkhdr(ptb)
  278     TCB *ptb;
  279 {
  280     BOOL    ret = TRUE;
  281     int errs = 0;
  282     Ullong  ll;
  283 
  284     if (ptb->ustar_dbuf.t_name[  0] == '\0') {
  285         gtprintf("Warning: t_name[  0] is a null character.\n");
  286         errs++;
  287     }
  288     if (ptb->ustar_dbuf.t_name[  0] != '\0' &&
  289         ptb->ustar_dbuf.t_name[ 99] != '\0' &&
  290         /* LINTED */
  291         ptb->ndbuf.t_name[100] == '\0') {
  292         gtprintf("Warning: t_name[100] is a null character.\n");
  293         errs++;
  294     }
  295     if (ptb->ustar_dbuf.t_linkname[  0] != '\0' &&
  296         ptb->ustar_dbuf.t_linkname[ 99] != '\0' &&
  297         /* LINTED */
  298         ptb->ndbuf.t_linkname[100] == '\0') {
  299         gtprintf("Warning: t_linkname[100] is a null character.\n");
  300         errs++;
  301     }
  302 
  303     if (!checkoctal(ptb->ustar_dbuf.t_mode, 8, "t_mode"))
  304         errs++;
  305 
  306     stolli(ptb->ustar_dbuf.t_mode, &ll, 8);
  307     if (ll & ~07777) {
  308         gtprintf(
  309         "Warning: too many bits in t_mode field: 0%llo, should be 0%llo\n",
  310             ll, ll & 07777);
  311         errs++;
  312     }
  313 
  314     if (!checkoctal(ptb->ustar_dbuf.t_uid, 8, "t_uid"))
  315         errs++;
  316 
  317     if (!checkoctal(ptb->ustar_dbuf.t_gid, 8, "t_gid"))
  318         errs++;
  319 
  320     if (!checkoctal(ptb->ustar_dbuf.t_size, 12, "t_size"))
  321         errs++;
  322 
  323     if (!checkoctal(ptb->ustar_dbuf.t_mtime, 12, "t_mtime"))
  324         errs++;
  325 
  326     if (!checkoctal(ptb->ustar_dbuf.t_chksum, 8, "t_chksum"))
  327         errs++;
  328 
  329     if (!checktype(ptb))
  330         errs++;
  331 
  332     if (!checkmagic(ptb->ustar_dbuf.t_magic))
  333         errs++;
  334 
  335     if (!checkvers(ptb->ustar_dbuf.t_version))
  336         errs++;
  337 
  338     if (!checkid(ptb->ustar_dbuf.t_uname, "t_uname"))
  339         errs++;
  340     if (!checkid(ptb->ustar_dbuf.t_gname, "t_gname"))
  341         errs++;
  342 
  343     if (!checkoctal(ptb->ustar_dbuf.t_devmajor, 8, "t_devmajor"))
  344         errs++;
  345 
  346     if (!checkoctal(ptb->ustar_dbuf.t_devminor, 8, "t_devminor"))
  347         errs++;
  348 
  349 #ifdef  __needed__
  350     /*
  351      * The POSIX.1 TAR standard does not mention the last 12 bytes in the
  352      * TAR header. They may have any value...
  353      */
  354     if (cmpnullbytes(ptb->ustar_dbuf.t_mfill, 12) < 12) {
  355         gtprintf(
  356         "Warning: non null character in last 12 bytes of header\n");
  357         errs++;
  358     }
  359 #endif
  360 
  361     if (errs)
  362         ret = FALSE;
  363     return (ret);
  364 }
  365 
  366 /*
  367  * Check whether octal numeric fields are according to POSIX.1-1990.
  368  */
  369 LOCAL BOOL
  370 checkoctal(ptr, len, text)
  371     char    *ptr;
  372     int len;
  373     char    *text;
  374 {
  375     BOOL    ret = TRUE;
  376     BOOL    foundoctal = FALSE;
  377     int i;
  378     int endoff = 0;
  379 #ifdef      END_ALL_THESAME
  380     char    endc = '\0';
  381 #endif
  382     char    cs[4];
  383 
  384     for (i = 0; i < len; i++) {
  385 #ifdef  CHECKOCTAL_DEBUG
  386         error("%d '%c'\n", i, ptr[i]);
  387 #endif
  388 
  389 #ifdef      END_ALL_THESAME
  390         if (endoff > 0 && ptr[i] != endc) {
  391 #else
  392         /*
  393          * Ugly, but the standard seems to allow mixins space and null
  394          * characters at the end of an octal numeric field.
  395          */
  396         if (endoff > 0 && (ptr[i] != ' ' && ptr[i] != '\0')) {
  397 #endif
  398             pretty_char(cs, ptr[i] & 0xFF);
  399             gtprintf(
  400             "Warning: illegal end character '%s' (0x%02X) found in field '%s[%d]'\n",
  401                     cs,
  402                     ptr[i] & 0xFF,
  403                     text, i);
  404             ret = FALSE;
  405         }
  406         if (endoff > 0)
  407             continue;
  408         if (ptr[i] == ' ' || ptr[i] == '\0') {
  409             if (foundoctal) {
  410                 endoff = i;
  411 #ifdef      END_ALL_THESAME
  412                 endc = ptr[i];
  413 #endif
  414                 continue;
  415             }
  416         }
  417         if (!isoctal(ptr[i])) {
  418             pretty_char(cs, ptr[i] & 0xFF);
  419             gtprintf(
  420             "Warning: non octal character '%s' (0x%02X) found in field '%s[%d]'\n",
  421                     cs,
  422                     ptr[i] & 0xFF,
  423                     text, i);
  424             ret = FALSE;
  425         } else {
  426             foundoctal = TRUE;
  427         }
  428     }
  429     if (foundoctal && endoff == 0) {
  430         gtprintf("Warning: no end character found in field '%s'\n",
  431             text);
  432         ret = FALSE;
  433     }
  434     return (ret);
  435 }
  436 
  437 /*
  438  * Check whether the POSIX.1-1990 'typeflag' field contains a valid character.
  439  */
  440 LOCAL BOOL
  441 checktype(ptb)
  442     TCB *ptb;
  443 {
  444     BOOL    ret = TRUE;
  445     char    cs[4];
  446 
  447     switch ((int)(ptb->ustar_dbuf.t_typeflag & 0xFF)) {
  448 
  449     case '\0':  /* Old plain file */
  450     case '0':   /* Ustar plain file */
  451     case '1':   /* Hard link */
  452     case '2':   /* Symbolic link */
  453     case '3':   /* Character special */
  454     case '4':   /* Block special */
  455     case '5':   /* Directory */
  456     case '6':   /* FIFO  (named pipe) */
  457     case '7':   /* Contiguous file */
  458         break;
  459 
  460     case 'g':
  461     case 'x':
  462         if (!is_posix_2001) {
  463             gtprintf("Warning: Archive uses POSIX.1-2001 extensions.\n");
  464             gtprintf("Warning: The correctness of the size field cannot be checked for this reason.\n");
  465             is_posix_2001 = TRUE;
  466         }
  467         break;
  468 
  469     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
  470     case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
  471     case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
  472     case 'V': case 'W': case 'X': case 'Y': case 'Z':
  473         { static char vend[256];
  474             if (vend[ptb->ustar_dbuf.t_typeflag & 0xFF] == 0) {
  475                 gtprintf(
  476                 "Warning: Archive uses Vendor specific extension file type '%c'.\n",
  477                 ptb->ustar_dbuf.t_typeflag & 0xFF);
  478                 vend[ptb->ustar_dbuf.t_typeflag & 0xFF] = 1;
  479             }
  480         }
  481         break;
  482 
  483     default:
  484         pretty_char(cs, ptb->ustar_dbuf.t_typeflag & 0xFF);
  485         gtprintf(
  486         "Warning: Archive uses illegal file type '%s' (0x%02X).\n",
  487                 cs,
  488                 ptb->ustar_dbuf.t_typeflag & 0xFF);
  489         ret = FALSE;
  490     }
  491     return (ret);
  492 }
  493 
  494 /*
  495  * Check whether the POSIX.1-1990 'uid' or 'gid' field contains
  496  * reasonable things.
  497  */
  498 LOCAL BOOL
  499 checkid(ptr, text)
  500     char    *ptr;
  501     char    *text;
  502 {
  503     BOOL    ret = TRUE;
  504     char    cs[4];
  505     int len = 32;
  506     int i;
  507 
  508     if (ptr[0] == '\0') {
  509         for (i = 0; i < len; i++) {
  510             if (ptr[i] != '\0') {
  511                 pretty_char(cs, ptr[i] & 0xFF);
  512                 gtprintf(
  513                 "Warning: non null character '%s' (0x%02X) found in field '%s[%d]'\n",
  514                         cs,
  515                         ptr[i] & 0xFF,
  516                         text, i);
  517                 ret = FALSE;
  518             }
  519         }
  520         return (ret);
  521     }
  522     i = len - 1;
  523     if (ptr[i] != '\0') {
  524         pretty_char(cs, ptr[i] & 0xFF);
  525         gtprintf(
  526         "Warning: non null string terminator character '%s' (0x%02X) found in field '%s[%d]'\n",
  527                 cs,
  528                 ptr[i] & 0xFF,
  529                 text, i);
  530         ret = FALSE;
  531     }
  532     return (ret);
  533 }
  534 
  535 /*
  536  * Check whether the POSIX.1-1990 'magic' field contains the
  537  * two string "ustar" (5 characters and a null byte).
  538  */
  539 LOCAL BOOL
  540 checkmagic(ptr)
  541     char    *ptr;
  542 {
  543     BOOL    ret = TRUE;
  544     char    *mag = "ustar";
  545     char    cs[4];
  546     int i;
  547 
  548     for (i = 0; i < 6; i++) {
  549         if (ptr[i] != mag[i]) {
  550             pretty_char(cs, ptr[i] & 0xFF);
  551             gtprintf(
  552             "Warning: illegal character '%s' (0x%02X) found in field 't_magic[%d]'\n",
  553                     cs,
  554                     ptr[i] & 0xFF, i);
  555             ret = FALSE;
  556         }
  557     }
  558     return (ret);
  559 }
  560 
  561 /*
  562  * Check whether the POSIX.1-1990 'version' field contains the
  563  * two characters "00".
  564  */
  565 LOCAL BOOL
  566 checkvers(ptr)
  567     char    *ptr;
  568 {
  569     BOOL    ret = TRUE;
  570     char    *vers = "00";
  571     char    cs[4];
  572     int i;
  573 
  574     for (i = 0; i < 2; i++) {
  575         if (ptr[i] != vers[i]) {
  576             pretty_char(cs, ptr[i] & 0xFF);
  577             gtprintf(
  578             "Warning: illegal character '%s' (0x%02X) found in field 't_version[%d]'\n",
  579                     cs,
  580                     ptr[i] & 0xFF, i);
  581             ret = FALSE;
  582         }
  583     }
  584     return (ret);
  585 }
  586 
  587 
  588 /*
  589  * Convert string -> long long int
  590  * This is the debug version that stops at "len" size to be safe against
  591  * field overflow.
  592  */
  593 EXPORT void
  594 stolli(s, ull, len)
  595     register char   *s;
  596         Ullong  *ull;
  597         int len;
  598 {
  599     register Ullong ret = (Ullong)0;
  600     register char   c;
  601     register int    t;
  602 
  603     while (*s == ' ') {
  604         if (--len < 0)
  605             break;
  606         s++;
  607     }
  608 
  609     for (;;) {
  610         if (--len < 0)
  611             break;
  612         c = *s++;
  613 #ifdef  STOLLI_DEBUG
  614         error("'%c'\n", c);
  615 #endif
  616         if (isoctal(c))
  617             t = c - '0';
  618         else
  619             break;
  620         ret *= 8;
  621         ret += t;
  622     }
  623     *ull = ret;
  624 #ifdef  STOLLI_DEBUG
  625     error("len: %d\n", len);
  626 #endif
  627 }
  628 
  629 /*
  630  * Checsum function.
  631  * Returns 0 if the block contains nothing but null characters.
  632  */
  633 #define CHECKS  sizeof (ptb->ustar_dbuf.t_chksum)
  634 /*
  635  * We know, that sizeof (TCP) is 512 and therefore has no
  636  * reminder when dividing by 8
  637  *
  638  * CHECKS is known to be 8 too, use loop unrolling.
  639  */
  640 #define DO8(a)  a; a; a; a; a; a; a; a;
  641 
  642 LOCAL Ulong
  643 checksum(ptb)
  644     register    TCB *ptb;
  645 {
  646     register    int i;
  647     register    Ulong   sum = 0;
  648     register    Uchar   *us;
  649 
  650     if (signedcksum) {
  651         register    char    *ss;
  652 
  653         ss = (char *)ptb;
  654         for (i = sizeof (*ptb)/8; --i >= 0; ) {
  655             DO8(sum += *ss++);
  656         }
  657         if (sum == 0L)      /* Block containing 512 nul's */
  658             return (sum);
  659 
  660         ss = (char *)ptb->ustar_dbuf.t_chksum;
  661         DO8(sum -= *ss++);
  662         sum += CHECKS*' ';
  663     } else {
  664         us = (Uchar *)ptb;
  665         for (i = sizeof (*ptb)/8; --i >= 0; ) {
  666             DO8(sum += *us++);
  667         }
  668         if (sum == 0L)      /* Block containing 512 nul's */
  669             return (sum);
  670 
  671         us = (Uchar *)ptb->ustar_dbuf.t_chksum;
  672         DO8(sum -= *us++);
  673         sum += CHECKS*' ';
  674     }
  675     return (sum);
  676 }
  677 
  678 /*
  679  * Pretty print one character.
  680  * Quote anything that is not a printable 7 bit ASCII character.
  681  */
  682 #define SP  ' '
  683 #define DEL '\177'
  684 #define SP8 (SP | 0x80)
  685 #define DEL8    (DEL | 0x80)
  686 
  687 LOCAL void
  688 pretty_char(p, c)
  689     char        *p;
  690     unsigned    c;
  691 {
  692     c &= 0xFF;
  693 
  694     if (c < SP || c == DEL) {           /* ctl char */
  695         *p++ = '^';
  696         *p++ = c ^ 0100;
  697     } else if ((c > DEL && c < SP8) || c == DEL8) {  /* 8 bit ctl */
  698         *p++ = '~';
  699         *p++ = '^';
  700         *p++ = c ^ 0300;
  701     } else if (c >= SP8) {              /* 8 bit char */
  702         *p++ = '~';
  703         *p++ = c & 0177;
  704     } else {                    /* normal char */
  705         *p++ = c;
  706     }
  707     *p = '\0';
  708 }