Updated README to mention debian-cd support
[jigit.git] / dump.c
1 #include <errno.h>
2 #include <math.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <zlib.h>
6 #include <stdio.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <sys/mman.h>
12
13 typedef unsigned long long UINT64;
14 typedef unsigned long      UINT32;
15
16 #define BUF_SIZE 65536
17
18 typedef enum state_
19 {
20     STARTING,
21     IN_DATA,
22     IN_DESC,
23     DUMP_DESC,
24     DONE,
25     ERROR
26 } e_state;
27
28 off_t find_string(unsigned char *buf, size_t buf_size, char *search)
29 {
30     size_t length = strlen(search);
31     off_t result;
32     
33     for (result = 0; result < (buf_size - length); result++)
34     {
35         if (!memcmp(&buf[result], search, length))
36             return result;
37     }
38     return -1;
39 }
40
41 off_t parse_data_block(off_t offset, unsigned char *buf, size_t buf_size)
42 {
43     /* Parse the contents of this data block... */
44     UINT64 dataLen = 0;
45     UINT64 dataUnc = 0;
46     
47     printf("\nDATA block found at offset %lld\n", offset);
48     dataLen = (UINT64)buf[4];
49     dataLen |= (UINT64)buf[5] << 8;
50     dataLen |= (UINT64)buf[6] << 16;
51     dataLen |= (UINT64)buf[7] << 24;
52     dataLen |= (UINT64)buf[8] << 32;
53     dataLen |= (UINT64)buf[9] << 40;
54     printf("  compressed block size %llu bytes\n", dataLen);
55
56     dataUnc = (UINT64)buf[10];
57     dataUnc |= (UINT64)buf[11] << 8;
58     dataUnc |= (UINT64)buf[12] << 16;
59     dataUnc |= (UINT64)buf[13] << 24;
60     dataUnc |= (UINT64)buf[14] << 32;
61     dataUnc |= (UINT64)buf[15] << 40;
62     printf("  uncompressed block size %llu bytes\n", dataUnc);
63
64     return dataLen;
65 }
66
67 void base64_dump(unsigned char *buf, size_t buf_size)
68 {
69     const char *b64_enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
70     int value = 0;
71     unsigned int i;
72     int bits = 0;
73
74     for (i = 0; i < buf_size ; i++)
75     {
76         value = (value << 8) | buf[i];
77         bits += 2;
78         printf("%c", b64_enc[(value >> bits) & 63U]);
79         if (bits >= 8) {
80             bits -= 6;
81             printf("%c", b64_enc[(value >> bits) & 63U]);
82         }
83     }
84     if (bits > 0)
85     {
86         value <<= 8 - bits;
87         printf("%c", b64_enc[(value >> bits) & 63U]);
88     }
89 }
90
91 off_t parse_desc_block(off_t offset, unsigned char *buf, size_t buf_size)
92 {
93     /* Parse the contents of this data block... */
94     UINT64 descLen = 0;
95     
96     printf("\nDESC block found at offset %lld\n", offset);
97     descLen = (UINT64)buf[4];
98     descLen |= (UINT64)buf[5] << 8;
99     descLen |= (UINT64)buf[6] << 16;
100     descLen |= (UINT64)buf[7] << 24;
101     descLen |= (UINT64)buf[8] << 32;
102     descLen |= (UINT64)buf[9] << 40;
103     printf("  DESC block size is %llu bytes\n", descLen);
104     
105     return 10;
106 }
107
108 off_t parse_desc_data(off_t offset, unsigned char *buf, size_t buf_size)
109 {
110     int type = buf[0];
111     printf("  DESC entry: block type %d\n", type);
112     
113     switch (type)
114     {
115         case 2:
116         {
117             UINT64 skipLen = 0;
118             skipLen = (UINT64)buf[1];
119             skipLen |= (UINT64)buf[2] << 8;
120             skipLen |= (UINT64)buf[3] << 16;
121             skipLen |= (UINT64)buf[4] << 24;
122             skipLen |= (UINT64)buf[5] << 32;
123             skipLen |= (UINT64)buf[6] << 40;
124             printf("    Unmatched data, %llu bytes\n", skipLen);
125             return 7;
126         }
127         case 5:
128         {
129             UINT64 imglen = 0;
130             UINT32 blocklen = 0;
131             int i = 0;
132
133             imglen = (UINT64)buf[1];
134             imglen |= (UINT64)buf[2] << 8;
135             imglen |= (UINT64)buf[3] << 16;
136             imglen |= (UINT64)buf[4] << 24;
137             imglen |= (UINT64)buf[5] << 32;
138             imglen |= (UINT64)buf[6] << 40;
139
140             blocklen = (UINT32)buf[23];
141             blocklen |= (UINT32)buf[24] << 8;
142             blocklen |= (UINT32)buf[25] << 16;
143             blocklen |= (UINT32)buf[26] << 24;
144
145             printf("    Original image length %llu bytes\n", imglen);
146             printf("    Image MD5: ");
147             for (i = 7; i < 23; i++)
148                 printf("%2.2x", buf[i]);
149             printf(" (");
150             base64_dump(&buf[7], 16);
151             printf(")");
152             printf("\n    MD5 block length %lu bytes\n", blocklen);
153             return 0; /* i.e. we're finished! */
154         }
155         case 6:
156         {
157             UINT64 fileLen = 0;
158             int i = 0;
159
160             fileLen = (UINT64)buf[1];
161             fileLen |= (UINT64)buf[2] << 8;
162             fileLen |= (UINT64)buf[3] << 16;
163             fileLen |= (UINT64)buf[4] << 24;
164             fileLen |= (UINT64)buf[5] << 32;
165             fileLen |= (UINT64)buf[6] << 40;
166             
167             printf("    File, length %llu bytes\n", fileLen);
168             printf("    file rsyncsum: ");
169             for (i = 7; i < 15; i++)
170                 printf("%2.2x", buf[i]);
171             printf("\n    file md5: ");
172             for (i = 15; i < 31; i++)
173                 printf("%2.2x", buf[i]);
174             printf(" (");
175             base64_dump(&buf[15], 16);
176             printf(")");
177             printf("\n");
178             return 31;
179         }
180         default:
181             break;
182     }
183
184     return 0;
185 }
186
187 int main(int argc, char **argv)
188 {
189     char *filename = NULL;
190     int fd = -1;
191     unsigned char *buf = NULL;
192     off_t offset = 0;
193     off_t bytes = 0;
194     e_state state = STARTING;
195     
196     if (argc != 2)
197     {
198         printf("No filename specified! Try again...\n");
199         return EINVAL;
200     }
201     
202     filename = argv[1];
203     
204     fd = open(filename, O_RDONLY);
205     if (-1 == fd)
206     {
207         printf("Failed to open file %s, error %d!. Try again...\n", filename, errno);
208         return errno;
209     }
210
211     buf = malloc(BUF_SIZE);
212     if (!buf)
213     {
214         printf("Failed to malloc %d bytes. Abort!\n", BUF_SIZE);
215         return ENOMEM;
216     }
217
218     /* Find the beginning of the data - read the first chunk, including the header */
219     while (STARTING == state)
220     {
221         off_t start_offset = -1;
222
223         bytes = read(fd, buf, BUF_SIZE);
224         if (0 >= bytes)
225         {
226             state = DONE;
227             break;
228         }
229         start_offset = find_string(buf, bytes, "DATA");
230         if (start_offset >= 0)
231         {
232             offset += start_offset;
233             state = IN_DATA;
234             break;
235         }
236         offset += bytes;
237     }
238
239     while (DONE != state && ERROR != state)
240     {
241         off_t start_offset = -1;
242         lseek(fd, offset, SEEK_SET);
243         bytes = read(fd, buf, BUF_SIZE);
244         if (0 >= bytes)
245         {
246             state = ERROR;
247             break;
248         }
249         if (IN_DATA == state)
250         {
251             if (!find_string(buf, bytes, "DATA"))
252                 state = IN_DATA;
253             if (!find_string(buf, bytes, "DESC"))
254                 state = IN_DESC;
255         }
256         switch (state)
257         {
258             case IN_DATA:
259                 start_offset = parse_data_block(offset, buf, bytes);
260                 offset += start_offset;
261                 break;
262             case IN_DESC:
263                 start_offset = parse_desc_block(offset, buf, bytes);
264                 offset += start_offset;
265                 state = DUMP_DESC;
266                 break;
267             case DUMP_DESC:
268                 start_offset = parse_desc_data(offset, buf, bytes);
269                 offset += start_offset;
270                 if (0 == start_offset)
271                     state = DONE;
272                 break;
273             default:
274                 break;
275         }
276     }        
277     
278     close(fd);
279
280     return 0;
281 }