"Fossies" - the Fresh Open Source Software Archive

Member "zsync-0.6.2/libzsync/zsync.c" (19 Sep 2010, 34600 Bytes) of package /linux/privat/old/zsync-0.6.2.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 "zsync.c" see the Fossies "Dox" file reference documentation.

    1 
    2 /*
    3  *   zsync - client side rsync over http
    4  *   Copyright (C) 2004,2005,2007,2009 Colin Phipps <cph@moria.org.uk>
    5  *
    6  *   This program is free software; you can redistribute it and/or modify
    7  *   it under the terms of the Artistic License v2 (see the accompanying 
    8  *   file COPYING for the full license terms), or, at your option, any later 
    9  *   version of the same license.
   10  *
   11  *   This program is distributed in the hope that it will be useful,
   12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14  *   COPYING file for details.
   15  */
   16 
   17 /* This is the heart of zsync.
   18  *
   19  * .zsync file parsing and glue between all the main components of zsync.
   20  *
   21  * This file is where the .zsync metadata format is understood and read; it
   22  * extracts it and creates the corresponding rcksum object to apply the rsync
   23  * algorithm in constructing the target. It applies the zmap to convert byte
   24  * ranges between compressed and uncompressed versions of the data as needed,
   25  * and does decompression on compressed data received. It joins the HTTP code
   26  * to the rsync algorithm by converting lists of blocks from rcksum into lists
   27  * of byte ranges at particular URLs to be retrieved by the HTTP code.
   28  *
   29  * It also handles:
   30  * - blocking edge cases (decompressed data not lining up with blocks for rcksum; 
   31  *   last block of the file only containing partial data)
   32  * - recompression of the compressed data at the end of the transfer;
   33  * - checksum verification of the entire output.
   34  */
   35 #include "zsglobal.h"
   36 
   37 #include <stdio.h>
   38 #include <stdlib.h>
   39 #include <sys/types.h>
   40 #include <unistd.h>
   41 #include <string.h>
   42 #include <ctype.h>
   43 #include <time.h>
   44 
   45 #include <arpa/inet.h>
   46 
   47 #ifdef WITH_DMALLOC
   48 # include <dmalloc.h>
   49 #endif
   50 
   51 #include "zlib/zlib.h"
   52 
   53 #include "librcksum/rcksum.h"
   54 #include "zsync.h"
   55 #include "sha1.h"
   56 #include "zmap.h"
   57 
   58 /* Probably we really want a table of compression methods here. But I've only
   59  * implemented SHA1 so this is it for now. */
   60 const char ckmeth_sha1[] = { "SHA-1" };
   61 
   62 /* List of options strings for gzip(1) allowed in the .zsync. This is 
   63  * security against someone specifying arbitrary commands. */
   64 static const char* const gzip_safe_option[] = {
   65     "--best",
   66     "",
   67     "--rsync",
   68     "--rsync --best",
   69     "--best --no-name",
   70     "--no-name",
   71     "--rsync --no-name",
   72     "--rsync --best --no-name"
   73 };
   74 const int gzip_safe_options = sizeof(gzip_safe_option)/sizeof *gzip_safe_option;
   75 
   76 /****************************************************************************
   77  *
   78  * zsync_state object and methods
   79  * This holds a single target file's details, and holds the state of the
   80  * in-progress local copy of that target that we are constructing (via a
   81  * contained rcksum_state object)
   82  *
   83  * Also holds all the other misc data from the .zsync file.
   84  */
   85 struct zsync_state {
   86     struct rcksum_state *rs;    /* rsync algorithm state, with block checksums and
   87                                  * holding the in-progress local version of the target */
   88     off_t filelen;              /* Length of the target file */
   89     int blocks;                 /* Number of blocks in the target */
   90     size_t blocksize;           /* Blocksize */
   91 
   92     /* Checksum of the entire file, and checksum alg */
   93     char *checksum;
   94     const char *checksum_method;
   95 
   96     /* URLs to uncompressed versions of the target */
   97     char **url;
   98     int nurl;
   99 
  100     /* URLs to compressed versions of the target, and the zmap of that compressed version */
  101     struct zmap *zmap;
  102     char **zurl;
  103     int nzurl;
  104 
  105     char *cur_filename;         /* If we have taken the filename from rcksum, it is here */
  106 
  107     /* Hints for the output file, from the .zsync */
  108     char *filename;             /* The Filename: header */
  109     char *zfilename;            /* ditto Z-Filename: */
  110 
  111     char *gzopts;               /* If we're recompressing the download afterwards, these are the options to gzip(1) */
  112     char *gzhead;               /* And this is the header of the gzip file (for the mtime) */
  113 
  114     time_t mtime;               /* MTime: from the .zsync, or -1 */
  115 };
  116 
  117 static int zsync_read_blocksums(struct zsync_state *zs, FILE * f,
  118                                 int rsum_bytes, int checksum_bytes,
  119                                 int seq_matches);
  120 static int zsync_sha1(struct zsync_state *zs, int fh);
  121 static int zsync_recompress(struct zsync_state *zs);
  122 static time_t parse_822(const char* ts);
  123 
  124 /* char*[] = append_ptrlist(&num, &char[], "to add")
  125  * Crude data structure to store an ordered list of strings. This appends one
  126  * entry to the list. */
  127 static char **append_ptrlist(int *n, char **p, char *a) {
  128     if (!a)
  129         return p;
  130     p = realloc(p, (*n + 1) * sizeof *p);
  131     if (!p) {
  132         fprintf(stderr, "out of memory\n");
  133         exit(1);
  134     }
  135     p[*n] = a;
  136     (*n)++;
  137     return p;
  138 }
  139 
  140 /* Constructor */
  141 struct zsync_state *zsync_begin(FILE * f) {
  142     /* Defaults for the checksum bytes and sequential matches properties of the
  143      * rcksum_state. These are the defaults from versions of zsync before these
  144      * were variable. */
  145     int checksum_bytes = 16, rsum_bytes = 4, seq_matches = 1;
  146 
  147     /* Field names that we can ignore if present and not
  148      * understood. This allows new headers to be added without breaking
  149      * backwards compatibility, and conversely to add headers that do break
  150      * backwards compat and have old clients give meaningful errors. */
  151     char *safelines = NULL;
  152 
  153     /* Allocate memory for the object */
  154     struct zsync_state *zs = calloc(sizeof *zs, 1);
  155 
  156     if (!zs)
  157         return NULL;
  158 
  159     /* Any non-zero defaults here. */
  160     zs->mtime = -1;
  161 
  162     for (;;) {
  163         char buf[1024];
  164         char *p = NULL;
  165         int l;
  166 
  167         if (fgets(buf, sizeof(buf), f) != NULL) {
  168             if (buf[0] == '\n')
  169                 break;
  170             l = strlen(buf) - 1;
  171             while (l >= 0
  172                    && (buf[l] == '\n' || buf[l] == '\r' || buf[l] == ' '))
  173                 buf[l--] = 0;
  174 
  175             p = strchr(buf, ':');
  176         }
  177         if (p && *(p + 1) == ' ') {
  178             *p++ = 0;
  179             p++;
  180             if (!strcmp(buf, "zsync")) {
  181                 if (!strcmp(p, "0.0.4")) {
  182                     fprintf(stderr, "This version of zsync is not compatible with zsync 0.0.4 streams.\n");
  183                     free(zs);
  184                     return NULL;
  185                 }
  186             }
  187             else if (!strcmp(buf, "Min-Version")) {
  188                 if (strcmp(p, VERSION) > 0) {
  189                     fprintf(stderr,
  190                             "control file indicates that zsync-%s or better is required\n",
  191                             p);
  192                     free(zs);
  193                     return NULL;
  194                 }
  195             }
  196             else if (!strcmp(buf, "Length")) {
  197                 zs->filelen = atoll(p);
  198             }
  199             else if (!strcmp(buf, "Filename")) {
  200                 zs->filename = strdup(p);
  201             }
  202             else if (!strcmp(buf, "Z-Filename")) {
  203                 zs->zfilename = strdup(p);
  204             }
  205             else if (!strcmp(buf, "URL")) {
  206                 zs->url = (char **)append_ptrlist(&(zs->nurl), zs->url, strdup(p));
  207             }
  208             else if (!strcmp(buf, "Z-URL")) {
  209                 zs->zurl = (char **)append_ptrlist(&(zs->nzurl), zs->zurl, strdup(p));
  210             }
  211             else if (!strcmp(buf, "Blocksize")) {
  212                 zs->blocksize = atol(p);
  213                 if (zs->blocksize < 0 || (zs->blocksize & (zs->blocksize - 1))) {
  214                     fprintf(stderr, "nonsensical blocksize %ld\n", zs->blocksize);
  215                     free(zs);
  216                     return NULL;
  217                 }
  218             }
  219             else if (!strcmp(buf, "Hash-Lengths")) {
  220                 if (sscanf
  221                     (p, "%d,%d,%d", &seq_matches, &rsum_bytes,
  222                      &checksum_bytes) != 3 || rsum_bytes < 1 || rsum_bytes > 4
  223                     || checksum_bytes < 3 || checksum_bytes > 16
  224                     || seq_matches > 2 || seq_matches < 1) {
  225                     fprintf(stderr, "nonsensical hash lengths line %s\n", p);
  226                     free(zs);
  227                     return NULL;
  228                 }
  229             }
  230             else if (zs->blocks && !strcmp(buf, "Z-Map2")) {
  231                 int nzblocks;
  232                 struct gzblock *zblock;
  233 
  234                 nzblocks = atoi(p);
  235                 if (nzblocks < 0) {
  236                     fprintf(stderr, "bad Z-Map line\n");
  237                     free(zs);
  238                     return NULL;
  239                 }
  240 
  241                 zblock = malloc(nzblocks * sizeof *zblock);
  242                 if (zblock) {
  243                     if (fread(zblock, sizeof *zblock, nzblocks, f) < nzblocks) {
  244                         fprintf(stderr, "premature EOF after Z-Map\n");
  245                         free(zs);
  246                         return NULL;
  247                     }
  248 
  249                     zs->zmap = zmap_make(zblock, nzblocks);
  250                     free(zblock);
  251                 }
  252             }
  253             else if (!strcmp(buf, ckmeth_sha1)) {
  254                 if (strlen(p) != SHA1_DIGEST_LENGTH * 2) {
  255                     fprintf(stderr, "SHA-1 digest from control file is wrong length.\n");
  256                 }
  257                 else {
  258                     zs->checksum = strdup(p);
  259                     zs->checksum_method = ckmeth_sha1;
  260                 }
  261             }
  262             else if (!strcmp(buf, "Safe")) {
  263                 safelines = strdup(p);
  264             }
  265             else if (!strcmp(buf, "Recompress")) {
  266                 zs->gzhead = strdup(p);
  267                 if (zs->gzhead) {
  268                     int i;
  269                     char *q = strchr(zs->gzhead, ' ');
  270                     if (!q)
  271                         q = zs->gzhead + strlen(zs->gzhead);
  272 
  273                     if (*q)
  274                         *q++ = 0;
  275                     /* Whitelist for safe options for gzip command line */
  276                     for (i = 0; i < gzip_safe_options; i++)
  277                         if (!strcmp(q, gzip_safe_option[i])) {
  278                             zs->gzopts = strdup(q);
  279                             break;
  280                         }
  281                     if( !zs->gzopts ) {
  282                         fprintf(stderr, "bad recompress options, rejected\n");
  283                         free(zs->gzhead);
  284                     }
  285                 }
  286             }
  287             else if (!strcmp(buf, "MTime")) {
  288                 zs->mtime = parse_822(p);
  289             }
  290             else if (!safelines || !strstr(safelines, buf)) {
  291                 fprintf(stderr,
  292                         "unrecognised tag %s - you need a newer version of zsync.\n",
  293                         buf);
  294                 free(zs);
  295                 return NULL;
  296             }
  297             if (zs->filelen && zs->blocksize)
  298                 zs->blocks = (zs->filelen + zs->blocksize - 1) / zs->blocksize;
  299         }
  300         else {
  301             fprintf(stderr, "Bad line - not a zsync file? \"%s\"\n", buf);
  302             free(zs);
  303             return NULL;
  304         }
  305     }
  306     if (!zs->filelen || !zs->blocksize) {
  307         fprintf(stderr, "Not a zsync file (looked for Blocksize and Length lines)\n");
  308         free(zs);
  309         return NULL;
  310     }
  311     if (zsync_read_blocksums(zs, f, rsum_bytes, checksum_bytes, seq_matches) != 0) {
  312         free(zs);
  313         return NULL;
  314     }
  315     return zs;
  316 }
  317 
  318 /* zsync_read_blocksums(self, FILE*, rsum_bytes, checksum_bytes, seq_matches)
  319  * Called during construction only, this creates the rcksum_state that stores
  320  * the per-block checksums of the target file and holds the local working copy
  321  * of the in-progress target. And it populates the per-block checksums from the
  322  * given file handle, which must be reading from the .zsync at the start of the
  323  * checksums. 
  324  * rsum_bytes, checksum_bytes, seq_matches are settings for the checksums,
  325  * passed through to the rcksum_state. */
  326 static int zsync_read_blocksums(struct zsync_state *zs, FILE * f,
  327                                 int rsum_bytes, int checksum_bytes,
  328                                 int seq_matches) {
  329     /* Make the rcksum_state first */
  330     if (!(zs->rs = rcksum_init(zs->blocks, zs->blocksize, rsum_bytes,
  331                                checksum_bytes, seq_matches))) {
  332         return -1;
  333     }
  334 
  335     /* Now read in and store the checksums */
  336     zs_blockid id = 0;
  337     for (; id < zs->blocks; id++) {
  338         struct rsum r = { 0, 0 };
  339         unsigned char checksum[CHECKSUM_SIZE];
  340 
  341         /* Read in */
  342         if (fread(((char *)&r) + 4 - rsum_bytes, rsum_bytes, 1, f) < 1
  343             || fread((void *)&checksum, checksum_bytes, 1, f) < 1) {
  344 
  345             /* Error - free the rcksum_state and tell the caller to bail */
  346             fprintf(stderr, "short read on control file; %s\n",
  347                     strerror(ferror(f)));
  348             rcksum_end(zs->rs);
  349             return -1;
  350         }
  351 
  352         /* Convert to host endian and store */
  353         r.a = ntohs(r.a);
  354         r.b = ntohs(r.b);
  355         rcksum_add_target_block(zs->rs, id, r, checksum);
  356     }
  357     return 0;
  358 }
  359 
  360 /* parse_822(buf[])
  361  * Parse an RFC822 date string. Returns a time_t, or -1 on failure. 
  362  * E.g. Tue, 25 Jul 2006 20:02:17 +0000
  363  */
  364 static time_t parse_822(const char* ts) {
  365     struct tm t;
  366 
  367     if (strptime(ts, "%a, %d %b %Y %H:%M:%S %z", &t) == NULL
  368         && strptime(ts, "%d %b %Y %H:%M:%S %z", &t) == NULL) {
  369         return -1;
  370     }
  371     return mktime(&t);
  372 }
  373 
  374 /* zsync_hint_decompress(self)
  375  * Returns true if we think we'll be able to download compressed data to get
  376  * the needed data to complete the target file */
  377 int zsync_hint_decompress(const struct zsync_state *zs) {
  378     return (zs->nzurl > 0 ? 1 : 0);
  379 }
  380 
  381 /* zsync_blocksize(self)
  382  * Returns the blocksize used by zsync on this target. */
  383 int zsync_blocksize(const struct zsync_state *zs) {
  384     return zs->blocksize;
  385 }
  386 
  387 /* char* = zsync_filename(self)
  388  * Returns the suggested filename to be used for the final result of this
  389  * zsync.  Malloced string to be freed by the caller. */
  390 char *zsync_filename(const struct zsync_state *zs) {
  391     return strdup(zs->gzhead && zs->zfilename ? zs->zfilename : zs->filename);
  392 }
  393 
  394 /* time_t = zsync_mtime(self)
  395  * Returns the mtime on the original copy of the target; for the client program
  396  * to set the mtime of the local file to match, if it so chooses.
  397  * Or -1 if no mtime specified in the .zsync */
  398 time_t zsync_mtime(const struct zsync_state *zs) {
  399     return zs->mtime;
  400 }
  401 
  402 /* zsync_status(self)
  403  * Returns  0 if we have no data in the target file yet.
  404  *          1 if we have some but not all
  405  *          2 or more if we have all.
  406  * The caller should not rely on exact values 2+; just test >= 2. Values >2 may
  407  * be used in later versions of libzsync. */
  408 int zsync_status(const struct zsync_state *zs) {
  409     int todo = rcksum_blocks_todo(zs->rs);
  410 
  411     if (todo == zs->blocks)
  412         return 0;
  413     if (todo > 0)
  414         return 1;
  415     return 2;                   /* TODO: more? */
  416 }
  417 
  418 /* zsync_progress(self, &got, &total)
  419  * Writes the number of bytes got, and the total to get, into the long longs.
  420  */
  421 void zsync_progress(const struct zsync_state *zs, long long *got,
  422                     long long *total) {
  423 
  424     if (got) {
  425         int todo = zs->blocks - rcksum_blocks_todo(zs->rs);
  426         *got = todo * zs->blocksize;
  427     }
  428     if (total)
  429         *total = zs->blocks * zs->blocksize;
  430 }
  431 
  432 /* zsync_get_urls(self, &num, &type)
  433  * Returns a (pointer to an) array of URLs (returning the number of them in
  434  * num) that are remote available copies of the target file (according to the
  435  * .zsync).
  436  * Note that these URLs could be for encoded versions of the target; a 'type'
  437  * is returned in *type which tells libzsync in later calls what version of the
  438  * target is being retrieved. */
  439 const char *const *zsync_get_urls(struct zsync_state *zs, int *n, int *t) {
  440     if (zs->zmap && zs->nzurl) {
  441         *n = zs->nzurl;
  442         *t = 1;
  443         return zs->zurl;
  444     }
  445     else {
  446         *n = zs->nurl;
  447         *t = 0;
  448         return zs->url;
  449     }
  450 }
  451 
  452 /* zsync_needed_byte_ranges(self, &num, type)
  453  * Returns an array of offsets (2*num of them) for the start and end of num
  454  * byte ranges in the given type of version of the target (type as returned by
  455  * a zsync_get_urls call), such that retrieving all these byte ranges would be
  456  * sufficient to obtain a complete copy of the target file.
  457  */
  458 off_t *zsync_needed_byte_ranges(struct zsync_state * zs, int *num, int type) {
  459     int nrange;
  460     off_t *byterange;
  461     int i;
  462 
  463     /* Request all needed block ranges */
  464     zs_blockid *blrange = rcksum_needed_block_ranges(zs->rs, &nrange, 0, 0x7fffffff);
  465     if (!blrange)
  466         return NULL;
  467 
  468     /* Allocate space for byte ranges */
  469     byterange = malloc(2 * nrange * sizeof *byterange);
  470     if (!byterange) {
  471         free(blrange);
  472         return NULL;
  473     }
  474 
  475     /* Now convert blocks to bytes.
  476      * Note: Must cast one operand to off_t as both blocksize and blrange[x]
  477      * are int's whereas the product must be a file offfset. Needed so we don't
  478      * truncate file offsets to 32bits on 32bit platforms. */
  479     for (i = 0; i < nrange; i++) {
  480         byterange[2 * i] = blrange[2 * i] * (off_t)zs->blocksize;
  481         byterange[2 * i + 1] = blrange[2 * i + 1] * (off_t)zs->blocksize - 1;
  482     }
  483     free(blrange);      /* And release the blocks, we're done with them */
  484 
  485     switch (type) {
  486     case 0:
  487         *num = nrange;
  488         return byterange;
  489     case 1:
  490         {   /* Convert ranges in the uncompressed data to ranges in the compressed data */
  491             off_t *zbyterange =
  492                 zmap_to_compressed_ranges(zs->zmap, byterange, nrange, &nrange);
  493 
  494             /* Store the number of compressed ranges and return them, freeing
  495              * the uncompressed ones now we've used them. */
  496             if (zbyterange) {
  497                 *num = nrange;
  498             }
  499             free(byterange);
  500             return zbyterange;
  501         }
  502     default:
  503         free(byterange);
  504         return NULL;
  505     }
  506 }
  507 
  508 /* zsync_submit_source_file(self, FILE*, progress)
  509  * Read the given stream, applying the rsync rolling checksum algorithm to
  510  * identify any blocks of data in common with the target file. Blocks found are
  511  * written to our local copy of the target in progress. Progress reports if
  512  * progress != 0  */
  513 int zsync_submit_source_file(struct zsync_state *zs, FILE * f, int progress) {
  514     return rcksum_submit_source_file(zs->rs, f, progress);
  515 }
  516 
  517 char *zsync_cur_filename(struct zsync_state *zs) {
  518     if (!zs->cur_filename)
  519         zs->cur_filename = rcksum_filename(zs->rs);
  520 
  521     return zs->cur_filename;
  522 }
  523 
  524 /* zsync_rename_file(self, filename)
  525  * Tell libzsync to move the local copy of the target (or under construction
  526  * target) to the given filename. */
  527 int zsync_rename_file(struct zsync_state *zs, const char *f) {
  528     char *rf = zsync_cur_filename(zs);
  529 
  530     int x = rename(rf, f);
  531 
  532     if (!x) {
  533         free(rf);
  534         zs->cur_filename = strdup(f);
  535     }
  536     else
  537         perror("rename");
  538 
  539     return x;
  540 }
  541 
  542 /* int hexdigit(char)
  543  * Maps a character to 0..15 as a hex digit (or 0 if not valid hex digit)
  544  */
  545 static int hexdigit(char c) {
  546     return (isdigit(c) ? (c - '0') : isupper(c) ? (0xa + (c - 'A')) : islower(c)
  547             ? (0xa + (c - 'a')) : 0);
  548 }
  549 
  550 /* zsync_complete(self)
  551  * Finish a zsync download. Should be called once all blocks have been
  552  * retrieved successfully. This returns 0 if the file passes the final
  553  * whole-file checksum and if any recompression requested by the .zsync file is
  554  * done.
  555  * Returns -1 on error (and prints the error to stderr)
  556  *          0 if successful but no checksum verified
  557  *          1 if successful including checksum verified
  558  */
  559 int zsync_complete(struct zsync_state *zs) {
  560     int rc = 0;
  561 
  562     /* We've finished with the rsync algorithm. Take over the local copy from
  563      * librcksum and free our rcksum state. */
  564     int fh = rcksum_filehandle(zs->rs);
  565     zsync_cur_filename(zs);
  566     rcksum_end(zs->rs);
  567     zs->rs = NULL;
  568 
  569     /* Truncate the file to the exact length (to remove any trailing NULs from
  570      * the last block); return to the start of the file ready to verify. */
  571     if (ftruncate(fh, zs->filelen) != 0) {
  572         perror("ftruncate");
  573         rc = -1;
  574     }
  575     if (lseek(fh, 0, SEEK_SET) != 0) {
  576         perror("lseek");
  577         rc = -1;
  578     }
  579 
  580     /* Do checksum check */
  581     if (rc == 0 && zs->checksum && !strcmp(zs->checksum_method, ckmeth_sha1)) {
  582         rc = zsync_sha1(zs, fh);
  583     }
  584     close(fh);
  585 
  586     /* Do any requested recompression */
  587     if (rc >= 0 && zs->gzhead && zs->gzopts) {
  588         if (zsync_recompress(zs) != 0) {
  589             return -1;
  590         }
  591     }
  592     return rc;
  593 }
  594 
  595 /* zsync_sha1(self, filedesc)
  596  * Given the currently-open-and-at-start-of-file complete local copy of the
  597  * target, read it and compare the SHA1 checksum with the one from the .zsync.
  598  * Returns -1 or 1 as per zsync_complete.
  599  */
  600 static int zsync_sha1(struct zsync_state *zs, int fh) {
  601     SHA1_CTX shactx;
  602 
  603     {                           /* Do SHA1 of file contents */
  604         unsigned char buf[4096];
  605         int rc;
  606 
  607         SHA1Init(&shactx);
  608         while (0 < (rc = read(fh, buf, sizeof buf))) {
  609             SHA1Update(&shactx, buf, rc);
  610         }
  611         if (rc < 0) {
  612             perror("read");
  613             return -1;
  614         }
  615     }
  616 
  617     {                           /* And compare result of the SHA1 with the one from the .zsync */
  618         unsigned char digest[SHA1_DIGEST_LENGTH];
  619         int i;
  620 
  621         SHA1Final(digest, &shactx);
  622 
  623         for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
  624             int j;
  625             sscanf(&(zs->checksum[2 * i]), "%2x", &j);
  626             if (j != digest[i]) {
  627                 return -1;
  628             }
  629         }
  630         return 1; /* Checksum verified okay */
  631     }
  632 }
  633 
  634 /* zsync_recompress(self)
  635  * Called when we have a complete local copy of the uncompressed data, to
  636  * perform compression requested in the .zsync.
  637  *
  638  * Shells out to the standard system gzip(1). Replaces the gzip file header
  639  * with the one supplied in the .zsync; this means we should get an identical
  640  * compressed file output to the original compressed file on the source system
  641  * (to allow the user to verify a checksum on the compressed file, or just
  642  * because the user is picky and wants their compressed file to match the
  643  * original).
  644  *
  645  * Returns 0 on success, -1 on error (which is reported on stderr). */
  646 static int zsync_recompress(struct zsync_state *zs) {
  647     /* Recompression. This is a fugly mess, calling gzip on the temporary file with options
  648      *  read out of the .zsync, reading its output and replacing the gzip header. Ugh. */
  649     FILE *g;
  650     FILE *zout;
  651     int rc = 0;
  652 
  653     char cmd[1024];
  654     snprintf(cmd, sizeof(cmd), "gzip -n %s < ", zs->gzopts);
  655 
  656     {   /* Add input filename, shell-escaped, to the command line */
  657         int i = 0;
  658         size_t j = strlen(cmd);
  659         char c;
  660 
  661         while ((c = zs->cur_filename[i++]) != 0 && j < sizeof(cmd) - 2) {
  662             if (!isalnum(c))
  663                 cmd[j++] = '\\';
  664             cmd[j++] = c;
  665         }
  666         cmd[j] = 0;
  667     }
  668 
  669     /* Read gzipped version of the data via pipe from gzip; write it to our new
  670      * output file, except that we replace the gzip header with our own from
  671      * the .zsync file. */
  672     g = popen(cmd, "r");
  673     if (g) {
  674         char zoname[1024];
  675 
  676         snprintf(zoname, sizeof(zoname), "%s.gz", zs->cur_filename);
  677         zout = fopen(zoname, "w");
  678 
  679         if (zout) {
  680             char *p = zs->gzhead;
  681             int skip = 1;
  682 
  683             while (p[0] && p[1]) {
  684                 if (fputc((hexdigit(p[0]) << 4) + hexdigit(p[1]), zout) == EOF) {
  685                     perror("putc");
  686                     rc = -1;
  687                 }
  688                 p += 2;
  689             }
  690             while (!feof(g)) {
  691                 char buf[1024];
  692                 int r;
  693                 const char *p = buf;
  694 
  695                 if ((r = fread(buf, 1, sizeof(buf), g)) < 0) {
  696                     perror("fread");
  697                     rc = -1;
  698                     goto leave_it;
  699                 }
  700                 if (skip) {
  701                     p = skip_zhead(buf);
  702                     skip = 0;
  703                 }
  704                 if (fwrite(p, 1, r - (p - buf), zout) != r - (p - buf)) {
  705                     perror("fwrite");
  706                     rc = -1;
  707                     goto leave_it;
  708                 }
  709             }
  710 
  711           leave_it:
  712             if (fclose(zout) != 0) {
  713                 perror("close");
  714                 rc = -1;
  715             }
  716         }
  717         if (fclose(g) != 0) {
  718             perror("close");
  719             rc = -1;
  720         }
  721 
  722         /* Free our old filename and replace with the new one */
  723         unlink(zs->cur_filename);
  724         free(zs->cur_filename);
  725         zs->cur_filename = strdup(zoname);
  726     }
  727     else {
  728         fprintf(stderr, "problem with gzip, unable to compress.\n");
  729     }
  730     return rc;
  731 }
  732 
  733 /* Destructor */
  734 char *zsync_end(struct zsync_state *zs) {
  735     int i;
  736     char *f = zsync_cur_filename(zs);
  737 
  738     /* Free rcksum object and zmap */
  739     if (zs->rs)
  740         rcksum_end(zs->rs);
  741     if (zs->zmap)
  742         zmap_free(zs->zmap);
  743 
  744     /* Clear download URLs */
  745     for (i = 0; i < zs->nurl; i++)
  746         free(zs->url[i]);
  747     for (i = 0; i < zs->nzurl; i++)
  748         free(zs->zurl[i]);
  749 
  750     /* And the rest. */
  751     free(zs->url);
  752     free(zs->zurl);
  753     free(zs->checksum);
  754     free(zs->filename);
  755     free(zs->zfilename);
  756     free(zs);
  757     return f;
  758 }
  759 
  760 /* Next come the methods for accepting data received from the remote copies of
  761  * the target and incomporating them into the local copy under construction. */
  762 
  763 /* zsync_configure_zstream_for_zdata(self, &z_stream_s, zoffset, &outoffset)
  764  * Rewrites the state in the given zlib stream object to be ready to decompress
  765  * data from the compressed version of this zsync stream at the given offset in
  766  * the compressed file. Returns the offset in the uncompressed stream that this
  767  * corresponds to in the 4th parameter. 
  768  */
  769 void zsync_configure_zstream_for_zdata(const struct zsync_state *zs,
  770                                        struct z_stream_s *zstrm,
  771                                        long zoffset, long long *poutoffset) {
  772     configure_zstream_for_zdata(zs->zmap, zstrm, zoffset, poutoffset);
  773     {                           /* Load in prev 32k sliding window for backreferences */
  774         long long pos = *poutoffset;
  775         int lookback = (pos > 32768) ? 32768 : pos;
  776 
  777         /* Read in 32k of leading uncompressed context - needed because the deflate
  778          * compression method includes back-references to previously-seen strings. */
  779         unsigned char wbuf[32768];
  780         rcksum_read_known_data(zs->rs, wbuf, pos - lookback, lookback);
  781 
  782         /* Fake an output buffer of 32k filled with data to zlib */
  783         zstrm->next_out = wbuf + lookback;
  784         zstrm->avail_out = 0;
  785         updatewindow(zstrm, lookback);
  786     }
  787 }
  788 
  789 /* zsync_submit_data(self, buf[], offset, blocks)
  790  * Passes data retrieved from the remote copy of
  791  * the target file to libzsync, to be written into our local copy. The data is
  792  * the given number of blocks at the given offset (must be block-aligned), data
  793  * in buf[].  */
  794 static int zsync_submit_data(struct zsync_state *zs,
  795                              const unsigned char *buf, off_t offset,
  796                              int blocks) {
  797     zs_blockid blstart = offset / zs->blocksize;
  798     zs_blockid blend = blstart + blocks - 1;
  799 
  800     return rcksum_submit_blocks(zs->rs, buf, blstart, blend);
  801 }
  802 
  803 /****************************************************************************
  804  *
  805  * zsync_receiver object definition and methods.
  806  * Stores the state for a currently-running download of blocks from a
  807  * particular URL or version of a file to complete a file using zsync.
  808  *
  809  * This is mostly a wrapper for the zsync_state which keeps various additional
  810  * state needed per-download: in particular the zlib stream object to
  811  * decompress the incoming data if this is a URL of a compressed version of the
  812  * target file.
  813  */
  814 struct zsync_receiver {
  815     struct zsync_state *zs;     /* The zsync_state that we are downloading for */
  816     struct z_stream_s strm;     /* Decompression object */
  817     int url_type;               /* Compressed or not */
  818     unsigned char *outbuf;      /* Working buffer to keep incomplete blocks of data */
  819     off_t outoffset;            /* and the position in that buffer */
  820 };
  821 
  822 /* Constructor */
  823 struct zsync_receiver *zsync_begin_receive(struct zsync_state *zs, int url_type) {
  824     struct zsync_receiver *zr = malloc(sizeof(struct zsync_receiver));
  825 
  826     if (!zr)
  827         return NULL;
  828     zr->zs = zs;
  829 
  830     zr->outbuf = malloc(zs->blocksize);
  831     if (!zr->outbuf) {
  832         free(zr);
  833         return NULL;
  834     }
  835 
  836     /* Set up new inflate object */
  837     zr->strm.zalloc = Z_NULL;
  838     zr->strm.zfree = Z_NULL;
  839     zr->strm.opaque = NULL;
  840     zr->strm.total_in = 0;
  841 
  842     zr->url_type = url_type;
  843     zr->outoffset = 0;
  844 
  845     return zr;
  846 }
  847 
  848 /* zsync_receive_data_uncompressed(self, buf[], offset, buflen)
  849  * Adds the data in buf (buflen bytes) to this file at the given offset.
  850  * Returns 0 unless there's an error (e.g. the submitted data doesn't match the
  851  * expected checksum for the corresponding blocks)
  852  */
  853 static int zsync_receive_data_uncompressed(struct zsync_receiver *zr,
  854                                            const unsigned char *buf,
  855                                            off_t offset, size_t len) {
  856     int ret = 0;
  857     size_t blocksize = zr->zs->blocksize;
  858 
  859     if (0 != (offset % blocksize)) {
  860         size_t x = len;
  861 
  862         if (x > blocksize - (offset % blocksize))
  863             x = blocksize - (offset % blocksize);
  864 
  865         if (zr->outoffset == offset) {
  866             /* Half-way through a block, so let's try and complete it */
  867             if (len)
  868                 memcpy(zr->outbuf + offset % blocksize, buf, x);
  869             else {
  870                 // Pad with 0s to length.
  871                 memset(zr->outbuf + offset % blocksize, 0, len = x =
  872                        blocksize - (offset % blocksize));
  873             }
  874 
  875             if ((x + offset) % blocksize == 0)
  876                 if (zsync_submit_data
  877                     (zr->zs, zr->outbuf, zr->outoffset + x - blocksize, 1))
  878                     ret = 1;
  879         }
  880         buf += x;
  881         len -= x;
  882         offset += x;
  883     }
  884 
  885     /* Now we are block-aligned */
  886     if (len >= blocksize) {
  887         int w = len / blocksize;
  888 
  889         if (zsync_submit_data(zr->zs, buf, offset, w))
  890             ret = 1;
  891 
  892         w *= blocksize;
  893         buf += w;
  894         len -= w;
  895         offset += w;
  896 
  897     }
  898     /* Store incomplete block */
  899     if (len) {
  900         memcpy(zr->outbuf, buf, len);
  901         offset += len;          /* not needed: buf += len; len -= len; */
  902     }
  903 
  904     zr->outoffset = offset;
  905     return ret;
  906 }
  907 
  908 /* zsync_receive_data_compressed(self, buf[], offset, buflen)
  909  * Passes data received corresponding to the compressed version of this file at
  910  * the given offset; data in buf, buflen bytes.
  911  * Returns 0 unless there's an error (e.g. the submitted data doesn't match the
  912  * expected checksum for the corresponding blocks)
  913  */
  914 static int zsync_receive_data_compressed(struct zsync_receiver *zr,
  915                               const unsigned char *buf, off_t offset,
  916                               size_t len) {
  917     int ret = 0;
  918     int eoz = 0;
  919     size_t blocksize = zr->zs->blocksize;
  920 
  921     if (!len)
  922         return 0;
  923 
  924     /* Now set up for the downloaded block */
  925     zr->strm.next_in = buf;
  926     zr->strm.avail_in = len;
  927 
  928     if (zr->strm.total_in == 0 || offset != zr->strm.total_in) {
  929         zsync_configure_zstream_for_zdata(zr->zs, &(zr->strm), offset,
  930                                           &(zr->outoffset));
  931 
  932         /* On first iteration, we might be reading an incomplete block from zsync's point of view. Limit avail_out so we can stop after doing that and realign with the buffer. */
  933         zr->strm.avail_out = blocksize - (zr->outoffset % blocksize);
  934         zr->strm.next_out = zr->outbuf;
  935     }
  936     else {
  937         if (zr->outoffset == -1) {
  938             fprintf(stderr,
  939                     "data didn't align with block boundary in compressed stream\n");
  940             return 1;
  941         }
  942         zr->strm.next_in = buf;
  943         zr->strm.avail_in = len;
  944     }
  945 
  946     while (zr->strm.avail_in && !eoz) {
  947         int rc;
  948 
  949         /* Read in up to the next block (in the libzsync sense on the output stream) boundary */
  950 
  951         rc = inflate(&(zr->strm), Z_SYNC_FLUSH);
  952         switch (rc) {
  953         case Z_STREAM_END:
  954             eoz = 1;
  955         case Z_BUF_ERROR:
  956         case Z_OK:
  957             if (zr->strm.avail_out == 0 || eoz) {
  958                 /* If this was at the start of a block, try submitting it */
  959                 if (!(zr->outoffset % blocksize)) {
  960                     int rc;
  961 
  962                     if (zr->strm.avail_out)
  963                         memset(zr->strm.next_out, 0, zr->strm.avail_out);
  964                     rc = zsync_submit_data(zr->zs, zr->outbuf,
  965                                            zr->outoffset, 1);
  966                     if (!zr->strm.avail_out)
  967                         ret |= rc;
  968                     zr->outoffset += blocksize;
  969                 }
  970                 else {
  971                     /* We were reading a block fragment; update outoffset, and we are now block-aligned. */
  972                     zr->outoffset += (zr->strm.next_out - zr->outbuf);
  973                 }
  974                 zr->strm.avail_out = blocksize;
  975                 zr->strm.next_out = zr->outbuf;
  976             }
  977             break;
  978         default:
  979             fprintf(stderr, "zlib error: %s (%d)\n", zr->strm.msg, rc);
  980             eoz = 1;
  981             ret = -1;
  982             break;
  983         }
  984     }
  985     return ret;
  986 }
  987 
  988 /* zsync_receive_data(self, buf[], offset, buflen)
  989  * Passes data received from the source URL at the given offset; 
  990  * data is buflen bytes in buf[].
  991  * Returns 0 unless there's an error (e.g. the submitted data doesn't match the
  992  * expected checksum for the corresponding blocks)
  993  */
  994 int zsync_receive_data(struct zsync_receiver *zr, const unsigned char *buf,
  995                        off_t offset, size_t len) {
  996     if (zr->url_type == 1) {
  997         return zsync_receive_data_compressed(zr, buf, offset, len);
  998     }
  999     else {
 1000         return zsync_receive_data_uncompressed(zr, buf, offset, len);
 1001     }
 1002 }
 1003 
 1004 /* Destructor */
 1005 void zsync_end_receive(struct zsync_receiver *zr) {
 1006     if (zr->strm.total_in > 0) {
 1007         inflateEnd(&(zr->strm));
 1008     }
 1009     free(zr->outbuf);
 1010     free(zr);
 1011 }