Cover V02, I06
Article
Figure 1
Listing 1
Listing 2

nov93.tar


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   */
164  /* End of File */