Listing 1: tartt.c 

     1	/*  Example usage:  tartt < /dev/rst0
     2	 *  Example Output:
     3	 *  0       512     dumbo_home2/jcj/
     4	 *  512     1024    dumbo_home2/jcj/lost+found/
     5	 *  1024    1280    dumbo_home2/jcj/.Master
     6	 *  . . .
     7	 */
     8	
     9	#include <stdio.h>
    10	
    11	
    12	
    13	main()
    14	{
    15	    while(1) {
    16		findHeader();
    17		writeInformation();
    18		skipOverData();
    19	    }
    20	}
    21	
    22	#include <errno.h>
    23	#include <ctype.h>
    24	#include <fcntl.h>
    25	
    26	#define TBLOCK 512
    27	#define NAMSIZ 100
    28	union hblock {
    29	   char dummy[TBLOCK];
    30	   struct header {
    31		char name[NAMSIZ];
    32		char mode[8];
    33		char uid[8];
    34		char gid[8];
    35		char size[12];
    36		char mtime[12];
    37		char chksum[8];
    38		char linkflag;
    39		char linkname[NAMSIZ];
    40	   } dbuf;
    41	} tarHeader;
    42	
    43	char fileName[100];
    44	int  nBlocks;
    45	int  fs, i, fh;
    46	char dataBuffer[TBLOCK];
    47	int  blocksRead = 0;
    48	
    49	    char *
    50	readHeader()
    51	{
    52	    i = fread (&tarHeader, TBLOCK, 1, stdin);
    53	    blocksRead++;
    54	
    55	    /****** End of file? ******/
    56	
    57	    if (feof(stdin)) return "end of input";
    58	    if (i != 1) {
    59		perror("readHeader: fread");
    60		exit(0);
    61	    }
    62	
    63	    /****** Check the validity of this header: ******
    64	
    65		    Check the NAME field (first 100 bytes)
    66		    0) If null header, return "null header" - this may be EOF
    67		       and time to sync on another new tarFile.
    68		    1) if 1st byte is 0, it's invalid.  (Takes care of null hdrs)
    69		    2) if we have unprintable characters before 1st 0, it's invalid.
    70		    3) if we have any blanks before 1st 0, it's invalid.
    71		    4) If the name is >= 100 characters long, it's invalid.
    72		    5) After the 1st 0, all bytes should be 0.
    73		    6) If the file size is zero, consider it invalid.
    74		    7) No, that might be a directory...
    75	     */
    76	    
    77	    if (tarHeader.dbuf.name[0] == '\0') {
    78		int sum = 0;
    79		for (i = 0; i < TBLOCK; i++) sum += abs((int) tarHeader.dummy[i]);
    80		if (sum == 0) return "null header";
    81		else return "header first byte is 0";
    82	    }
    83	
    84	    for (i=0; i<100; i++) {
    85		if (tarHeader.dbuf.name[i] == '\0') break;
    86		if (! isprint (tarHeader.dbuf.name[i])) return "nonprintable character in filename";
    87		if (tarHeader.dbuf.name[i] == '\n') return "NL in filename";
    88		if (tarHeader.dbuf.name[i] == '\r') return "CR in filename";
    89	    }
    90	
    91	    if (i >= 100) return "name is too long";
    92	
    93	    for ( ; i < 100; i++) {
    94		if (tarHeader.dbuf.name[i]) return "name is not zero-filled";
    95	    }
    96	    sscanf (tarHeader.dbuf.size, "%12o", &fs);
    97	
    98	    /****** Header is legal. Proceed. ******/
    99	
   100	    nBlocks = (fs + TBLOCK - 1) / TBLOCK;
   101	    strcpy (fileName, tarHeader.dbuf.name);
   102	    return NULL;
   103	}
   104	
   105	findHeader()
   106	{
   107	    char *m = NULL;
   108	    while (1) {
   109		int  b = blocksRead * TBLOCK;
   110		char chksum[8];
   111		m = readHeader();
   112		if (m) {
   113		    printf ("HEADER: byte %d\t%s\n", b, m);
   114		    if (strcmp (m, "end of input") == 0) exit(1);
   115		    continue;
   116		}
   117		/* Check the checksum */
   118		{   int bcs, ccs;	/* buffer checksum, calculated checksum */
   119		    sscanf (tarHeader.dbuf.chksum, "%7o", &bcs);
   120		    memcpy (chksum, tarHeader.dbuf.chksum, 8);
   121		    memset (tarHeader.dbuf.chksum, ' ', 8);
   122		    ccs = 0;
   123		    for (i=0; i<TBLOCK; i++) ccs += (int) tarHeader.dummy[i];
   124		    memcpy (tarHeader.dbuf.chksum, chksum, 8);
   125		    if (bcs != ccs) {
   126			printf ("HEADER: byte %d\tchecksum %d in buffer != %d calculated\n", b, bcs, ccs);
   127			continue;
   128		    }
   129		}
   130		/* Check some more about the header */
   131		if (nBlocks < 0) { printf ("HEADER: byte %d\tnBlocks < 0\n", b); continue; }
   132		/* If you've gotten here without a continue, you can return. */
   133		/* Bad flow, I know */
   134		return;
   135	    }
   136	}
   137	
   138	writeInformation()
   139	{
   140	    int startByte = (blocksRead-1) * TBLOCK;
   141	    int endByte = (blocksRead + nBlocks) * TBLOCK;
   142	    printf ("%d\t%d\t%s\n", startByte, endByte, tarHeader.dbuf.name);
   143	}
   144	
   145	skipOverData()
   146	{
   147	    int j;
   148	    for (j = 0; j < nBlocks; j++) {
   149		int i = fread (dataBuffer, TBLOCK, 1, stdin);
   150		if (feof (stdin)) fprintf (stderr, "End of input <= byte # %d", TBLOCK * blocksRead);
   151		if (i != 1) fprintf (stderr, "End of input about byte # %d", TBLOCK * (blocksRead + j));
   152		blocksRead++;
   153	    }
   154	}
   155	
   156	/******   E D I T I N G   H I S T O R Y   &   N O T E S   *******
   157	 *
   158	 * Jan 29, 1991: Ben: it works, on a long tape, across dd file marks.
   159	 * Feb. 1, 1991: Exit when a header can't be found.
   160	 * Feb. 1, 1991: After 2 null headers, get back to a 20-byte boundary.
   161	 * 04/20/93 Ben: set all verbosity to 0
   162	 * 09/22/93 Ben: clean it up for sysAdm magazine
   163	 */

