/[debburn]/cdrkit/trunk/genisoimage/jte.c
ViewVC logotype

Contents of /cdrkit/trunk/genisoimage/jte.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 453 - (show annotations) (download)
Thu Nov 23 22:11:41 2006 UTC (6 years, 5 months ago) by blade
File MIME type: text/plain
File size: 28092 byte(s)
Name is finally genisoimage, debian/* fixes, debian/copyright cleanup
1 /*
2 * This file has been modified for the cdrkit suite.
3 *
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
6 *
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
10 *
11 */
12
13 #undef BZ2_SUPPORT
14
15 #include <mconfig.h>
16 #include "genisoimage.h"
17 #include <timedefs.h>
18 #include <fctldefs.h>
19 #include <zlib.h>
20 #ifdef BZ2_SUPPORT
21 # include <bzlib.h>
22 #endif
23 #include <regex.h>
24 #ifdef SORTING
25 #include "match.h"
26 #endif /* SORTING */
27 #include <errno.h>
28 #include <schily.h>
29 #ifdef DVD_VIDEO
30 #include "dvd_reader.h"
31 #include "dvd_file.h"
32 #include "ifo_read.h"
33 #include "md5.h"
34 #include "endianconv.h"
35 #endif
36 #ifdef APPLE_HYB
37 #include <ctype.h>
38 #endif
39
40 #ifdef VMS
41 #include "vms.h"
42 #endif
43
44 /* Different types used in building our state list below */
45 #define JTET_FILE_MATCH 1
46 #define JTET_NOMATCH 2
47
48 #define JTE_VER_MAJOR 0x0001
49 #define JTE_VER_MINOR 0x000F
50 #define JTE_NAME "JTE"
51 #define JTE_COMMENT "JTE at http://www.einval.com/~steve/software/JTE/ ; jigdo at http://atterer.net/jigdo/"
52
53 #define JIGDO_TEMPLATE_VERSION "1.1"
54
55 #ifdef BZ2_SUPPORT
56 int use_bz2 = 0;
57 #endif
58
59 /*
60 Simple list to hold the results of -jigdo-exclude and
61 -jigdo-force-match command line options. Seems easiest to do this
62 using regexps.
63 */
64 struct path_match
65 {
66 regex_t match_pattern;
67 char *match_rule;
68 struct path_match *next;
69 };
70
71 /* List of mappings e.g. Debian=/mirror/debian */
72 struct path_mapping
73 {
74 char *from;
75 char *to;
76 struct path_mapping *next;
77 };
78
79 FILE *jtjigdo = NULL; /* File handle used throughout for the jigdo file */
80 FILE *jttemplate = NULL; /* File handle used throughout for the template file */
81 char *jjigdo_out = NULL; /* Output name for jigdo .jigdo file; NULL means don't do it */
82 char *jtemplate_out = NULL; /* Output name for jigdo template file; NULL means don't do it */
83 char *jmd5_list = NULL; /* Name of file to use for MD5 checking */
84 int jte_min_size = MIN_JIGDO_FILE_SIZE;
85 struct path_match *exclude_list = NULL;
86 struct path_match *include_list = NULL;
87 struct path_mapping *map_list = NULL;
88 unsigned long long template_size = 0;
89 unsigned long long image_size = 0;
90
91 static struct mk_MD5Context iso_context;
92 static struct mk_MD5Context template_context;
93
94 /* List of files that we've seen, ready to write into the template and
95 jigdo files */
96 typedef struct _file_entry
97 {
98 unsigned char md5[16];
99 off_t file_length;
100 unsigned long long rsyncsum;
101 char *filename;
102 } file_entry_t;
103
104 typedef struct _unmatched_entry
105 {
106 off_t uncompressed_length;
107 } unmatched_entry_t;
108
109 typedef struct _entry
110 {
111 int entry_type; /* JTET_TYPE as above */
112 struct _entry *next;
113 union
114 {
115 file_entry_t file;
116 unmatched_entry_t chunk;
117 } data;
118 } entry_t;
119
120 typedef struct _jigdo_file_entry
121 {
122 unsigned char type;
123 unsigned char fileLen[6];
124 unsigned char fileRsync[8];
125 unsigned char fileMD5[16];
126 } jigdo_file_entry_t;
127
128 typedef struct _jigdo_chunk_entry
129 {
130 unsigned char type;
131 unsigned char skipLen[6];
132 } jigdo_chunk_entry_t;
133
134 typedef struct _jigdo_image_entry
135 {
136 unsigned char type;
137 unsigned char imageLen[6];
138 unsigned char imageMD5[16];
139 unsigned char blockLen[4];
140 } jigdo_image_entry_t;
141
142 typedef struct _md5_list_entry
143 {
144 struct _md5_list_entry *next;
145 unsigned char MD5[16];
146 unsigned long long size;
147 char *filename;
148 } md5_list_entry_t;
149
150 entry_t *entry_list = NULL;
151 entry_t *entry_last = NULL;
152 FILE *t_file = NULL;
153 FILE *j_file = NULL;
154 int num_matches = 0;
155 int num_chunks = 0;
156 md5_list_entry_t *md5_list = NULL;
157 md5_list_entry_t *md5_last = NULL;
158
159 /* Grab the file component from a full path */
160 static char *file_base_name(char *path)
161 {
162 char *endptr = path;
163 char *ptr = path;
164
165 while (*ptr != '\0')
166 {
167 if ('/' == *ptr)
168 endptr = ++ptr;
169 else
170 ++ptr;
171 }
172 return endptr;
173 }
174
175 /* Dump a buffer in hex */
176 static char *hex_dump(unsigned char *buf, size_t buf_size)
177 {
178 unsigned int i;
179 static char output_buffer[2048];
180 char *p = output_buffer;
181
182 memset(output_buffer, 0, sizeof(output_buffer));
183 if (buf_size >= (sizeof(output_buffer) / 2))
184 {
185 fprintf(stderr, "hex_dump: Buffer too small!\n");
186 exit(1);
187 }
188
189 for (i = 0; i < buf_size ; i++)
190 p += sprintf(p, "%2.2x", buf[i]);
191
192 return output_buffer;
193 }
194
195 /* Build the list of exclusion regexps */
196 extern int jte_add_exclude(char *pattern)
197 {
198 struct path_match *new = NULL;
199
200 new = malloc(sizeof *new);
201 if (!new)
202 return ENOMEM;
203
204 regcomp(&new->match_pattern, pattern, REG_NEWLINE);
205 new->match_rule = pattern;
206
207 /* Order on the exclude list doesn't matter! */
208 if (NULL != exclude_list)
209 new->next = exclude_list;
210
211 exclude_list = new;
212 return 0;
213 }
214
215 /* Check if the file should be excluded because of a filename match. 1
216 means exclude, 0 means not */
217 static int check_exclude_by_name(char *filename, char **matched)
218 {
219 struct path_match *ptr = exclude_list;
220 regmatch_t pmatch[1];
221 int i = 0;
222
223 while (ptr)
224 {
225 if (!regexec(&ptr->match_pattern, filename, 1, pmatch, 0))
226 {
227 *matched = ptr->match_rule;
228 return 1;
229 }
230 ptr = ptr->next;
231 }
232
233 /* Not matched, so return 0 */
234 return 0;
235 }
236
237 /* Build the list of required inclusion regexps */
238 extern int jte_add_include(char *pattern)
239 {
240 struct path_match *new = NULL;
241
242 new = malloc(sizeof *new);
243 if (!new)
244 return ENOMEM;
245
246 regcomp(&new->match_pattern, pattern, REG_NEWLINE);
247 new->match_rule = pattern;
248
249 /* Order on the include list doesn't matter! */
250 if (NULL != include_list)
251 new->next = include_list;
252
253 include_list = new;
254 return 0;
255 }
256
257 /* Check if a file has to be MD5-matched to be valid. If we get called
258 here, we've failed to match any of the MD5 entries we were
259 given. If the path to the filename matches one of the paths in our
260 list, clearly it must have been corrupted. Abort with an error. */
261 static void check_md5_file_match(char *filename)
262 {
263 struct path_match *ptr = include_list;
264 regmatch_t pmatch[1];
265 int i = 0;
266
267 while (ptr)
268 {
269 if (!regexec(&ptr->match_pattern, filename, 1, pmatch, 0))
270 {
271 #ifdef USE_LIBSCHILY
272 comerr("File %s should have matched an MD5 entry, but didn't! (Rule '%s')\n", filename, ptr->match_rule);
273 #else
274 fprintf(stderr, "File %s should have matched an MD5 entry, but didn't! (Rule '%s')\n", filename, ptr->match_rule);
275 exit(1);
276 #endif
277 }
278 ptr = ptr->next;
279 }
280 }
281
282 /* Should we list a file separately in the jigdo output, or should we
283 just dump it into the template file as binary data? Three things
284 cases to look for here:
285
286 1. Small files are better simply folded in, as they take less space that way.
287
288 2. Files in /doc (for example) may change in the archive all the
289 time and it's better to not have to fetch snapshot copies if we
290 can avoid it.
291
292 3. Files living in specified paths *must* match an entry in the
293 md5-list, or they must have been corrupted. If we find a corrupt
294 file, bail out with an error.
295
296 */
297 extern int list_file_in_jigdo(char *filename, off_t size, char **realname, unsigned char md5[16])
298 {
299 char *matched_rule;
300 md5_list_entry_t *entry = md5_list;
301 int md5sum_done = 0;
302
303 if (!jtemplate_out)
304 return 0;
305
306 memset(md5, 0, sizeof(md5));
307
308 /* Cheaper to check file size first */
309 if (size < jte_min_size)
310 {
311 if (verbose > 0)
312 fprintf(stderr, "Jigdo-ignoring file %s; it's too small\n", filename);
313 return 0;
314 }
315
316 /* Now check the excluded list by name */
317 if (check_exclude_by_name(filename, &matched_rule))
318 {
319 if (verbose > 0)
320 fprintf(stderr, "Jigdo-ignoring file %s; it's covered in the exclude list by \"%s\"\n", filename, matched_rule);
321 return 0;
322 }
323
324 /* Check to see if the file is in our md5 list. Check three things:
325
326 1. the size
327 2. the filename
328 3. (only if the first 2 match) the md5sum
329
330 If we get a match for all three, include the file and return
331 the full path to the file that we have gleaned from the mirror.
332 */
333
334 while (entry)
335 {
336 if (size == entry->size)
337 {
338 if (!strcmp(file_base_name(filename), file_base_name(entry->filename)))
339 {
340 if (!md5sum_done)
341 {
342 calculate_md5sum(filename, size, md5);
343 md5sum_done = 1;
344 }
345 if (!memcmp(md5, entry->MD5, sizeof(entry->MD5)))
346 {
347 *realname = entry->filename;
348 return 1;
349 }
350 }
351 }
352 entry = entry->next;
353 }
354
355 /* We haven't found an entry in our MD5 list to match this
356 * file. If we should have done, complain and bail out. */
357 check_md5_file_match(filename);
358 return 0;
359 }
360
361 /* Add a mapping of pathnames (e.g. Debian=/mirror/debian). We should
362 be passed TO=FROM here */
363 extern int jte_add_mapping(char *arg)
364 {
365 int error = 0;
366 struct path_mapping *new = NULL;
367 struct path_mapping *entry = NULL;
368 char *p = arg;
369 char *from = NULL;
370 char *to = NULL;
371
372 /* Find the "=" in the string passed. Set it to NULL and we can
373 use the string in-place */
374 while (*p)
375 {
376 if ('=' == *p)
377 {
378 *p = 0;
379 p++;
380 to = arg;
381 from = p;
382 }
383 p++;
384 }
385 if (!from || !strlen(from) || !to || !strlen(to))
386 return EINVAL;
387
388 new = malloc(sizeof(*new));
389 if (!new)
390 return ENOMEM;
391
392 new->from = from;
393 new->to = to;
394 new->next = NULL;
395
396 if (verbose > 0)
397 fprintf(stderr, "Adding mapping from %s to %s for the jigdo file\n", from, to);
398 if (!map_list)
399 map_list = new;
400 else
401 {
402 /* Order is important; add to the end of the list */
403 entry = map_list;
404 while (NULL != entry->next)
405 entry = entry->next;
406 entry->next = new;
407 }
408 return 0;
409 }
410
411 /* Check if the filename should be remapped; if so map it, otherwise
412 return the original name. */
413 static char *remap_filename(char *filename)
414 {
415 char *new_name = filename;
416 struct path_mapping *entry = map_list;
417
418 while (entry)
419 {
420 if (!strncmp(filename, entry->from, strlen(entry->from)))
421 {
422 new_name = calloc(1, 2 + strlen(filename) + strlen(entry->to) - strlen(entry->from));
423 if (!new_name)
424 {
425 fprintf(stderr, "Failed to malloc new filename; abort!\n");
426 exit(1);
427 }
428 sprintf(new_name, "%s:%s", entry->to, &filename[strlen(entry->from)]);
429 return new_name;
430 }
431 entry = entry->next;
432 }
433
434 /* No mapping in effect */
435 return strdup(filename);
436 }
437
438 /* Write data to the template file and update the MD5 sum */
439 static size_t template_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
440 {
441 mk_MD5Update(&template_context, ptr, size * nmemb);
442 template_size += (unsigned long long)size * nmemb;
443 return fwrite(ptr, size, nmemb, stream);
444 }
445
446 /* Create a new template file and initialise it */
447 static void write_template_header()
448 {
449 char buf[2048];
450 int i = 0;
451 char *p = buf;
452
453 memset(buf, 0, sizeof(buf));
454
455 mk_MD5Init(&template_context);
456 i += sprintf(p, "JigsawDownload template %s %s/%d.%d \r\n",
457 JIGDO_TEMPLATE_VERSION, JTE_NAME, JTE_VER_MAJOR, JTE_VER_MINOR);
458 p = &buf[i];
459
460 i += sprintf(p, "%s \r\n", JTE_COMMENT);
461 p = &buf[i];
462
463 i += sprintf(p, "\r\n");
464 template_fwrite(buf, i, 1, t_file);
465 }
466
467 /* Read the MD5 list and build a list in memory for us to use later */
468 static void add_md5_entry(unsigned char *md5, unsigned long long size, char *filename)
469 {
470 int error = 0;
471 md5_list_entry_t *new = NULL;
472
473 new = calloc(1, sizeof(md5_list_entry_t));
474 memcpy(new->MD5, md5, sizeof(new->MD5));
475 new->size = size;
476 new->filename = strdup(filename);
477
478 /* Add to the end of the list */
479 if (NULL == md5_last)
480 {
481 md5_last = new;
482 md5_list = new;
483 }
484 else
485 {
486 md5_last->next = new;
487 md5_last = new;
488 }
489 }
490
491 /* Parse a 12-digit decimal number */
492 static unsigned long long parse_number(unsigned char in[12])
493 {
494 unsigned long long size = 0;
495 int i = 0;
496
497 for (i = 0; i < 12; i++)
498 {
499 size *= 10;
500 if (isdigit(in[i]))
501 size += (in[i] - '0');
502 }
503
504 return size;
505 }
506
507 /* Read the MD5 list and build a list in memory for us to use later
508 MD5 list format:
509
510 <---MD5---> <--Size--> <--Filename-->
511 32 12 remaining
512 */
513 static void parse_md5_list(void)
514 {
515 FILE *md5_file = NULL;
516 unsigned char buf[1024];
517 unsigned char md5[16];
518 char *filename = NULL;
519 unsigned char *numbuf = NULL;
520 int num_files = 0;
521 unsigned long long size = 0;
522
523 md5_file = fopen(jmd5_list, "rb");
524 if (!md5_file)
525 {
526 #ifdef USE_LIBSCHILY
527 comerr("cannot read from MD5 list file '%s'\n", jmd5_list);
528 #else
529 fprintf(stderr, "cannot read from MD5 list file '%s'\n", jmd5_list);
530 exit(1);
531 #endif
532 }
533
534 memset(buf, 0, sizeof(buf));
535 while (fgets(buf, sizeof(buf), md5_file))
536 {
537 numbuf = &buf[34];
538 filename = &buf[48];
539 /* Lose the trailing \n from the fgets() call */
540 if (buf[strlen(buf)-1] == '\n')
541 buf[strlen(buf)-1] = 0;
542
543 if (mk_MD5Parse(buf, md5))
544 {
545 #ifdef USE_LIBSCHILY
546 comerr("cannot parse MD5 file '%s'\n", jmd5_list);
547 #else
548 fprintf(stderr, "cannot parse MD5 file '%s'\n", jmd5_list);
549 exit(1);
550 #endif
551 }
552 size = parse_number(numbuf);
553 add_md5_entry(md5, size, filename);
554 memset(buf, 0, sizeof(buf));
555 num_files++;
556 }
557 if (verbose > 0)
558 fprintf(stderr, "parse_md5_list: added MD5 checksums for %d files\n", num_files);
559 fclose(md5_file);
560 }
561
562 /* Initialise state and start the jigdo template file */
563 void write_jt_header(FILE *template_file, FILE *jigdo_file)
564 {
565 t_file = template_file;
566 j_file = jigdo_file;
567
568 /* Start MD5 work for the image */
569 mk_MD5Init(&iso_context);
570
571 /* Start the template file */
572 write_template_header();
573
574 /* Load up the MD5 list if we've been given one */
575 if (jmd5_list)
576 parse_md5_list();
577 }
578
579 /* Compress and flush out a buffer full of template data */
580 static void flush_gzip_chunk(void *buffer, off_t size)
581 {
582 z_stream c_stream; /* compression stream */
583 unsigned char comp_size_out[6];
584 unsigned char uncomp_size_out[6];
585 off_t compressed_size_out = 0;
586 int err = 0;
587 unsigned char *comp_buf = NULL;
588
589 c_stream.zalloc = NULL;
590 c_stream.zfree = NULL;
591 c_stream.opaque = NULL;
592
593 err = deflateInit(&c_stream, Z_BEST_COMPRESSION);
594 comp_buf = malloc(2 * size); /* Worst case */
595 c_stream.next_out = comp_buf;
596 c_stream.avail_out = 2 * size;
597 c_stream.next_in = buffer;
598 c_stream.avail_in = size;
599
600 err = deflate(&c_stream, Z_NO_FLUSH);
601 err = deflate(&c_stream, Z_FINISH);
602
603 compressed_size_out = c_stream.total_out + 16;
604 err = deflateEnd(&c_stream);
605
606 template_fwrite("DATA", 4, 1, t_file);
607
608 write_le48(compressed_size_out, &comp_size_out[0]);
609 template_fwrite(comp_size_out, sizeof(comp_size_out), 1, t_file);
610
611 write_le48(size, &uncomp_size_out[0]);
612 template_fwrite(uncomp_size_out, sizeof(uncomp_size_out), 1, t_file);
613
614 template_fwrite(comp_buf, c_stream.total_out, 1, t_file);
615 free(comp_buf);
616 }
617
618 #ifdef BZ2_SUPPORT
619 /* Compress and flush out a buffer full of template data */
620 static void flush_bz2_chunk(void *buffer, off_t size)
621 {
622 bz_stream c_stream; /* compression stream */
623 unsigned char comp_size_out[6];
624 unsigned char uncomp_size_out[6];
625 off_t compressed_size_out = 0;
626 int err = 0;
627 unsigned char *comp_buf = NULL;
628
629 c_stream.bzalloc = NULL;
630 c_stream.bzfree = NULL;
631 c_stream.opaque = NULL;
632
633 err = BZ2_bzCompressInit(&c_stream, 9, 0, 0);
634 comp_buf = malloc(2 * size); /* Worst case */
635 c_stream.next_out = comp_buf;
636 c_stream.avail_out = 2 * size;
637 c_stream.next_in = buffer;
638 c_stream.avail_in = size;
639
640 err = BZ2_bzCompress(&c_stream, BZ_FINISH);
641
642 compressed_size_out = c_stream.total_out_lo32 + 16;
643 err = BZ2_bzCompressEnd(&c_stream);
644
645 template_fwrite("DATA", 4, 1, t_file);
646
647 write_le48(compressed_size_out, &comp_size_out[0]);
648 template_fwrite(comp_size_out, sizeof(comp_size_out), 1, t_file);
649
650 write_le48(size, &uncomp_size_out[0]);
651 template_fwrite(uncomp_size_out, sizeof(uncomp_size_out), 1, t_file);
652
653 template_fwrite(comp_buf, c_stream.total_out_lo32, 1, t_file);
654 free(comp_buf);
655 }
656 #endif
657
658 static void flush_compressed_chunk(void *buffer, off_t size)
659 {
660 #ifdef BZ2_SUPPORT
661 if (use_bz2)
662 flush_bz2_chunk(buffer, size);
663 else
664 #endif
665 flush_gzip_chunk(buffer, size);
666 }
667
668 /* Append to an existing data buffer, and compress/flush it if
669 necessary */
670 static void write_compressed_chunk(unsigned char *buffer, size_t size)
671 {
672 static unsigned char uncomp_buf[1024 * 1024];
673 static size_t uncomp_buf_used = 0;
674
675 if ((uncomp_buf_used + size) > sizeof(uncomp_buf))
676 {
677 flush_compressed_chunk(uncomp_buf, uncomp_buf_used);
678 uncomp_buf_used = 0;
679 }
680
681 if (!size) /* Signal a flush before we start writing the DESC entry */
682 {
683 flush_compressed_chunk(uncomp_buf, uncomp_buf_used);
684 return;
685 }
686
687 if (!uncomp_buf_used)
688 memset(uncomp_buf, 0, sizeof(uncomp_buf));
689
690 while (size > sizeof(uncomp_buf))
691 {
692 flush_compressed_chunk(buffer, sizeof(uncomp_buf));
693 buffer += sizeof(uncomp_buf);
694 size -= sizeof(uncomp_buf);
695 }
696 memcpy(&uncomp_buf[uncomp_buf_used], buffer, size);
697 uncomp_buf_used += size;
698 }
699
700 /* Loop through the list of DESC entries that we've built up and
701 append them to the template file */
702 static void write_template_desc_entries(off_t image_len, char *image_md5)
703 {
704 entry_t *entry = entry_list;
705 off_t desc_len = 0;
706 unsigned char out_len[6];
707 jigdo_image_entry_t jimage;
708
709 desc_len = 16 /* DESC + length twice */
710 + (sizeof(jigdo_file_entry_t) * num_matches)
711 + (sizeof(jigdo_chunk_entry_t) * num_chunks)
712 + sizeof(jigdo_image_entry_t);
713
714 write_le48(desc_len, &out_len[0]);
715 write_compressed_chunk(NULL, 0);
716 template_fwrite("DESC", 4, 1, t_file);
717 template_fwrite(out_len, sizeof(out_len), 1, t_file);
718
719 while (entry)
720 {
721 switch (entry->entry_type)
722 {
723 case JTET_FILE_MATCH:
724 {
725 jigdo_file_entry_t jfile;
726 jfile.type = 6; /* Matched file */
727 write_le48(entry->data.file.file_length, &jfile.fileLen[0]);
728 write_le64(entry->data.file.rsyncsum, &jfile.fileRsync[0]);
729 memcpy(jfile.fileMD5, entry->data.file.md5, sizeof(jfile.fileMD5));
730 template_fwrite(&jfile, sizeof(jfile), 1, t_file);
731 break;
732 }
733 case JTET_NOMATCH:
734 {
735 jigdo_chunk_entry_t jchunk;
736 #ifdef BZ2_SUPPORT
737 if (use_bz2)
738 jchunk.type = 8; /* Raw data, bzipped */
739 else
740 #endif
741 jchunk.type = 2; /* Raw data, gzipped */
742 write_le48(entry->data.chunk.uncompressed_length, &jchunk.skipLen[0]);
743 template_fwrite(&jchunk, sizeof(jchunk), 1, t_file);
744 break;
745 }
746 }
747 entry = entry->next;
748 }
749
750 jimage.type = 5;
751 write_le48(image_len, &jimage.imageLen[0]);
752 memcpy(jimage.imageMD5, image_md5, sizeof(jimage.imageMD5));
753 write_le32(MIN_JIGDO_FILE_SIZE, &jimage.blockLen[0]);
754 template_fwrite(&jimage, sizeof(jimage), 1, t_file);
755 template_fwrite(out_len, sizeof(out_len), 1, t_file);
756 }
757
758 /* Dump a buffer in jigdo-style "base64" */
759 static char *base64_dump(unsigned char *buf, size_t buf_size)
760 {
761 const char *b64_enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
762 int value = 0;
763 unsigned int i;
764 int bits = 0;
765 static char output_buffer[2048];
766 char *p = output_buffer;
767
768 memset(output_buffer, 0, sizeof(output_buffer));
769 if (buf_size >= (sizeof(output_buffer) * 6/8))
770 {
771 fprintf(stderr, "base64_dump: Buffer too small!\n");
772 exit(1);
773 }
774
775 for (i = 0; i < buf_size ; i++)
776 {
777 value = (value << 8) | buf[i];
778 bits += 2;
779 p += sprintf(p, "%c", b64_enc[(value >> bits) & 63U]);
780 if (bits >= 6) {
781 bits -= 6;
782 p += sprintf(p, "%c", b64_enc[(value >> bits) & 63U]);
783 }
784 }
785 if (bits > 0)
786 {
787 value <<= 6 - bits;
788 p += sprintf(p, "%c", b64_enc[value & 63U]);
789 }
790 return output_buffer;
791 }
792
793 /* Write the .jigdo file to match the .template we've just finished. */
794 static void write_jigdo_file(void)
795 {
796 unsigned char template_md5sum[16];
797 entry_t *entry = entry_list;
798 struct path_mapping *map = map_list;
799
800 mk_MD5Final(&template_md5sum[0], &template_context);
801
802 fprintf(j_file, "# JigsawDownload\n");
803 fprintf(j_file, "# See <http://atterer.net/jigdo/> for details about jigdo\n");
804 fprintf(j_file, "# See <http://www.einval.com/~steve/software/CD/JTE/> for details about JTE\n\n");
805
806 fprintf(j_file, "[Jigdo]\n");
807 fprintf(j_file, "Version=%s\n", JIGDO_TEMPLATE_VERSION);
808 fprintf(j_file, "Generator=%s/%d.%d\n\n", JTE_NAME, JTE_VER_MAJOR, JTE_VER_MINOR);
809
810 fprintf(j_file, "[Image]\n");
811 fprintf(j_file, "Filename=%s\n", file_base_name(outfile));
812 fprintf(j_file, "Template=http://localhost/%s\n", jtemplate_out);
813 fprintf(j_file, "Template-MD5Sum=%s \n",
814 base64_dump(&template_md5sum[0], sizeof(template_md5sum)));
815 fprintf(j_file, "# Template Hex MD5sum %s\n",
816 hex_dump(&template_md5sum[0], sizeof(template_md5sum)));
817 fprintf(j_file, "# Template size %lld bytes\n", template_size);
818 fprintf(j_file, "# Image size %lld bytes\n\n", image_size);
819
820 fprintf(j_file, "[Parts]\n");
821 while (entry)
822 {
823 if (JTET_FILE_MATCH == entry->entry_type)
824 {
825 char *new_name = remap_filename(entry->data.file.filename);
826 fprintf(j_file, "%s=%s\n",
827 base64_dump(&entry->data.file.md5[0], sizeof(entry->data.file.md5)),
828 new_name);
829 free(new_name);
830 }
831 entry = entry->next;
832 }
833
834 fprintf(j_file, "\n[Servers]\n");
835 fflush(j_file);
836 }
837
838 /* Finish and flush state; for now:
839
840 1. Dump the DESC blocks and the footer information in the jigdo template file
841 2. Write the jigdo .jigdo file containing file pointers
842 */
843 void write_jt_footer(void)
844 {
845 unsigned char md5[16]; /* MD5SUM of the entire image */
846
847 /* Finish calculating the image's checksum */
848 mk_MD5Final(&md5[0], &iso_context);
849
850 /* And calculate the image size */
851 image_size = (unsigned long long)SECTOR_SIZE * last_extent_written;
852
853 write_template_desc_entries(image_size, md5);
854
855 write_jigdo_file();
856 }
857
858 /* Add a raw data entry to the list of extents; no file to match */
859 static void add_unmatched_entry(int uncompressed_length)
860 {
861 entry_t *new_entry = NULL;
862
863 /* Can we extend a previous non-match entry? */
864 if (entry_last && (JTET_NOMATCH == entry_last->entry_type))
865 {
866 entry_last->data.chunk.uncompressed_length += uncompressed_length;
867 return;
868 }
869
870 new_entry = calloc(1, sizeof(entry_t));
871 new_entry->entry_type = JTET_NOMATCH;
872 new_entry->next = NULL;
873 new_entry->data.chunk.uncompressed_length = uncompressed_length;
874
875 /* Add to the end of the list */
876 if (NULL == entry_last)
877 {
878 entry_last = new_entry;
879 entry_list = new_entry;
880 }
881 else
882 {
883 entry_last->next = new_entry;
884 entry_last = new_entry;
885 }
886 num_chunks++;
887 }
888
889 /* Add a file match entry to the list of extents */
890 static void add_file_entry(char *filename, off_t size, unsigned char *md5,
891 unsigned long long rsyncsum)
892 {
893 entry_t *new_entry = NULL;
894
895 new_entry = calloc(1, sizeof(entry_t));
896 new_entry->entry_type = JTET_FILE_MATCH;
897 new_entry->next = NULL;
898 memcpy(new_entry->data.file.md5, md5, sizeof(new_entry->data.file.md5));
899 new_entry->data.file.file_length = size;
900 new_entry->data.file.rsyncsum = rsyncsum;
901 new_entry->data.file.filename = strdup(filename);
902
903 /* Add to the end of the list */
904 if (NULL == entry_last)
905 {
906 entry_last = new_entry;
907 entry_list = new_entry;
908 }
909 else
910 {
911 entry_last->next = new_entry;
912 entry_last = new_entry;
913 }
914 num_matches++;
915 }
916
917 /* Cope with an unmatched block in the .iso file:
918
919 1. Write a compressed data chunk in the jigdo template file
920 2. Add an entry in our list of unmatched chunks for later */
921 void jtwrite(buffer, size, count, submode, islast)
922 void *buffer;
923 int size;
924 int count;
925 int submode;
926 BOOL islast;
927 {
928 #ifdef JTWRITE_DEBUG
929 if (count != 1 || (size % 2048) != 0)
930 fprintf(stderr, "Count: %d, size: %d\n", count, size);
931 #endif
932
933 if (!jtemplate_out)
934 return;
935
936 /* Update the global image checksum */
937 mk_MD5Update(&iso_context, buffer, size*count);
938
939 /* Write a compressed version of the data to the template file,
940 and add a reference on the state list so we can write that
941 later. */
942 write_compressed_chunk(buffer, size*count);
943 add_unmatched_entry(size*count);
944 }
945
946 /* Cope with a file entry in the .iso file:
947
948 1. Read the file for the image's md5 checksum
949 2. Add an entry in our list of files to be written into the .jigdo later
950 */
951 void write_jt_match_record(char *filename, char *mirror_name, int sector_size, off_t size, unsigned char md5[16])
952 {
953 unsigned long long tmp_size = 0;
954 char buf[32768];
955 off_t remain = size;
956 FILE *infile = NULL;
957 int use = 0;
958 unsigned long long rsync64_sum = 0;
959 int first_block = 1;
960
961 memset(buf, 0, sizeof(buf));
962
963 if ((infile = fopen(filename, "rb")) == NULL) {
964 #ifdef USE_LIBSCHILY
965 comerr("cannot open '%s'\n", filename);
966 #else
967 #ifndef HAVE_STRERROR
968 fprintf(stderr, "cannot open '%s': (%d)\n",
969 filename, errno);
970 #else
971 fprintf(stderr, "cannot open '%s': %s\n",
972 filename, strerror(errno));
973 #endif
974 exit(1);
975 #endif
976 }
977
978 while (remain > 0)
979 {
980 use = remain;
981 if (remain > sizeof(buf))
982 use = sizeof(buf);
983 if (fread(buf, 1, use, infile) == 0)
984 {
985 #ifdef USE_LIBSCHILY
986 comerr("cannot read from '%s'\n", filename);
987 #else
988 fprintf(stderr, "cannot read from '%s'\n", filename);
989 exit(1);
990 #endif
991 }
992 if (first_block)
993 rsync64_sum = rsync64(buf, MIN_JIGDO_FILE_SIZE);
994 mk_MD5Update(&iso_context, buf, use);
995 remain -= use;
996 first_block = 0;
997 }
998
999 fclose(infile);
1000
1001 /* Update the image checksum with any necessary padding data */
1002 if (size % sector_size)
1003 {
1004 int pad_size = sector_size - (size % sector_size);
1005 memset(buf, 0, pad_size);
1006 mk_MD5Update(&iso_context, buf, pad_size);
1007 }
1008
1009 add_file_entry(mirror_name, size, &md5[0], rsync64_sum);
1010 if (size % sector_size)
1011 {
1012 int pad_size = sector_size - (size % sector_size);
1013 write_compressed_chunk(buf, pad_size);
1014 add_unmatched_entry(pad_size);
1015 }
1016 }

  ViewVC Help
Powered by ViewVC 1.1.5