"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libjte/jte.c" (30 Jan 2021, 43378 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "jte.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.5.2_vs_1.5.4.

    1 /*
    2  * jte.c
    3  *
    4  * 
    5  * Copyright (c) 2004-2019 Steve McIntyre <steve@einval.com>
    6  * Copyright (c) 2010-2011 Thomas Schmitt <scdbackup@gmx.net>
    7  * Copyright (c) 2010-2011 George Danchev <danchev@spnet.net>
    8  * 
    9  * These routines were originally implemented by 
   10  * Steve McIntyre <steve@einval.com>. 
   11  * More recently few tweaks and additions were applied by 
   12  * Thomas Schmitt <scdbackup@gmx.net> and
   13  * George Danchev <danchev@spnet.net>
   14  * Updated by Steve to add more generic checksum support, first for sha256
   15  * 
   16  * Implementation of the Jigdo Template Engine - make jigdo files
   17  * directly when making ISO images
   18  *
   19  * GNU GPL v2+
   20  */
   21 
   22 #ifdef HAVE_CONFIG_H
   23 #include "../config.h"
   24 #endif
   25 
   26 #ifdef HAVE_STDINT_H
   27 #include <stdint.h>
   28 #else
   29 #ifdef HAVE_INTTYPES_H
   30 #include <inttypes.h>
   31 #endif
   32 #endif
   33 
   34 #include <string.h>
   35 #include <stdlib.h>
   36 
   37 #ifdef LIBJTE_WITH_ZLIB
   38 #include <zlib.h>
   39 #endif
   40 
   41 #ifdef LIBJTE_WITH_LIBBZ2
   42 #include <bzlib.h>
   43 #endif
   44 
   45 #include <sys/types.h>
   46 #include <ctype.h>
   47 #include <errno.h>
   48 #include "jte.h"
   49 #include "checksum.h"
   50 #include "endianconv.h"
   51 #include "rsync.h"
   52 #include "libjte_private.h"
   53 #include "libjte.h"
   54 
   55 /* Different types used in building our state list below */
   56 #define JTET_FILE_MATCH 1
   57 #define JTET_NOMATCH    2
   58 
   59 #define JTE_VER_MAJOR     0x0002
   60 #define JTE_VER_MINOR     0x0000
   61 #define JTE_NAME          "JTE"
   62 #define JTE_COMMENT       "JTE at https://www.einval.com/~steve/software/JTE/ ; Jigdo at https://www.einval.com/~steve/software/jigdo/"
   63 
   64 #define JIGDO_TEMPLATE_VERSION_MD5    "1.1"
   65 #define JIGDO_TEMPLATE_VERSION_SHA256 "2.0"
   66 
   67 #define JTE_MAX_ERROR_LIST_LENGTH 20
   68 
   69 /* The various type of jigdo descriptor */
   70 enum _jigdo_desc_type {
   71     JDT_OBSOLETE_IMAGE_INFO = 1,
   72     JDT_UNMATCHED_DATA = 2,
   73     JDT_OBSOLETE_MATCHED_FILE = 3,
   74     JDT_OBSOLETE_WRITTEN_FILE = 4,
   75     JDT_IMAGE_INFO_MD5 = 5,
   76     JDT_MATCHED_FILE_MD5 = 6,
   77     JDT_WRITTEN_FILE_MD5 = 7,
   78     JDT_IMAGE_INFO_SHA256 = 8,
   79     JDT_MATCHED_FILE_SHA256 = 9,
   80     JDT_WRITTEN_FILE_SHA256 = 10
   81 };
   82 
   83 /* Grab the file component from a full path */
   84 static char *file_base_name(char *path)
   85 {
   86     char *endptr = path;
   87     char *ptr = path;
   88     
   89     while (*ptr != '\0')
   90     {
   91         if ('/' == *ptr)
   92             endptr = ++ptr;
   93         else
   94             ++ptr;
   95     }
   96     return endptr;
   97 }
   98 
   99 static void exit_if_enabled(struct libjte_env *o, int value)
  100 {
  101     if (!(o->error_behavior & 2))
  102         return;
  103     libjte_clear_msg_list(o, 1);
  104     exit(value);
  105 }
  106 
  107 int libjte_report_no_mem(struct libjte_env *o, size_t size, int flag)
  108 {
  109     sprintf(o->message_buffer, "Out of memory for %.f new bytes",
  110             (double) size);
  111     libjte_add_msg_entry(o, o->message_buffer, 0);
  112     return -1;
  113 }
  114 
  115 /* @param flag bit0-7 = mode
  116                         0= include_list
  117                         1= exclude_list
  118 */
  119 static int jte_add_path_match(struct libjte_env *o, char *pattern, int flag)
  120 {
  121     struct path_match *new = NULL, **old;
  122     int mode;
  123 
  124     mode = flag & 255;
  125     if (mode == 0)
  126         old = &(o->include_list);
  127     else
  128         old = &(o->exclude_list);
  129 
  130     new = malloc(sizeof *new);
  131     if (new == NULL)
  132         return libjte_report_no_mem(o, sizeof *new, 0);
  133     
  134     regcomp(&new->match_pattern, pattern, REG_NEWLINE);
  135     new->match_rule = strdup(pattern);
  136     if (new->match_rule == NULL)
  137         return libjte_report_no_mem(o, sizeof *new, 0);
  138 
  139     /* Order on the list doesn't matter! */
  140     new->next = *old;
  141 
  142     *old = new;
  143     return 0;
  144 }
  145 
  146 /* @param flag bit0-7 = mode
  147                         0= include_list
  148                         1= exclude_list
  149 */
  150 int libjte_destroy_path_match_list(struct libjte_env *o, int flag)
  151 {
  152     struct path_match **old, *s, *s_next;
  153     int mode;
  154 
  155     mode = flag & 255;
  156     if (mode == 0)
  157         old = &(o->include_list);
  158     else
  159         old = &(o->exclude_list);
  160     for (s = *old; s != NULL; s = s_next) {
  161         s_next = s->next;
  162         regfree(&(s->match_pattern));
  163         free(s->match_rule);
  164         free(s);
  165     }
  166     *old = NULL;
  167     return 1;
  168 }
  169 
  170 /* Build the list of exclusion regexps */
  171 int jte_add_exclude(struct libjte_env *o, char *pattern)
  172 {
  173     int ret;
  174     
  175     ret = jte_add_path_match(o, pattern, 1);
  176     return ret;
  177 }
  178 
  179 /* Check if the file should be excluded because of a filename match. 1
  180    means exclude, 0 means not */
  181 static int check_exclude_by_name(struct libjte_env *o,
  182                                  char *filename, char **matched)
  183 {
  184     struct path_match *ptr = o->exclude_list;
  185     regmatch_t pmatch[1];
  186 
  187     while (ptr)
  188     {
  189         if (!regexec(&ptr->match_pattern, filename, 1, pmatch, 0))
  190         {
  191             *matched = ptr->match_rule;
  192             return 1;
  193         }
  194         ptr = ptr->next;
  195     }
  196     
  197     /* Not matched, so return 0 */
  198     return 0;
  199 }
  200 
  201 /* Build the list of required inclusion regexps */
  202 int jte_add_include(struct libjte_env *o, char *pattern)
  203 {
  204     int ret;
  205     
  206     ret = jte_add_path_match(o, pattern, 0);
  207     return ret;
  208 }
  209 
  210 int libjte_destroy_entry_list(struct libjte_env *o, int flag)
  211 {
  212     entry_t *s, *s_next;
  213 
  214     for (s = o->entry_list ; s != NULL; s = s_next) {
  215         s_next = s->next;
  216         if (s->entry_type == JTET_FILE_MATCH) {
  217             if (s->data.file.filename != NULL)
  218                 free(s->data.file.filename);
  219         }
  220         free(s);
  221     }
  222     o->entry_list = o->entry_last = NULL;
  223     return 1;
  224 }
  225 
  226 /* Check if a file has to be checksum-matched to be valid. If we get called
  227    here, we've failed to match any of the checksum entries we were
  228    given. If the path to the filename matches one of the paths in our
  229    list, clearly it must have been corrupted. Abort with an error. */
  230 static int check_checksum_file_match(struct libjte_env *o, char *filename)
  231 {
  232     struct path_match *ptr = o->include_list;
  233     regmatch_t pmatch[1];
  234 
  235     while (ptr)
  236     {
  237         if (!regexec(&ptr->match_pattern, filename, 1, pmatch, 0))
  238         {
  239             sprintf(o->message_buffer,
  240                 "File %1.1024s should have matched a checksum entry, but didn't! (Rule '%1.1024s')",
  241                 filename, ptr->match_rule);
  242             libjte_add_msg_entry(o, o->message_buffer, 0);
  243             exit_if_enabled(o, 1);
  244             return -1;
  245     }
  246         ptr = ptr->next;
  247     }
  248     return 0;
  249 }    
  250 
  251 /* Should we list a file separately in the jigdo output, or should we
  252    just dump it into the template file as binary data? Three things
  253    cases to look for here:
  254 
  255    1. Small files are better simply folded in, as they take less space that way.
  256 
  257    2. Files in /doc (for example) may change in the archive all the
  258       time and it's better to not have to fetch snapshot copies if we
  259       can avoid it.      
  260 
  261    3. Files living in specified paths *must* match an entry in the
  262       checksum-list, or they must have been corrupted. If we find a
  263       corrupt file, bail out with an error.
  264 
  265 */
  266 int list_file_in_jigdo(struct libjte_env *o,
  267                        char *filename, off_t size,
  268                        char **realname, unsigned char *checksum)
  269 {
  270     char *matched_rule;
  271     checksum_list_entry_t *entry = o->checksum_list;
  272     int checksum_done = 0, ret;
  273     
  274     if (o->jtemplate_out == NULL)
  275         return 0;
  276 
  277     memset(checksum, 0, check_algos[o->checksum_algo].raw_bytes);
  278 
  279     /* Cheaper to check file size first */
  280     if (size < o->jte_min_size)
  281     {
  282         if (o->verbose > 1) {
  283             sprintf(o->message_buffer,
  284                    "Jigdo-ignoring file %1.1024s; it's too small", filename);
  285             libjte_add_msg_entry(o, o->message_buffer, 0);
  286         }
  287         return 0;
  288     }
  289     
  290     /* Now check the excluded list by name */
  291     if (check_exclude_by_name(o, filename, &matched_rule))
  292     {
  293         if (o->verbose > 1) {
  294             sprintf(o->message_buffer,
  295                     "Jigdo-ignoring file %1.1024s; it's covered in the exclude list by \"%1.1024s\"",
  296                     filename, matched_rule);
  297             libjte_add_msg_entry(o, o->message_buffer, 0);
  298         }
  299         return 0;
  300     }
  301 
  302     /* Check to see if the file is in our checksum list. Check three things:
  303        
  304        1. the size
  305        2. the filename
  306        3. (only if the first 2 match) the checksum
  307 
  308        If we get a match for all three, include the file and return
  309        the full path to the file that we have gleaned from the mirror.
  310     */
  311 
  312     while (entry)
  313     {
  314         if (size == (off_t)entry->size)
  315         {
  316             if (!strcmp(file_base_name(filename), file_base_name(entry->filename)))
  317             {
  318                 if (!checksum_done)
  319                 {
  320                     ret = checksum_calculate(filename, size,
  321                                              checksum, check_algos[o->checksum_algo].type);
  322                     if (ret < 0) { /* (0 is success) */
  323                         sprintf(o->message_buffer,
  324                                 "Error with file '%1.1024s' : errno=%d",
  325                                 filename, errno);
  326                         libjte_add_msg_entry(o, o->message_buffer, 0);
  327                         return -1;
  328                     }
  329                     checksum_done = 1;
  330                 }
  331                 if (!memcmp(checksum, entry->checksum, check_algos[o->checksum_algo].raw_bytes))
  332                 {
  333                     *realname = entry->filename;
  334                     return 1;
  335                 }
  336             }
  337         }
  338         entry = entry->next;
  339     }
  340 
  341     /* We haven't found an entry in our checksum list to match this
  342      * file. If we should have done, complain and bail out. */
  343     ret = check_checksum_file_match(o, filename);
  344     return ret;
  345 }
  346 
  347 /* Add a mapping of pathnames (e.g. Debian=/mirror/debian). We should
  348    be passed TO=FROM here */
  349 int jte_add_mapping(struct libjte_env *o, char *arg)
  350 {
  351     struct path_mapping *new = NULL;
  352     struct path_mapping *entry = NULL;
  353     char *p = arg;
  354     char *from = NULL;
  355     char *to = NULL;
  356     char *eqpt = NULL;
  357 
  358     /* Find the "=" in the string passed. */
  359     while (*p)
  360     {
  361         if ('=' == *p)
  362         {
  363             if (eqpt == NULL)
  364                 eqpt = p;
  365             p++;
  366             from = p;
  367             break;
  368         }
  369         p++;
  370     }
  371     if (from == NULL || !strlen(from) || eqpt == arg)
  372         return EINVAL;
  373     from = strdup(from);
  374     if (from == NULL)
  375         return ENOMEM;
  376     to = calloc(1, (eqpt - arg) + 1);
  377     if (to == NULL) {
  378         free(from);
  379         return ENOMEM;
  380     }
  381     strncpy(to, arg, eqpt - arg);
  382     to[eqpt - arg] = 0;
  383     
  384     new = malloc(sizeof(*new));
  385     if (!new) {
  386         free(to);
  387         free(from);
  388         return ENOMEM;
  389     }
  390     new->from = from;
  391     new->to = to;
  392     new->next = NULL;
  393 
  394     if (o->verbose > 0) {
  395         sprintf(o->message_buffer,
  396                 "Adding mapping from %1.1024s to %1.1024s for the jigdo file",
  397                 from, to);
  398         libjte_add_msg_entry(o, o->message_buffer, 0);
  399     }
  400     if (o->map_list == NULL)
  401         o->map_list = new;
  402     else
  403     {
  404         /* Order is important; add to the end of the list */
  405         entry = o->map_list;
  406         while (NULL != entry->next)
  407             entry = entry->next;
  408         entry->next = new;
  409     }
  410     return 0;
  411 }
  412 
  413 
  414 int libjte_destroy_path_mapping(struct libjte_env *o, int flag)
  415 {
  416     struct path_mapping *s, *s_next;
  417 
  418     for (s = o->map_list; s != NULL; s = s_next) {
  419         s_next = s->next;
  420         free(s->from);
  421         free(s->to);
  422         free(s);
  423     }
  424     o->map_list = NULL;
  425     return 1;
  426 }
  427 
  428 
  429 /* Check if the filename should be remapped; if so map it, otherwise
  430    return the original name. */
  431 static char *remap_filename(struct libjte_env *o, char *filename)
  432 {
  433     char *new_name = filename;
  434     struct path_mapping *entry = o->map_list;
  435     
  436     while (entry)
  437     {
  438         if (!strncmp(filename, entry->from, strlen(entry->from)))
  439         {
  440             new_name = calloc(1, 2 + strlen(filename) + strlen(entry->to) - strlen(entry->from));
  441             if (!new_name)
  442             {
  443                 sprintf(o->message_buffer,
  444                         "Failed to malloc new filename; abort!");
  445                 libjte_add_msg_entry(o, o->message_buffer, 0);
  446                 exit_if_enabled(o, 1);
  447                 return NULL;
  448             }
  449             sprintf(new_name, "%s:%s", entry->to, &filename[strlen(entry->from)]);
  450             return new_name;
  451         }
  452         entry = entry->next;
  453     }
  454 
  455     /* No mapping in effect */
  456     return strdup(filename);
  457 }    
  458 
  459 /* Write data to the template file and update the checksum */
  460 static int template_fwrite(struct libjte_env *o,
  461                       const void *ptr, size_t size, size_t nmemb, FILE *stream)
  462 {
  463     size_t written;
  464 
  465     checksum_update(o->template_context, ptr, size * nmemb);
  466     written = fwrite(ptr, size, nmemb, stream);
  467     o->template_size += written * size;
  468     if (written != nmemb)
  469         return 0;
  470     return 1;
  471 }
  472 
  473 /* Create a new template file and initialise it */
  474 static int write_template_header(struct libjte_env *o)
  475 {
  476     char buf[2048];
  477     int i = 0;
  478     char *p = buf;
  479 
  480 #ifndef LIBJTE_WITH_LIBBZ2
  481 
  482     if (o->jte_template_compression == JTE_TEMP_BZIP2) {
  483         sprintf(o->message_buffer,
  484             "libjte: Compression algorithm BZIP2 not enabled at compile time");
  485         libjte_add_msg_entry(o, o->message_buffer, 0);
  486         exit_if_enabled(o, 1);
  487         return -1;
  488     }
  489 
  490 #endif /* LIBJTE_WITH_LIBBZ2 */
  491 
  492     memset(buf, 0, sizeof(buf));
  493 
  494     if (o->template_context != NULL)
  495         checksum_free_context(o->template_context);
  496     o->template_context = checksum_init_context(o->checksum_algo_tmpl,
  497                                                 "template");
  498     if (o->template_context == NULL)
  499     {
  500         sprintf(o->message_buffer,
  501                 "cannot allocate template checksum contexts");
  502         libjte_add_msg_entry(o, o->message_buffer, 0);
  503         exit_if_enabled(o, 1);
  504         return -1;
  505     }
  506     
  507     if (CHECK_MD5 == check_algos[o->checksum_algo].type)
  508         i += sprintf(p, "JigsawDownload template %s libjte-%d.%d.%d \r\n",
  509                      JIGDO_TEMPLATE_VERSION_MD5, 
  510                      LIBJTE_VERSION_MAJOR, LIBJTE_VERSION_MINOR, LIBJTE_VERSION_MICRO);
  511     else /* CHECK_SHA256 */
  512         i += sprintf(p, "JigsawDownload template %s libjte-%d.%d.%d \r\n",
  513                      JIGDO_TEMPLATE_VERSION_SHA256, 
  514                      LIBJTE_VERSION_MAJOR, LIBJTE_VERSION_MINOR, LIBJTE_VERSION_MICRO);
  515     p = &buf[i];
  516 
  517     i += sprintf(p, "%s \r\n", JTE_COMMENT);
  518     p = &buf[i];
  519 
  520     i += sprintf(p, "\r\n");
  521     if (template_fwrite(o, buf, i, 1, o->t_file) <= 0)
  522         return 0;
  523     return 1;
  524 }
  525 
  526 /* Read the checksum list and build a list in memory for us to use later */
  527 static int add_checksum_entry(struct libjte_env *o,
  528                               unsigned char *checksum, uint64_t size,
  529                               char *filename)
  530 {
  531     checksum_list_entry_t *new = NULL;
  532     
  533     new = calloc(1, sizeof(checksum_list_entry_t));
  534     if (!new)
  535         return ENOMEM;
  536     new->checksum = calloc(1, check_algos[o->checksum_algo].raw_bytes);
  537     if (!new->checksum)
  538     {
  539         free(new);
  540         return ENOMEM;
  541     }
  542     memcpy(new->checksum, checksum, check_algos[o->checksum_algo].raw_bytes);
  543     new->size = size;
  544     new->filename = strdup(filename);
  545     if (!new->filename)
  546     {
  547         free(new->checksum);
  548         free(new);
  549         return ENOMEM;
  550     }
  551     
  552     /* Add to the end of the list */
  553     if (NULL == o->checksum_last)
  554     {
  555         o->checksum_last = new;
  556         o->checksum_list = new;
  557     }
  558     else
  559     {
  560         o->checksum_last->next = new;
  561         o->checksum_last = new;
  562     }
  563     return 0;
  564 }
  565 
  566 int libjte_destroy_checksum_list(struct libjte_env *o, int flag)
  567 {
  568     checksum_list_entry_t *s, *s_next;
  569 
  570     for (s = o->checksum_list; s != NULL; s = s_next) {
  571         s_next = s->next;
  572         free(s->checksum);
  573         free(s->filename);
  574         free(s);
  575     }
  576     o->checksum_list = o->checksum_last = NULL;
  577     return 1;
  578 }
  579 
  580 /* Parse a 12-digit decimal number */
  581 static uint64_t parse_number(unsigned char in[12])
  582 {
  583     uint64_t size = 0;
  584     int i = 0;
  585     
  586     for (i = 0; i < 12; i++)
  587     {
  588         size *= 10;
  589         if (isdigit(in[i]))
  590             size += (in[i] - '0');
  591     }
  592 
  593     return size;
  594 }
  595     
  596 /* Read the checksum list and build a list in memory for us to use later
  597    list format:
  598 
  599    <---checksum--->  <--Size-->  <--Filename-->
  600     XX                12          remaining
  601 
  602     We know XX (length of the checksum in hex) from the specified
  603     checksum type in our env. We explicitly check here that the
  604     entries are well-formed
  605 */
  606 static int parse_checksum_list(struct libjte_env *o)
  607 {
  608     FILE *checksum_file = NULL;
  609     unsigned char buf[1024];
  610     unsigned char *checksum;
  611     char *filename = NULL;
  612     unsigned char *numbuf = NULL;
  613     int num_files = 0;
  614     uint64_t size = 0;
  615     int i = 0;
  616     int valid = 1;
  617     int error = 0;
  618     int csum_hex_size = check_algos[o->checksum_algo].hex_bytes;
  619 
  620     if (!strcmp (o->jchecksum_list, "/dev/null"))
  621     {
  622         if (o->verbose)
  623         {
  624             sprintf(o->message_buffer, "Ignoring call with checksum list file '%1.1024s'",
  625                     o->jchecksum_list);
  626             libjte_add_msg_entry(o, o->message_buffer, 0);
  627         }
  628         return 1;
  629     }
  630 
  631     checksum = calloc(1, check_algos[o->checksum_algo].raw_bytes);
  632     if (!checksum)
  633     {
  634         sprintf(o->message_buffer, "cannot allocate memory to read from checksum list file '%1.1024s'",
  635                 o->jchecksum_list);
  636         libjte_add_msg_entry(o, o->message_buffer, 0);
  637         exit_if_enabled(o, 1);
  638         errno = ENOMEM;
  639         return -1;
  640     }
  641 
  642     checksum_file = fopen(o->jchecksum_list, "rb");
  643     if (!checksum_file)
  644     {
  645         sprintf(o->message_buffer, "cannot open checksum list file '%1.1024s'",
  646                 o->jchecksum_list);
  647         libjte_add_msg_entry(o, o->message_buffer, 0);
  648         exit_if_enabled(o, 1);
  649         return -1;
  650     }
  651 
  652     /* Validate the first line - is it using the right checksum
  653      * type? */
  654     memset(buf, 0, sizeof(buf));
  655     if(!fgets((char *)buf, sizeof(buf), checksum_file))
  656     {
  657         free(checksum);
  658         fclose(checksum_file);
  659         sprintf(o->message_buffer, "cannot read from checksum list file '%1.1024s'",
  660                 o->jchecksum_list);
  661         libjte_add_msg_entry(o, o->message_buffer, 0);
  662         exit_if_enabled(o, 1);
  663         return -1;
  664     }
  665 
  666     /* Check that we have hex digits for just the right number of
  667      * characters, followed by two spaces */
  668     for (i = 0; valid && i < csum_hex_size; i++)
  669         if (!isxdigit(buf[i]))
  670             valid = -i;
  671     if (valid > 0) {
  672         if (' ' != buf[csum_hex_size])
  673             valid = -csum_hex_size;
  674         if (' ' != buf[csum_hex_size+1])
  675             valid = -csum_hex_size - 1;
  676     }
  677     if(valid <= 0)
  678     {
  679         free(checksum);
  680         fclose(checksum_file);
  681         sprintf(o->message_buffer, "invalid checksum list file '%1.1024s' - wrong checksum type?",
  682                 o->jchecksum_list);
  683         libjte_add_msg_entry(o, o->message_buffer, 0);
  684         exit_if_enabled(o, 1);
  685         return -1;
  686     }
  687 
  688     fseek(checksum_file, 0, SEEK_SET);
  689     memset(buf, 0, sizeof(buf));
  690     while (fgets((char *)buf, sizeof(buf), checksum_file))
  691     {
  692         numbuf = &buf[csum_hex_size + 2];
  693         filename = (char *)&buf[csum_hex_size + 16];
  694         /* Lose the trailing \n from the fgets() call */
  695         if (buf[strlen((char *)buf)-1] == '\n')
  696             buf[strlen((char *)buf)-1] = 0;
  697 
  698         if (checksum_parse_hex((char *)buf, checksum, csum_hex_size))
  699         {
  700             free(checksum);
  701             fclose(checksum_file);
  702             sprintf(o->message_buffer, "cannot parse checksum file '%1.1024s'",
  703                     o->jchecksum_list);
  704             libjte_add_msg_entry(o, o->message_buffer, 0);
  705             exit_if_enabled(o, 1);
  706             return -1;
  707         }
  708         size = parse_number(numbuf);
  709 
  710         error = add_checksum_entry(o, checksum, size, filename);
  711         if (error)
  712         {
  713             free(checksum);
  714             fclose(checksum_file);
  715             sprintf(o->message_buffer, "cannot add checksum entry to list from file '%1.1024s', error %d",
  716                     o->jchecksum_list, error);
  717             libjte_add_msg_entry(o, o->message_buffer, 0);
  718             exit_if_enabled(o, 1);
  719             return -1;
  720         }
  721 
  722         memset(buf, 0, sizeof(buf));
  723         num_files++;
  724     }
  725     if (o->verbose > 0) {
  726         sprintf(o->message_buffer,
  727               "parse_checksum_list: added checksums for %d files", num_files);
  728         libjte_add_msg_entry(o, o->message_buffer, 0);
  729     }
  730     free(checksum);
  731     fclose(checksum_file);
  732     return 1;
  733 }
  734 
  735 /* Initialise state and start the jigdo template file */
  736 int write_jt_header(struct libjte_env *o,
  737                      FILE *template_file, FILE *jigdo_file)
  738 {
  739     int ret;
  740 
  741     o->t_file = template_file;
  742     o->j_file = jigdo_file;
  743 
  744     /* Start checksum work for the image */
  745     if (o->iso_context != NULL)
  746         checksum_free_context(o->iso_context);
  747     o->iso_context = checksum_init_context(o->checksum_algo_iso, "iso");
  748     if (o->iso_context == NULL)
  749     {
  750         sprintf(o->message_buffer, "cannot allocate iso checksum contexts");
  751         libjte_add_msg_entry(o, o->message_buffer, 0);
  752         exit_if_enabled(o, 1);
  753         return -1;
  754     }
  755 
  756     /* Start the template file */
  757     ret = write_template_header(o);
  758     if (ret <= 0)
  759         return ret;
  760 
  761     /* Load up the checksum list if we've been given one */
  762     if (o->jchecksum_list) {
  763         ret = parse_checksum_list(o);
  764         if (ret <= 0)
  765             return ret;
  766     }
  767     return 1;
  768 }
  769 
  770 /* Compress and flush out a buffer full of template data */
  771 /* Return 0 on failure, non-zero on success */
  772 static int flush_gzip_chunk(struct libjte_env *o, void *buffer, off_t size)
  773 {
  774 
  775 #ifdef LIBJTE_WITH_ZLIB
  776 
  777     z_stream c_stream; /* compression stream */
  778     unsigned char comp_size_out[6];
  779     unsigned char uncomp_size_out[6];
  780     off_t compressed_size_out = 0;
  781     int err = 0;
  782     unsigned char *comp_buf = NULL;
  783 
  784     c_stream.zalloc = NULL;
  785     c_stream.zfree = NULL;
  786     c_stream.opaque = NULL;
  787 
  788     err = deflateInit(&c_stream, Z_BEST_COMPRESSION);
  789     if (err < 0)
  790         return 0;
  791     
  792     if (NULL == (comp_buf = malloc(2 * size))) /* Worst case */
  793         return 0;
  794 
  795     c_stream.next_out = comp_buf;
  796     c_stream.avail_out = 2 * size;
  797     c_stream.next_in = buffer;
  798     c_stream.avail_in = size;
  799     
  800     err = deflate(&c_stream, Z_NO_FLUSH);
  801     if (err < 0)
  802     {
  803         free(comp_buf);
  804         return 0;
  805     }
  806 
  807     err = deflate(&c_stream, Z_FINISH);
  808     if (err < 0)
  809     {
  810         free(comp_buf);
  811         return 0;
  812     }
  813     
  814     compressed_size_out = c_stream.total_out + 16;
  815     err = deflateEnd(&c_stream);
  816     if (err < 0)
  817     {
  818         free(comp_buf);
  819         return 0;
  820     }
  821 
  822     if (template_fwrite(o, "DATA", 4, 1, o->t_file) <= 0)
  823     {
  824         free(comp_buf);
  825         return 0;
  826     }
  827 
  828     write_le48(compressed_size_out, &comp_size_out[0]);
  829     if (template_fwrite(o, comp_size_out, sizeof(comp_size_out), 1, o->t_file)
  830         <= 0)
  831     {
  832         free(comp_buf);
  833         return 0;
  834     }
  835 
  836     write_le48(size, &uncomp_size_out[0]);
  837     if (template_fwrite(o, uncomp_size_out, sizeof(uncomp_size_out), 1, 
  838                         o->t_file) <= 0)
  839     {
  840         free(comp_buf);
  841         return 0;
  842     }
  843     
  844     if (template_fwrite(o, comp_buf, c_stream.total_out, 1, o->t_file) <= 0)
  845         return 0;
  846     free(comp_buf);
  847     return 1;
  848 
  849 #else /* LIBJTE_WITH_ZLIB */
  850 
  851     static int complaints = 0;
  852 
  853     if (complaints >= 3)
  854         return 0;
  855     complaints++;
  856     fprintf(stderr,
  857             "\nlibjte: Configuration error. Use without enabled zlib\n\n");
  858     return 0;
  859 
  860 #endif /* ! LIBJTE_WITH_ZLIB */
  861 
  862 }
  863 
  864 
  865 #ifdef LIBJTE_WITH_LIBBZ2
  866 
  867 /* Compress and flush out a buffer full of template data */
  868 /* Return 0 on failure, non-zero on success */
  869 static int flush_bz2_chunk(struct libjte_env *o, void *buffer, off_t size)
  870 {
  871     bz_stream c_stream; /* compression stream */
  872     unsigned char comp_size_out[6];
  873     unsigned char uncomp_size_out[6];
  874     off_t compressed_size_out = 0;
  875     int err = 0;
  876     char *comp_buf = NULL;
  877 
  878     c_stream.bzalloc = NULL;
  879     c_stream.bzfree = NULL;
  880     c_stream.opaque = NULL;
  881 
  882     err = BZ2_bzCompressInit(&c_stream, 9, 0, 0);
  883     if (err < 0)
  884         return 0;
  885 
  886     if (NULL == (comp_buf = (char*) malloc(2 * size))) /* Worst case */
  887         return 0;
  888     c_stream.next_out = comp_buf;
  889     c_stream.avail_out = 2 * size;
  890     c_stream.next_in = buffer;
  891     c_stream.avail_in = size;
  892     
  893     err = BZ2_bzCompress(&c_stream, BZ_FINISH);
  894     if (err < 0)
  895     {
  896         free(comp_buf);
  897         return 0;
  898     }
  899     
  900     compressed_size_out = c_stream.total_out_lo32 + 16;
  901     err = BZ2_bzCompressEnd(&c_stream);
  902     if (err < 0)
  903     {
  904         free(comp_buf);
  905         return 0;
  906     }
  907 
  908     if (template_fwrite(o, "BZIP", 4, 1, o->t_file) <= 0)
  909     {
  910         free(comp_buf);
  911         return 0;
  912     }
  913 
  914     write_le48(compressed_size_out, &comp_size_out[0]);
  915     if (template_fwrite(o, comp_size_out, sizeof(comp_size_out), 1, 
  916                         o->t_file) <= 0)
  917     {
  918         free(comp_buf);
  919         return 0;
  920     }
  921 
  922     write_le48(size, &uncomp_size_out[0]);
  923     if (template_fwrite(o, uncomp_size_out, sizeof(uncomp_size_out), 1,
  924                         o->t_file) <= 0)
  925     {
  926         free(comp_buf);
  927         return 0;
  928     }
  929     
  930     if (template_fwrite(o, comp_buf, c_stream.total_out_lo32, 1,
  931                         o->t_file) <= 0)
  932         return 0;
  933     free(comp_buf);
  934     return 1;
  935 }
  936 
  937 #else /* LIBJTE_WITH_LIBBZ2 */
  938 
  939 /* Compress and flush out a buffer full of template data */
  940 static int flush_bz2_chunk(struct libjte_env *o, void *buffer, off_t size)
  941 {
  942     return 0;
  943 }
  944 
  945 #endif /* ! LIBJTE_WITH_LIBBZ2 */
  946 
  947 
  948 static int flush_compressed_chunk(struct libjte_env *o,
  949                                   void *buffer, off_t size)
  950 {
  951     int ret;
  952 
  953     if (size <= 0)
  954         return 1;
  955 
  956     if (o->jte_template_compression == JTE_TEMP_BZIP2)
  957         ret = flush_bz2_chunk(o, buffer, size);
  958     else
  959         ret = flush_gzip_chunk(o, buffer, size);
  960     return ret;
  961 }
  962 
  963 /* Append to an existing data buffer, and compress/flush it if
  964    necessary */
  965 static int write_compressed_chunk(struct libjte_env *o,
  966                                    unsigned char *buffer, size_t size)
  967 {
  968     int ret;
  969 
  970     if (o->uncomp_buf == NULL)
  971     {
  972         if (o->jte_template_compression == JTE_TEMP_BZIP2)
  973             o->uncomp_size = 900 * 1024;
  974         else
  975             o->uncomp_size = 1024 * 1024;
  976         o->uncomp_buf = malloc(o->uncomp_size);
  977         if (o->uncomp_buf == NULL)
  978         {
  979                    sprintf(o->message_buffer,
  980                 "failed to allocate %lu bytes for template compression buffer",
  981                            (unsigned long) o->uncomp_size);
  982                    libjte_add_msg_entry(o, o->message_buffer, 0);
  983                    exit_if_enabled(o, 1);
  984                    return -1;
  985         }
  986     }
  987 
  988     if ((o->uncomp_buf_used + size) > o->uncomp_size)
  989     {
  990         ret = flush_compressed_chunk(o, o->uncomp_buf, o->uncomp_buf_used);
  991         if (ret <= 0)
  992             return ret;
  993         o->uncomp_buf_used = 0;
  994     }
  995 
  996     if (!size) /* Signal a flush before we start writing the DESC entry */
  997     {
  998         ret = flush_compressed_chunk(o, o->uncomp_buf, o->uncomp_buf_used);
  999         if (ret <= 0)
 1000             return ret;
 1001         return 1;
 1002     }
 1003     
 1004     if (!o->uncomp_buf_used)
 1005         memset(o->uncomp_buf, 0, o->uncomp_size);
 1006 
 1007     while (size > o->uncomp_size)
 1008     {
 1009         ret = flush_compressed_chunk(o, buffer, o->uncomp_size);
 1010         if (ret <= 0)
 1011             return ret;
 1012         buffer += o->uncomp_size;
 1013         size -= o->uncomp_size;
 1014     }
 1015     memcpy(&(o->uncomp_buf[o->uncomp_buf_used]), buffer, size);
 1016     o->uncomp_buf_used += size;
 1017     return 1;
 1018 }
 1019 
 1020 /* Loop through the list of DESC entries that we've built up and
 1021    append them to the template file */
 1022 static int write_template_desc_entries(struct libjte_env *o, off_t image_len)
 1023 {
 1024     entry_t *entry = o->entry_list;
 1025     off_t desc_len = 0;
 1026     unsigned char out_len[6];
 1027     int ret;
 1028 
 1029     if (CHECK_MD5 == check_algos[o->checksum_algo].type)
 1030     {
 1031         desc_len = 16 /* DESC + length twice */
 1032             + (sizeof(jigdo_file_entry_md5_t) * o->num_matches)
 1033             + (sizeof(jigdo_chunk_entry_t) * o->num_chunks)
 1034             + sizeof(jigdo_image_entry_md5_t);
 1035     }
 1036     else /* CHECK_SHA256 */
 1037     {
 1038         desc_len = 16 /* DESC + length twice */
 1039             + (sizeof(jigdo_file_entry_sha256_t) * o->num_matches)
 1040             + (sizeof(jigdo_chunk_entry_t) * o->num_chunks)
 1041             + sizeof(jigdo_image_entry_sha256_t);
 1042     }
 1043 
 1044     write_le48(desc_len, &out_len[0]);
 1045     ret = write_compressed_chunk(o, NULL, 0);
 1046     if (ret <= 0)
 1047         return ret;
 1048     if (template_fwrite(o, "DESC", 4, 1, o->t_file) <= 0)
 1049         return 0;
 1050     if (template_fwrite(o, out_len, sizeof(out_len), 1, o->t_file) <= 0)
 1051         return 0;
 1052     
 1053     while (entry)
 1054     {
 1055         switch (entry->entry_type)
 1056         {
 1057             case JTET_FILE_MATCH:
 1058             {
 1059                 if (CHECK_MD5 == check_algos[o->checksum_algo].type)
 1060                 {
 1061                     jigdo_file_entry_md5_t jfile;
 1062                     jfile.type = JDT_MATCHED_FILE_MD5;
 1063                     write_le48(entry->data.file.file_length, &jfile.fileLen[0]);
 1064                     write_le64(entry->data.file.rsyncsum, &jfile.fileRsync[0]);
 1065                     memcpy(jfile.fileMD5, entry->data.file.checksum, sizeof(jfile.fileMD5));
 1066                     if (template_fwrite(o, &jfile, sizeof(jfile), 1,
 1067                                         o->t_file) <= 0)
 1068                         return 0;
 1069                 }
 1070                 else /* CHECK_SHA256 */
 1071                 {
 1072                     jigdo_file_entry_sha256_t jfile;
 1073                     jfile.type = JDT_MATCHED_FILE_SHA256;
 1074                     write_le48(entry->data.file.file_length, &jfile.fileLen[0]);
 1075                     write_le64(entry->data.file.rsyncsum, &jfile.fileRsync[0]);
 1076                     memcpy(jfile.fileSHA256, entry->data.file.checksum, sizeof(jfile.fileSHA256));
 1077                     if (template_fwrite(o, &jfile, sizeof(jfile), 1,
 1078                                         o->t_file) <= 0)
 1079                         return 0;
 1080                 }
 1081                 break;
 1082             }
 1083             case JTET_NOMATCH:
 1084             {
 1085                 jigdo_chunk_entry_t jchunk;
 1086                 jchunk.type = JDT_UNMATCHED_DATA;
 1087                 write_le48(entry->data.chunk.uncompressed_length, &jchunk.skipLen[0]);
 1088                 if (template_fwrite(o, &jchunk, sizeof(jchunk), 1,
 1089                                     o->t_file) <= 0)
 1090                     return 0;
 1091                 break;
 1092             }
 1093         }
 1094         entry = entry->next;
 1095     }
 1096 
 1097     if (CHECK_MD5 == check_algos[o->checksum_algo].type)
 1098     {
 1099         jigdo_image_entry_md5_t jimage;
 1100         jimage.type = JDT_IMAGE_INFO_MD5;
 1101         write_le48(image_len, &jimage.imageLen[0]);
 1102         checksum_copy(o->iso_context, CHECK_MD5, &jimage.imageMD5[0]);
 1103         write_le32(MIN_JIGDO_FILE_SIZE, &jimage.blockLen[0]);
 1104         if (template_fwrite(o, &jimage, sizeof(jimage), 1, o->t_file) <= 0)
 1105             return 0;
 1106     }
 1107     else /* CHECK_SHA256 */
 1108     {
 1109         jigdo_image_entry_sha256_t jimage;
 1110         jimage.type = JDT_IMAGE_INFO_SHA256;
 1111         write_le48(image_len, &jimage.imageLen[0]);
 1112         checksum_copy(o->iso_context, CHECK_SHA256, &jimage.imageSHA256[0]);
 1113         write_le32(MIN_JIGDO_FILE_SIZE, &jimage.blockLen[0]);
 1114         if (template_fwrite(o, &jimage, sizeof(jimage), 1, o->t_file) <= 0)
 1115             return 0;
 1116     }
 1117         
 1118     if(template_fwrite(o, out_len, sizeof(out_len), 1, o->t_file) <= 0)
 1119         return 0;
 1120     return 1;
 1121 }
 1122 
 1123 /* Dump a buffer in jigdo-style "base64" */
 1124 static char *base64_dump(struct libjte_env *o,
 1125                          unsigned char *buf, size_t buf_size)
 1126 {
 1127     const char *b64_enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
 1128     int value = 0;
 1129     unsigned int i;
 1130     int bits = 0;
 1131     char *output_buffer = NULL;
 1132     int output_buffer_size;
 1133     char *p = NULL;
 1134 
 1135     output_buffer_size = buf_size * 8 / 6 + 1 + 1; /* round up , care for 0 */
 1136     p = output_buffer = calloc(1, output_buffer_size);
 1137     if (output_buffer == NULL)
 1138     {
 1139         sprintf(o->message_buffer,
 1140                 "base64_dump: Out of memory for buffer size %d",
 1141                 output_buffer_size);
 1142         libjte_add_msg_entry(o, o->message_buffer, 0);
 1143         exit_if_enabled(o, 1);
 1144         return NULL;
 1145     }
 1146     memset(output_buffer, 0, output_buffer_size);
 1147 
 1148     for (i = 0; i < buf_size ; i++)
 1149     {
 1150         value = (value << 8) | buf[i];
 1151         bits += 2;
 1152         p += sprintf(p, "%c", b64_enc[(value >> bits) & 63U]);
 1153         if (bits >= 6) {
 1154             bits -= 6;
 1155             p += sprintf(p, "%c", b64_enc[(value >> bits) & 63U]);
 1156         }
 1157     }
 1158     if (bits > 0)
 1159     {
 1160         value <<= 6 - bits;
 1161         p += sprintf(p, "%c", b64_enc[value & 63U]);
 1162     }
 1163     return output_buffer;
 1164 }
 1165 
 1166 
 1167 static char *uint64_to_dec(uint64_t num, char dec[40])
 1168 {
 1169     int i, l = 0, tr;
 1170 
 1171     dec[0] = 0;
 1172     while (num > 0 && l < 39) {
 1173         dec[l++] = '0' + num % 10;
 1174         num /= 10;
 1175     }
 1176     dec[l] = 0;
 1177 
 1178     /* Revert sequence of digits to Big Endian Decimal */
 1179     for (i = 0;i < l / 2; i++) {
 1180         tr = dec[i];
 1181         dec[i] = dec[l - i - 1];
 1182         dec[l - i - 1] = tr;
 1183     }
 1184     return dec;
 1185 }
 1186 
 1187 
 1188 /* Write the .jigdo file to match the .template we've just finished. */
 1189 static int write_jigdo_file(struct libjte_env *o)
 1190 {
 1191     unsigned char *template_checksum;
 1192     entry_t *entry = o->entry_list;
 1193     int i = 0;
 1194     struct checksum_info *info = NULL;
 1195     FILE *j_file = o->j_file;
 1196     char *b64, dec[40];
 1197     
 1198     template_checksum = calloc(1, check_algos[o->checksum_algo].raw_bytes);
 1199     if (!template_checksum)
 1200     {
 1201         sprintf(o->message_buffer,
 1202                 "write_jigdo_file: Out of memory for buffer size %d",
 1203                 check_algos[o->checksum_algo].raw_bytes);
 1204         libjte_add_msg_entry(o, o->message_buffer, 0);
 1205         exit_if_enabled(o, 1);
 1206         return -1;
 1207     }
 1208 
 1209     checksum_final(o->template_context);
 1210     checksum_copy(o->template_context, check_algos[o->checksum_algo].type, &template_checksum[0]);
 1211 
 1212     fprintf(j_file, "# JigsawDownload\n");
 1213     fprintf(j_file, "# See <https://www.einval.com/~steve/software/jigdo/> for details about jigdo\n");
 1214     fprintf(j_file, "# See <https://www.einval.com/~steve/software/JTE/> for details about JTE\n\n");
 1215     
 1216     fprintf(j_file, "[Jigdo]\n");
 1217     if (CHECK_MD5 == check_algos[o->checksum_algo].type)
 1218         fprintf(j_file, "Version=%s\n", JIGDO_TEMPLATE_VERSION_MD5);
 1219     else /* CHECK_SHA256 */
 1220         fprintf(j_file, "Version=%s\n", JIGDO_TEMPLATE_VERSION_SHA256);
 1221     fprintf(j_file, "Generator=libjte-%d.%d.%d\n\n",
 1222             LIBJTE_VERSION_MAJOR, LIBJTE_VERSION_MINOR, LIBJTE_VERSION_MICRO);
 1223 
 1224     fprintf(j_file, "[Image]\n");
 1225     fprintf(j_file, "Filename=%s\n", file_base_name(o->outfile));
 1226     fprintf(j_file, "Template=http://localhost/%s\n", o->jtemplate_out);
 1227 
 1228     b64 = base64_dump(o, &template_checksum[0], check_algos[o->checksum_algo].raw_bytes);
 1229     if (b64 == NULL)
 1230         return -1;
 1231 
 1232     if (CHECK_MD5 == check_algos[o->checksum_algo].type)
 1233         fprintf(j_file, "Template-MD5Sum=%s \n", b64);
 1234     else /* CHECK_SHA256 */
 1235         fprintf(j_file, "Template-SHA256Sum=%s \n", b64);
 1236     free(b64);
 1237     
 1238     for (i = 0; i < NUM_CHECKSUMS; i++)
 1239     {
 1240         if (o->checksum_algo_tmpl & (1 << i))
 1241         {
 1242             info = checksum_information(i);
 1243             fprintf(j_file, "# Template Hex %sSum %s\n", info->name,
 1244                     checksum_hex(o->template_context, i));
 1245         }
 1246     }
 1247     fprintf(j_file, "# Template size %s bytes\n",
 1248             uint64_to_dec(o->template_size, dec));
 1249 
 1250     for (i = 0; i < NUM_CHECKSUMS; i++)
 1251     {
 1252         if (o->checksum_algo_iso & (1 << i))
 1253         {
 1254             info = checksum_information(i);
 1255             fprintf(j_file, "# Image Hex %sSum %s\n",
 1256                     info->name, checksum_hex(o->iso_context, i));
 1257         }
 1258     }
 1259 
 1260     fprintf(j_file, "# Image size %s bytes\n\n",
 1261             uint64_to_dec(o->image_size, dec));
 1262 
 1263     fprintf(j_file, "[Parts]\n");
 1264     while (entry)
 1265     {
 1266         if (JTET_FILE_MATCH == entry->entry_type)
 1267         {
 1268             char *new_name = remap_filename(o, entry->data.file.filename);
 1269 
 1270             if (new_name == NULL)
 1271                 return -1;
 1272             b64 = base64_dump(o, entry->data.file.checksum, check_algos[o->checksum_algo].raw_bytes);
 1273             if (b64 == NULL)
 1274                 return -1;
 1275             fprintf(j_file, "%s=%s\n", b64, new_name);
 1276             free(b64);
 1277             free(new_name);
 1278         }
 1279         entry = entry->next;
 1280     }
 1281 
 1282     fprintf(j_file, "\n[Servers]\n");
 1283     fflush(j_file);
 1284     return 1;
 1285 }
 1286 
 1287 /* Finish and flush state; for now:
 1288    
 1289    1. Dump the DESC blocks and the footer information in the jigdo template file
 1290    2. Write the jigdo .jigdo file containing file pointers
 1291 */
 1292 int write_jt_footer(struct libjte_env *o)
 1293 {
 1294     int ret;
 1295 
 1296     /* Finish calculating the image's checksum */
 1297     checksum_final(o->iso_context);
 1298 
 1299     ret = write_template_desc_entries(o, o->image_size);
 1300     if (ret <= 0)
 1301         return ret;
 1302 
 1303     ret = write_jigdo_file(o);
 1304     return ret;
 1305 }
 1306 
 1307 /* Add a raw data entry to the list of extents; no file to match */
 1308 static void add_unmatched_entry(struct libjte_env *o, int uncompressed_length)
 1309 {
 1310     entry_t *new_entry = NULL;
 1311 
 1312     /* Can we extend a previous non-match entry? */
 1313     if (o->entry_last && (JTET_NOMATCH == o->entry_last->entry_type))
 1314     {
 1315         o->entry_last->data.chunk.uncompressed_length += uncompressed_length;
 1316         return;
 1317     }
 1318 
 1319     new_entry = calloc(1, sizeof(entry_t));
 1320     new_entry->entry_type = JTET_NOMATCH;
 1321     new_entry->next = NULL;
 1322     new_entry->data.chunk.uncompressed_length = uncompressed_length;
 1323 
 1324     /* Add to the end of the list */
 1325     if (NULL == o->entry_last)
 1326     {
 1327         o->entry_last = new_entry;
 1328         o->entry_list = new_entry;
 1329     }
 1330     else
 1331     {
 1332         o->entry_last->next = new_entry;
 1333         o->entry_last = new_entry;
 1334     }
 1335     o->num_chunks++;
 1336 }
 1337 
 1338 /* Add a file match entry to the list of extents */
 1339 static void add_file_entry(struct libjte_env *o,
 1340                            char *filename, off_t size, unsigned char *checksum,
 1341                            uint64_t rsyncsum)
 1342 {
 1343     entry_t *new_entry = NULL;
 1344 
 1345     new_entry = calloc(1, sizeof(entry_t));
 1346     new_entry->entry_type = JTET_FILE_MATCH;
 1347     new_entry->next = NULL;
 1348     new_entry->data.file.checksum = calloc(1, check_algos[o->checksum_algo].raw_bytes);
 1349     memcpy(new_entry->data.file.checksum, checksum, check_algos[o->checksum_algo].raw_bytes);
 1350     new_entry->data.file.file_length = size;
 1351     new_entry->data.file.rsyncsum = rsyncsum;
 1352     new_entry->data.file.filename = strdup(filename);
 1353 
 1354     /* Add to the end of the list */
 1355     if (NULL == o->entry_last)
 1356     {
 1357         o->entry_last = new_entry;
 1358         o->entry_list = new_entry;
 1359     }
 1360     else
 1361     {
 1362         o->entry_last->next = new_entry;
 1363         o->entry_last = new_entry;
 1364     }
 1365     o->num_matches++;
 1366 }    
 1367 
 1368 /* Cope with an unmatched block in the .iso file:
 1369 
 1370    1. Write a compressed data chunk in the jigdo template file
 1371    2. Add an entry in our list of unmatched chunks for later */
 1372 int jtwrite(struct libjte_env *o, void *buffer, int size, int count)
 1373 {
 1374     int ret;
 1375 
 1376     if (o->jtemplate_out == NULL)
 1377         return 0;
 1378 
 1379     /* Update the global image checksum */
 1380     checksum_update(o->iso_context, buffer, size * count);
 1381 
 1382     /* Write a compressed version of the data to the template file,
 1383        and add a reference on the state list so we can write that
 1384        later. */
 1385     ret = write_compressed_chunk(o, buffer, size*count);
 1386     if (ret <= 0)
 1387         return ret;
 1388     add_unmatched_entry(o, size*count);
 1389     return 1;
 1390 }
 1391 
 1392 /* Cope with a file entry in the .iso file:
 1393 
 1394    1. Read the file for the image's checksum
 1395    2. Add an entry in our list of files to be written into the .jigdo later
 1396 */
 1397 int write_jt_match_record(struct libjte_env *o,
 1398                            char *filename, char *mirror_name, int sector_size,
 1399                            off_t size, unsigned char *checksum)
 1400 {
 1401     char                buf[32768];
 1402     off_t               remain = size;
 1403     FILE               *infile = NULL;
 1404     int                 use = 0;
 1405     uint64_t            rsync64_sum = 0;
 1406     int                 first_block = 1;
 1407 
 1408     memset(buf, 0, sizeof(buf));
 1409 
 1410     if ((infile = fopen(filename, "rb")) == NULL) {
 1411 #ifndef HAVE_STRERROR
 1412         sprintf(o->message_buffer, "cannot open '%s': (%d)",
 1413                 filename, errno);
 1414 #else
 1415         sprintf(o->message_buffer, "cannot open '%s': %s",
 1416                 filename, strerror(errno));
 1417 #endif
 1418                 libjte_add_msg_entry(o, o->message_buffer, 0);
 1419         exit_if_enabled(o, 1);
 1420         return -1;
 1421     }
 1422 
 1423     while (remain > 0)
 1424     {
 1425         use = remain;
 1426         if (remain > (off_t)sizeof(buf))
 1427             use = sizeof(buf);
 1428         if (fread(buf, 1, use, infile) == 0)
 1429         {
 1430             sprintf(o->message_buffer,
 1431                                 "cannot read from '%s'", filename);
 1432                         libjte_add_msg_entry(o, o->message_buffer, 0);
 1433             exit_if_enabled(o, 1);
 1434             return -1;
 1435     }
 1436         if (first_block)
 1437             rsync64_sum = rsync64((unsigned char *) buf, MIN_JIGDO_FILE_SIZE);
 1438         checksum_update(o->iso_context, (unsigned char *) buf, use);
 1439         remain -= use;
 1440         first_block = 0;
 1441     }
 1442 
 1443     fclose(infile);
 1444     
 1445     /* Update the image checksum with any necessary padding data */
 1446     if (size % sector_size)
 1447     {
 1448         int pad_size = sector_size - (size % sector_size);
 1449         memset(buf, 0, pad_size);
 1450         checksum_update(o->iso_context, (unsigned char *) buf, pad_size);
 1451     }
 1452 
 1453     add_file_entry(o, mirror_name, size, &checksum[0], rsync64_sum);
 1454     if (size % sector_size)
 1455     {
 1456         int pad_size = sector_size - (size % sector_size);
 1457         write_compressed_chunk(o, (unsigned char *) buf, pad_size);
 1458         add_unmatched_entry(o, pad_size);
 1459     }        
 1460     return 1;
 1461 }
 1462 
 1463 int libjte_add_msg_entry(struct libjte_env *o, char *message, int flag)
 1464 {
 1465     jigdo_msg_entry_t *new_entry = NULL, *s = NULL;
 1466     int list_length = 0;
 1467 
 1468     if (o->error_behavior & 1) {
 1469          fprintf(stderr, "libjte: %s\n", message);
 1470          return 1;
 1471     }
 1472     if (o->msg_list != NULL) {
 1473         /* Find end of list and eventually do an emergency message dump */
 1474         for (s = o->msg_list; s->next != NULL; s = s->next)
 1475             list_length++;
 1476         if (list_length >= JTE_MAX_ERROR_LIST_LENGTH) {
 1477             libjte_clear_msg_list(o, 1 | 2); /* dump to stderr */
 1478             o->msg_list = s = NULL;
 1479         }
 1480     }
 1481 
 1482     new_entry = calloc(1, sizeof(jigdo_msg_entry_t));
 1483     if (new_entry == NULL) {
 1484 no_mem:;
 1485         fprintf(stderr, "libjte: %s\n", message);
 1486         fprintf(stderr, "libjte: OUT OF MEMORY\n");
 1487         return -1;
 1488     }
 1489     new_entry->next = NULL;
 1490     new_entry->message = strdup(message);
 1491     if (new_entry->message == NULL) {
 1492         free(new_entry);
 1493         goto no_mem;
 1494     }
 1495     if (o->msg_list == NULL)
 1496         o->msg_list = new_entry;
 1497     else
 1498         s->next = new_entry;
 1499     return 1;
 1500 }
 1501