12 #include <sys/sendfile.h>
14 /* Possible commands to run. Or them together... */
15 #define CMD_LIST 0x0001
16 #define CMD_BUILD_IMAGE 0x0002
18 typedef unsigned long long UINT64;
19 typedef unsigned long UINT32;
21 #define BUF_SIZE 65536
23 /* Different types used in the extent_type below */
26 #define JTET_FILE_MATCH 2
27 #define JTET_NOMATCH 3
29 #define JTE_ID_STRING "JTE"
30 #define JTE_HEADER_STRING "MKJ IMAGE START"
31 #define JTE_FOOTER_STRING "*MKJ IMAGE END*"
32 #define JTE_VER_MAJOR 0x0001
33 #define JTE_VER_MINOR 0x0000
37 unsigned char id[4]; /* "JTE" plus NULL terminator */
38 unsigned char extent_type; /* The type of this extent in the jigdo template file */
39 unsigned char extent_length[8]; /* The length in bytes of this extent, including all
40 the metadata. 64-bit, big endian */
41 unsigned char start_sector[4]; /* The start sector of this extent within the output image;
42 32-bit BE. Header and footer use 0xFFFFFFFF */
47 unsigned char header_string[16]; /* Recognition string. Should contain "MKJ IMAGE START",
48 including NULL terminator */
49 unsigned char version[4]; /* Version number, encoded MMmm */
50 unsigned char sector_size[4]; /* Sector size used in this image.
51 _Always_ expected to be 2KB. Stored as 32-bit BE */
52 unsigned char pad[16];
56 unsigned char footer_string[16]; /* Recognition string. Should contain "*MKJ IMAGE END*",
57 including NULL terminator */
58 unsigned char image_size[8]; /* Size of image, in bytes. 64-bit BE. */
59 unsigned char md5[16]; /* MD5SUM of the entire image */
63 unsigned char file_length[8]; /* The actual length of the file stored in this extent.
64 Will be <= extent_length; also 64-bit BE */
65 unsigned char filename_length[4]; /* The length of the following filename entry */
66 unsigned char md5[16]; /* MD5SUM of the _file_ data in this lump, without padding */
67 unsigned char pad[12];
71 unsigned char unmatched_length[8]; /* The length of the data in this extent. Will be ==
72 extent_length - sizeof(struct jt_extent_data) ; also 64-bit BE */
73 unsigned char md5[16]; /* MD5SUM of this lump of unmatched data */
74 unsigned char pad[16];
81 UINT32 sector_size = 0;
85 static char *print_md5(unsigned char *buf)
87 static char outbuf[33];
89 bzero(outbuf, sizeof(outbuf));
90 sprintf(outbuf, "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
91 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
92 buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
96 static int my_sendfile(int src_fd, int dst_fd, off_t length)
100 off_t bytes_read = 0;
101 off_t bytes_written = 0;
104 while (bytes < length)
106 size = length - bytes;
110 bytes_read = read(src_fd, buf, size);
111 if (size != bytes_read)
113 printf("my_sendfile: FAILED to read %llu bytes from input file; error %d\n", size, errno);
116 bytes_written = write(dst_fd, buf, bytes_read);
117 if (bytes_read != bytes_written)
119 printf("my_sendfile: FAILED to write %llu bytes to output file; error %d\n", bytes_read, errno);
125 /* Now pad if necessary */
126 if (length % sector_size)
128 bzero (buf, BUF_SIZE);
129 off_t pad_size = sector_size - (length % sector_size);
131 bytes = write(dst_fd, buf, pad_size);
134 printf("my_sendfile: FAILED to pad with %llu bytes; error %d\n", pad_size, errno);
142 UINT64 handle_jtet_header(UINT64 extent_length,
143 UINT32 start_sector, unsigned char *buf)
145 struct jt_extent_data *extent = (struct jt_extent_data *)buf;
147 sector_size = extent->data.header.sector_size[0] << 24;
148 sector_size |= extent->data.header.sector_size[1] << 16;
149 sector_size |= extent->data.header.sector_size[2] << 8;
150 sector_size |= extent->data.header.sector_size[3];
154 printf(" Header string: %s\n", extent->data.header.header_string);
155 printf(" JTE version: %d.%d\n",
156 (extent->data.header.version[0] << 8) | extent->data.header.version[1],
157 (extent->data.header.version[2] << 8) | extent->data.header.version[3]);
158 printf(" Sector size: %ld bytes\n", sector_size);
160 return extent_length;
163 UINT64 handle_jtet_footer(UINT64 extent_length,
164 UINT32 start_sector, unsigned char *buf)
166 struct jt_extent_data *extent = (struct jt_extent_data *)buf;
167 UINT64 image_size = (UINT64)extent->data.footer.image_size[0] << 56;
168 image_size |= (UINT64)extent->data.footer.image_size[1] << 48;
169 image_size |= (UINT64)extent->data.footer.image_size[2] << 40;
170 image_size |= (UINT64)extent->data.footer.image_size[3] << 32;
171 image_size |= (UINT64)extent->data.footer.image_size[4] << 24;
172 image_size |= (UINT64)extent->data.footer.image_size[5] << 16;
173 image_size |= (UINT64)extent->data.footer.image_size[6] << 8;
174 image_size |= (UINT64)extent->data.footer.image_size[7];
178 printf(" Footer string: %s\n", extent->data.footer.footer_string);
179 printf(" ISO image size: %llu\n", image_size);
180 printf(" ISO image MD5sum: %s\n", print_md5(extent->data.footer.md5));
185 UINT64 handle_jtet_file_match(UINT64 extent_length,
186 UINT32 start_sector, unsigned char *buf)
190 struct jt_extent_data *extent = (struct jt_extent_data *)buf;
191 char *filename = &buf[57];
193 int filename_length = 0;
195 length |= (UINT64)extent->data.file_match.file_length[0] << 56;
196 length |= (UINT64)extent->data.file_match.file_length[1] << 48;
197 length |= (UINT64)extent->data.file_match.file_length[2] << 40;
198 length |= (UINT64)extent->data.file_match.file_length[3] << 32;
199 length |= (UINT64)extent->data.file_match.file_length[4] << 24;
200 length |= (UINT64)extent->data.file_match.file_length[5] << 16;
201 length |= (UINT64)extent->data.file_match.file_length[6] << 8;
202 length |= (UINT64)extent->data.file_match.file_length[7];
204 filename_length |= extent->data.file_match.filename_length[0] << 24;
205 filename_length |= extent->data.file_match.filename_length[1] << 16;
206 filename_length |= extent->data.file_match.filename_length[2] << 8;
207 filename_length |= extent->data.file_match.filename_length[3];
211 printf(" File length: %llu\n", length);
212 printf(" Filename len: %d\n", filename_length);
213 printf(" Filename: %s\n", filename);
214 printf(" File MD5sum: %s\n", print_md5(extent->data.file_match.md5));
217 if (cmd & CMD_BUILD_IMAGE)
219 chunk_fd = open(filename, O_RDONLY|O_LARGEFILE);
222 printf("FAILED to open filename %s, error %d. Aborting\n", filename, errno);
228 printf("Writing %7llu bytes of %s to output file\n", length, filename);
229 error = my_sendfile(chunk_fd, out_fd, length);
233 printf("FAILED to copy contents of %s into output file; error %d. Aborting\n", filename, error);
239 return extent_length;
242 UINT64 handle_jtet_no_match(UINT64 extent_length,
243 UINT32 start_sector, unsigned char *buf)
247 struct jt_extent_data *extent = (struct jt_extent_data *)buf;
249 length |= (UINT64)extent->data.nomatch.unmatched_length[0] << 56;
250 length |= (UINT64)extent->data.nomatch.unmatched_length[1] << 48;
251 length |= (UINT64)extent->data.nomatch.unmatched_length[2] << 40;
252 length |= (UINT64)extent->data.nomatch.unmatched_length[3] << 32;
253 length |= (UINT64)extent->data.nomatch.unmatched_length[4] << 24;
254 length |= (UINT64)extent->data.nomatch.unmatched_length[5] << 16;
255 length |= (UINT64)extent->data.nomatch.unmatched_length[6] << 8;
256 length |= (UINT64)extent->data.nomatch.unmatched_length[7];
260 printf(" Unmatched data, length %llu\n", length);
261 printf(" Chunk MD5sum: %s\n", print_md5(extent->data.nomatch.md5));
264 if (cmd & CMD_BUILD_IMAGE)
266 /* Seek past the header of this block */
267 lseek(jte_fd, sizeof(struct jt_extent_data), SEEK_CUR);
269 printf("Writing %7llu bytes of unmatched image data to output file\n", length);
270 error = my_sendfile(jte_fd, out_fd, length);
273 printf("FAILED to copy unmatched data chunk into output file; error %d. Aborting\n", error);
278 return extent_length;
281 UINT64 parse_jte_block(UINT64 offset, unsigned char *buf, size_t buf_size)
284 UINT64 extent_length = 0;
285 UINT32 start_sector = 0;
286 struct jt_extent_data *extent = (struct jt_extent_data *)buf;
288 if (strncmp(extent->id, JTE_ID_STRING, 4))
290 printf("Error! Didn't find expected JTE block at offset %lld\n", offset);
294 printf("\nJTE block found at offset %lld\n", offset);
296 extent_type = extent->extent_type;
298 extent_length |= (UINT64)extent->extent_length[0] << 56;
299 extent_length |= (UINT64)extent->extent_length[1] << 48;
300 extent_length |= (UINT64)extent->extent_length[2] << 40;
301 extent_length |= (UINT64)extent->extent_length[3] << 32;
302 extent_length |= (UINT64)extent->extent_length[4] << 24;
303 extent_length |= (UINT64)extent->extent_length[5] << 16;
304 extent_length |= (UINT64)extent->extent_length[6] << 8;
305 extent_length |= (UINT64)extent->extent_length[7];
307 start_sector |= extent->start_sector[0] << 24;
308 start_sector |= extent->start_sector[1] << 16;
309 start_sector |= extent->start_sector[2] << 8;
310 start_sector |= extent->start_sector[3];
313 printf(" extent type %d, length %llu, start_sector %ld (out offset %llu)\n",
314 extent_type, extent_length, start_sector, (off_t)start_sector * sector_size);
319 return handle_jtet_header(extent_length, start_sector, buf);
321 return handle_jtet_footer(extent_length, start_sector, buf);
322 case JTET_FILE_MATCH:
323 return handle_jtet_file_match(extent_length, start_sector, buf);
325 return handle_jtet_no_match(extent_length, start_sector, buf);
327 printf("Awooga! Invalid extent type!\n");
332 int main(int argc, char **argv)
334 char *filename = NULL;
335 char *outfile = NULL;
336 unsigned char *buf = NULL;
342 for (i = 1; i < argc; i++)
344 if (!strcmp(argv[i], "-l"))
346 else if (!strcmp(argv[i], "-b"))
347 cmd |= CMD_BUILD_IMAGE;
348 else if (!strcmp(argv[i], "-v"))
350 else if (!strcmp(argv[i], "-o") && i < argc - 1)
352 else if (!strcmp(argv[i], "-f") && i < argc - 1)
353 filename = argv[++i];
359 if (NULL == filename)
361 printf("No filename specified! Try again...\n");
365 if ( (cmd & CMD_BUILD_IMAGE) && !outfile)
367 printf("No output filename given; aborting...\n");
371 jte_fd = open(filename, O_RDONLY|O_LARGEFILE);
374 printf("Failed to open input file %s, error %d!. Try again...\n", filename, errno);
380 out_fd = open(outfile, O_RDWR|O_CREAT|O_TRUNC|O_LARGEFILE, 0644);
383 printf("Failed to open output file %s, error %d!\n", outfile, errno);
388 buf = malloc(BUF_SIZE);
391 printf("Failed to malloc %d bytes. Abort!\n", BUF_SIZE);
397 UINT64 start_offset = -1;
398 lseek(jte_fd, offset, SEEK_SET);
399 bytes = read(jte_fd, buf, BUF_SIZE);
402 printf("Failed to read! error %d\n", errno);
406 lseek(jte_fd, offset, SEEK_SET);
407 start_offset = parse_jte_block(offset, buf, bytes);
409 break; /* We're finished! */
410 offset += start_offset;