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 */
|