"Fossies" - the Fresh Open Source Software Archive

Member "zsync-0.6.2/client.c" (19 Sep 2010, 22733 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 "client.c" see the Fossies "Dox" file reference documentation.

A hint: This file contains one or more very long lines, so maybe it is better readable using the pure text view mode that shows the contents as wrapped lines within the browser window.


    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 /* zsync command-line client program */
   18 
   19 #include "zsglobal.h"
   20 
   21 #include <stdio.h>
   22 #include <stdlib.h>
   23 #include <string.h>
   24 
   25 #include <unistd.h>
   26 #include <fcntl.h>
   27 #include <errno.h>
   28 #include <ctype.h>
   29 #include <sys/types.h>
   30 #include <sys/stat.h>
   31 #include <utime.h>
   32 
   33 #ifdef WITH_DMALLOC
   34 # include <dmalloc.h>
   35 #endif
   36 
   37 #include "libzsync/zsync.h"
   38 
   39 #include "http.h"
   40 #include "url.h"
   41 #include "progress.h"
   42 
   43 /* FILE* f = open_zcat_pipe(file_str)
   44  * Returns a (popen) filehandle which when read returns the un-gzipped content
   45  * of the given file. Or NULL on error; or the filehandle may fail to read. It
   46  * is up to the caller to call pclose() on the handle and check the return
   47  * value of that.
   48  */
   49 FILE* open_zcat_pipe(const char* fname)
   50 {
   51     /* Get buffer to build command line */
   52     char *cmd = malloc(6 + strlen(fname) * 2);
   53     if (!cmd)
   54         return NULL;
   55 
   56     strcpy(cmd, "zcat ");
   57     {   /* Add filename to commandline, escaping any characters that the shell
   58          *might consider special. */
   59         int i, j;
   60 
   61         for (i = 0, j = 5; fname[i]; i++) {
   62             if (!isalnum(fname[i]))
   63                 cmd[j++] = '\\';
   64             cmd[j++] = fname[i];
   65         }
   66         cmd[j] = 0;
   67     }
   68 
   69     if (!no_progress)
   70         fprintf(stderr, "reading seed %s: ", cmd);
   71     {   /* Finally, open the subshell for reading, and return the handle */
   72         FILE* f = popen(cmd, "r");
   73         free(cmd);
   74         return f;
   75     }
   76 }
   77 
   78 /* read_seed_file(zsync, filename_str)
   79  * Reads the given file (decompressing it if appropriate) and applies the rsync
   80  * checksum algorithm to it, so any data that is contained in the target file
   81  * is written to the in-progress target. So use this function to supply local
   82  * source files which are believed to have data in common with the target.
   83  */
   84 void read_seed_file(struct zsync_state *z, const char *fname) {
   85     /* If we should decompress this file */
   86     if (zsync_hint_decompress(z) && strlen(fname) > 3
   87         && !strcmp(fname + strlen(fname) - 3, ".gz")) {
   88         /* Open for reading */
   89         FILE *f = open_zcat_pipe(fname);
   90         if (!f) {
   91             perror("popen");
   92             fprintf(stderr, "not using seed file %s\n", fname);
   93         }
   94         else {
   95 
   96             /* Give the contents to libzsync to read and find any useful
   97              * content */
   98             zsync_submit_source_file(z, f, !no_progress);
   99 
  100             /* Close and check for errors */
  101             if (pclose(f) != 0) {
  102                 perror("close");
  103             }
  104         }
  105     }
  106     else {
  107         /* Simple uncompressed file - open it */
  108         FILE *f = fopen(fname, "r");
  109         if (!f) {
  110             perror("open");
  111             fprintf(stderr, "not using seed file %s\n", fname);
  112         }
  113         else {
  114 
  115             /* Give the contents to libzsync to read, to find any content that
  116              * is part of the target file. */
  117             if (!no_progress)
  118                 fprintf(stderr, "reading seed file %s: ", fname);
  119             zsync_submit_source_file(z, f, !no_progress);
  120 
  121             /* And close */
  122             if (fclose(f) != 0) {
  123                 perror("close");
  124             }
  125         }
  126     }
  127 
  128     {   /* And print how far we've progressed towards the target file */
  129         long long done, total;
  130 
  131         zsync_progress(z, &done, &total);
  132         if (!no_progress)
  133             fprintf(stderr, "\rRead %s. Target %02.1f%% complete.      \n",
  134                     fname, (100.0f * done) / total);
  135     }
  136 }
  137 
  138 long long http_down;
  139 
  140 /* A ptrlist is a very simple structure for storing lists of pointers. This is
  141  * the only function in its API. The structure (not actually a struct) consists
  142  * of a (pointer to a) void*[] and an int giving the number of entries.
  143  *
  144  * ptrlist = append_ptrlist(&entries, ptrlist, new_entry)
  145  * Like realloc(2), this returns the new location of the ptrlist array; the
  146  * number of entries is passed by reference and updated in place. The new entry
  147  * is appended to the list.
  148  */
  149 static void **append_ptrlist(int *n, void **p, void *a) {
  150     if (!a)
  151         return p;
  152     p = realloc(p, (*n + 1) * sizeof *p);
  153     if (!p) {
  154         fprintf(stderr, "out of memory\n");
  155         exit(1);
  156     }
  157     p[*n] = a;
  158     (*n)++;
  159     return p;
  160 }
  161 
  162 /* zs = read_zsync_control_file(location_str, filename)
  163  * Reads a zsync control file from either a URL or filename specified in
  164  * location_str. This is treated as a URL if no local file exists of that name
  165  * and it starts with a URL scheme ; only http URLs are supported.
  166  * Second parameter is a filename in which to locally save the content of the
  167  * .zsync _if it is retrieved from a URL_; can be NULL in which case no local
  168  * copy is made.
  169  */
  170 struct zsync_state *read_zsync_control_file(const char *p, const char *fn) {
  171     FILE *f;
  172     struct zsync_state *zs;
  173     char *lastpath = NULL;
  174 
  175     /* Try opening as a local path */
  176     f = fopen(p, "r");
  177     if (!f) {
  178         /* No such local file - if not a URL either, report error */
  179         if (!is_url_absolute(p)) {
  180             perror(p);
  181             exit(2);
  182         }
  183 
  184         /* Try URL fetch */
  185         f = http_get(p, &lastpath, fn);
  186         if (!f) {
  187             fprintf(stderr, "could not read control file from URL %s\n", p);
  188             exit(3);
  189         }
  190         referer = lastpath;
  191     }
  192 
  193     /* Read the .zsync */
  194     if ((zs = zsync_begin(f)) == NULL) {
  195         exit(1);
  196     }
  197 
  198     /* And close it */
  199     if (fclose(f) != 0) {
  200         perror("fclose");
  201         exit(2);
  202     }
  203     return zs;
  204 }
  205 
  206 /* str = get_filename_prefix(path_str)
  207  * Returns a (malloced) string of the alphanumeric leading segment of the
  208  * filename in the given file path.
  209  */
  210 static char *get_filename_prefix(const char *p) {
  211     char *s = strdup(p);
  212     char *t = strrchr(s, '/');
  213     char *u;
  214 
  215     if (t)
  216         *t++ = 0;
  217     else
  218         t = s;
  219     u = t;
  220     while (isalnum(*u)) {
  221         u++;
  222     }
  223     *u = 0;
  224     if (*t > 0)
  225         t = strdup(t);
  226     else
  227         t = NULL;
  228     free(s);
  229     return t;
  230 }
  231 
  232 /* filename_str = get_filename(zs, source_filename_str)
  233  * Returns a (malloced string with a) suitable filename for a zsync download,
  234  * using the given zsync state and source filename strings as hints. */
  235 char *get_filename(const struct zsync_state *zs, const char *source_name) {
  236     char *p = zsync_filename(zs);
  237     char *filename = NULL;
  238 
  239     if (p) {
  240         if (strchr(p, '/')) {
  241             fprintf(stderr,
  242                     "Rejected filename specified in %s, contained path component.\n",
  243                     source_name);
  244             free(p);
  245         }
  246         else {
  247             char *t = get_filename_prefix(source_name);
  248 
  249             if (t && !memcmp(p, t, strlen(t)))
  250                 filename = p;
  251             else
  252                 free(p);
  253 
  254             if (t && !filename) {
  255                 fprintf(stderr,
  256                         "Rejected filename specified in %s - prefix %s differed from filename %s.\n",
  257                         source_name, t, p);
  258             }
  259             free(t);
  260         }
  261     }
  262     if (!filename) {
  263         filename = get_filename_prefix(source_name);
  264         if (!filename)
  265             filename = strdup("zsync-download");
  266     }
  267     return filename;
  268 }
  269 
  270 /* prog = calc_zsync_progress(zs)
  271  * Returns the progress ratio 0..1 (none...done) for the given zsync_state */
  272 static float calc_zsync_progress(const struct zsync_state *zs) {
  273     long long zgot, ztot;
  274 
  275     zsync_progress(zs, &zgot, &ztot);
  276     return (100.0f * zgot / ztot);
  277 }
  278 
  279 /* fetch_remaining_blocks_http(zs, url, type)
  280  * For the given zsync_state, using the given URL (which is a copy of the
  281  * actual content of the target file is type == 0, or a compressed copy of it
  282  * if type == 1), retrieve the parts of the target that are currently missing. 
  283  * Returns true if this URL was useful, false if we crashed and burned.
  284  */
  285 #define BUFFERSIZE 8192
  286 
  287 int fetch_remaining_blocks_http(struct zsync_state *z, const char *url,
  288                                 int type) {
  289     int ret = 0;
  290     struct range_fetch *rf;
  291     unsigned char *buf;
  292     struct zsync_receiver *zr;
  293 
  294     /* URL might be relative - we need an absolute URL to do a fetch */
  295     char *u = make_url_absolute(referer, url);
  296     if (!u) {
  297         fprintf(stderr,
  298                 "URL '%s' from the .zsync file is relative, but I don't know the referer URL (you probably downloaded the .zsync separately and gave it to me as a file). I need to know the referring URL (the URL of the .zsync) in order to locate the download. You can specify this with -u (or edit the URL line(s) in the .zsync file you have).\n",
  299                 url);
  300         return -1;
  301     }
  302 
  303     /* Start a range fetch and a zsync receiver */
  304     rf = range_fetch_start(u);
  305     if (!rf) {
  306         free(u);
  307         return -1;
  308     }
  309     zr = zsync_begin_receive(z, type);
  310     if (!zr) {
  311         range_fetch_end(rf);
  312         free(u);
  313         return -1;
  314     }
  315 
  316     if (!no_progress)
  317         fprintf(stderr, "downloading from %s:", u);
  318 
  319     /* Create a read buffer */
  320     buf = malloc(BUFFERSIZE);
  321     if (!buf) {
  322         zsync_end_receive(zr);
  323         range_fetch_end(rf);
  324         free(u);
  325         return -1;
  326     }
  327 
  328     {   /* Get a set of byte ranges that we need to complete the target */
  329         int nrange;
  330         off_t *zbyterange = zsync_needed_byte_ranges(z, &nrange, type);
  331         if (!zbyterange)
  332             return 1;
  333         if (nrange == 0)
  334             return 0;
  335 
  336         /* And give that to the range fetcher */
  337         range_fetch_addranges(rf, zbyterange, nrange);
  338         free(zbyterange);
  339     }
  340 
  341     {
  342         int len;
  343         off_t zoffset;
  344         struct progress p = { 0, 0, 0, 0 };
  345 
  346         /* Set up progress display to run during the fetch */
  347         if (!no_progress) {
  348             fputc('\n', stderr);
  349             do_progress(&p, calc_zsync_progress(z), range_fetch_bytes_down(rf));
  350         }
  351 
  352         /* Loop while we're receiving data, until we're done or there is an error */
  353         while (!ret
  354                && (len = get_range_block(rf, &zoffset, buf, BUFFERSIZE)) > 0) {
  355             /* Pass received data to the zsync receiver, which writes it to the
  356              * appropriate location in the target file */
  357             if (zsync_receive_data(zr, buf, zoffset, len) != 0)
  358                 ret = 1;
  359 
  360             /* Maintain progress display */
  361             if (!no_progress)
  362                 do_progress(&p, calc_zsync_progress(z),
  363                             range_fetch_bytes_down(rf));
  364 
  365             // Needed in case next call returns len=0 and we need to signal where the EOF was.
  366             zoffset += len;     
  367         }
  368 
  369         /* If error, we need to flag that to our caller */
  370         if (len < 0)
  371             ret = -1;
  372         else    /* Else, let the zsync receiver know that we're at EOF; there
  373                  *could be data in its buffer that it can use or needs to process */
  374             zsync_receive_data(zr, NULL, zoffset, 0);
  375 
  376         if (!no_progress)
  377             end_progress(&p, zsync_status(z) >= 2 ? 2 : len == 0 ? 1 : 0);
  378     }
  379 
  380     /* Clean up */
  381     free(buf);
  382     http_down += range_fetch_bytes_down(rf);
  383     zsync_end_receive(zr);
  384     range_fetch_end(rf);
  385     free(u);
  386     return ret;
  387 }
  388 
  389 /* fetch_remaining_blocks(zs)
  390  * Using the URLs in the supplied zsync state, downloads data to complete the
  391  * target file. 
  392  */
  393 int fetch_remaining_blocks(struct zsync_state *zs) {
  394     int n, utype;
  395     const char *const *url = zsync_get_urls(zs, &n, &utype);
  396     int *status;        /* keep status for each URL - 0 means no error */
  397     int ok_urls = n;
  398 
  399     if (!url) {
  400         fprintf(stderr, "no URLs available from zsync?");
  401         return 1;
  402     }
  403     status = calloc(n, sizeof *status);
  404 
  405     /* Keep going until we're done or have no useful URLs left */
  406     while (zsync_status(zs) < 2 && ok_urls) {
  407         /* Still need data; pick a URL to use. */
  408         int try = rand() % n;
  409 
  410         if (!status[try]) {
  411             const char *tryurl = url[try];
  412 
  413             /* Try fetching data from this URL */
  414             int rc = fetch_remaining_blocks_http(zs, tryurl, utype);
  415             if (rc != 0) {
  416                 fprintf(stderr, "failed to retrieve from %s\n", tryurl);
  417                 status[try] = 1;
  418                 ok_urls--;
  419             }
  420         }
  421     }
  422     free(status);
  423     return 0;
  424 }
  425 
  426 static int set_mtime(char* filename, time_t mtime) {
  427     struct stat s;
  428     struct utimbuf u;
  429 
  430     /* Get the access time, which I don't want to modify. */
  431     if (stat(filename, &s) != 0) {
  432         perror("stat");
  433         return -1;
  434     }
  435     
  436     /* Set the modification time. */
  437     u.actime = s.st_atime;
  438     u.modtime = mtime;
  439     if (utime(filename, &u) != 0) {
  440         perror("utime");
  441         return -1;
  442     }
  443     return 0;
  444 }
  445 
  446 /****************************************************************************
  447  *
  448  * Main program */
  449 int main(int argc, char **argv) {
  450     struct zsync_state *zs;
  451     char *temp_file = NULL;
  452     char **seedfiles = NULL;
  453     int nseedfiles = 0;
  454     char *filename = NULL;
  455     long long local_used;
  456     char *zfname = NULL;
  457     time_t mtime;
  458 
  459     srand(getpid());
  460     {   /* Option parsing */
  461         int opt;
  462 
  463         while ((opt = getopt(argc, argv, "A:k:o:i:Vsqu:")) != -1) {
  464             switch (opt) {
  465             case 'A':           /* Authentication options for remote server */
  466                 {               /* Scan string as hostname=username:password */
  467                     char *p = strdup(optarg);
  468                     char *q = strchr(p, '=');
  469                     char *r = q ? strchr(q, ':') : NULL;
  470 
  471                     if (!q || !r) {
  472                         fprintf(stderr,
  473                                 "-A takes hostname=username:password\n");
  474                         exit(1);
  475                     }
  476                     else {
  477                         *q++ = *r++ = 0;
  478                         add_auth(p, q, r);
  479                     }
  480                 }
  481                 break;
  482             case 'k':
  483                 free(zfname);
  484                 zfname = strdup(optarg);
  485                 break;
  486             case 'o':
  487                 free(filename);
  488                 filename = strdup(optarg);
  489                 break;
  490             case 'i':
  491                 seedfiles = append_ptrlist(&nseedfiles, seedfiles, optarg);
  492                 break;
  493             case 'V':
  494                 printf(PACKAGE " v" VERSION " (compiled " __DATE__ " " __TIME__
  495                        ")\n" "By Colin Phipps <cph@moria.org.uk>\n"
  496                        "Published under the Artistic License v2, see the COPYING file for details.\n");
  497                 exit(0);
  498             case 's':
  499             case 'q':
  500                 no_progress = 1;
  501                 break;
  502             case 'u':
  503                 referer = strdup(optarg);
  504                 break;
  505             }
  506         }
  507     }
  508 
  509     /* Last and only non-option parameter must be the path/URL of the .zsync */
  510     if (optind == argc) {
  511         fprintf(stderr,
  512                 "No .zsync file specified.\nUsage: zsync http://example.com/some/filename.zsync\n");
  513         exit(3);
  514     }
  515     else if (optind < argc - 1) {
  516         fprintf(stderr,
  517                 "Usage: zsync http://example.com/some/filename.zsync\n");
  518         exit(3);
  519     }
  520 
  521     /* No progress display except on terminal */
  522     if (!isatty(0))
  523         no_progress = 1;
  524     {   /* Get proxy setting from the environment */
  525         char *pr = getenv("http_proxy");
  526 
  527         if (pr != NULL)
  528             set_proxy_from_string(pr);
  529     }
  530 
  531     /* STEP 1: Read the zsync control file */
  532     if ((zs = read_zsync_control_file(argv[optind], zfname)) == NULL)
  533         exit(1);
  534 
  535     /* Get eventual filename for output, and filename to write to while working */
  536     if (!filename)
  537         filename = get_filename(zs, argv[optind]);
  538     temp_file = malloc(strlen(filename) + 6);
  539     strcpy(temp_file, filename);
  540     strcat(temp_file, ".part");
  541 
  542     {   /* STEP 2: read available local data and fill in what we know in the
  543          *target file */
  544         int i;
  545 
  546         /* If the target file already exists, we're probably updating that file
  547          * - so it's a seed file */
  548         if (!access(filename, R_OK)) {
  549             seedfiles = append_ptrlist(&nseedfiles, seedfiles, filename);
  550         }
  551         /* If the .part file exists, it's probably an interrupted earlier
  552          * effort; a normal HTTP client would 'resume' from where it got to,
  553          * but zsync can't (because we don't know this data corresponds to the
  554          * current version on the remote) and doesn't need to, because we can
  555          * treat it like any other local source of data. Use it now. */
  556         if (!access(temp_file, R_OK)) {
  557             seedfiles = append_ptrlist(&nseedfiles, seedfiles, temp_file);
  558         }
  559 
  560         /* Try any seed files supplied by the command line */
  561         for (i = 0; i < nseedfiles; i++) {
  562             int dup = 0, j;
  563 
  564             /* And stop reading seed files once the target is complete. */
  565             if (zsync_status(zs) >= 2) break;
  566 
  567             /* Skip dups automatically, to save the person running the program
  568              * having to worry about this stuff. */
  569             for (j = 0; j < i; j++) {
  570                 if (!strcmp(seedfiles[i],seedfiles[j])) dup = 1;
  571             }
  572 
  573             /* And now, if not a duplicate, read it */
  574             if (!dup)
  575                 read_seed_file(zs, seedfiles[i]);
  576         }
  577         /* Show how far that got us */
  578         zsync_progress(zs, &local_used, NULL);
  579 
  580         /* People that don't understand zsync might use it wrongly and end up
  581          * downloading everything. Although not essential, let's hint to them
  582          * that they probably messed up. */
  583         if (!local_used) {
  584             if (!no_progress)
  585                 fputs
  586                     ("No relevent local data found - I will be downloading the whole file. If that's not what you want, CTRL-C out. You should specify the local file is the old version of the file to download with -i (you might have to decompress it with gzip -d first). Or perhaps you just have no data that helps download the file\n",
  587                      stderr);
  588         }
  589     }
  590 
  591     /* libzsync has been writing to a randomely-named temp file so far -
  592      * because we didn't want to overwrite the .part from previous runs. Now
  593      * we've read any previous .part, we can replace it with our new
  594      * in-progress run (which should be a superset of the old .part - unless
  595      * the content changed, in which case it still contains anything relevant
  596      * from the old .part). */
  597     if (zsync_rename_file(zs, temp_file) != 0) {
  598         perror("rename");
  599         exit(1);
  600     }
  601 
  602     /* STEP 3: fetch remaining blocks via the URLs from the .zsync */
  603     if (fetch_remaining_blocks(zs) != 0) {
  604         fprintf(stderr,
  605                 "failed to retrieve all remaining blocks - no valid download URLs remain. Incomplete transfer left in %s.\n(If this is the download filename with .part appended, zsync will automatically pick this up and reuse the data it has already done if you retry in this dir.)\n",
  606                 temp_file);
  607         exit(3);
  608     }
  609 
  610     {   /* STEP 4: verify download */
  611         int r;
  612 
  613         if (!no_progress)
  614             printf("verifying download...");
  615         r = zsync_complete(zs);
  616         switch (r) {
  617         case -1:
  618             fprintf(stderr, "Aborting, download available in %s\n", temp_file);
  619             exit(2);
  620         case 0:
  621             if (!no_progress)
  622                 printf("no recognised checksum found\n");
  623             break;
  624         case 1:
  625             if (!no_progress)
  626                 printf("checksum matches OK\n");
  627             break;
  628         }
  629     }
  630 
  631     free(temp_file);
  632 
  633     /* Get any mtime that we is suggested to set for the file, and then shut
  634      * down the zsync_state as we are done on the file transfer. Getting the
  635      * current name of the file at the same time. */
  636     mtime = zsync_mtime(zs);
  637     temp_file = zsync_end(zs);
  638 
  639     /* STEP 5: Move completed .part file into place as the final target */
  640     if (filename) {
  641         char *oldfile_backup = malloc(strlen(filename) + 8);
  642         int ok = 1;
  643 
  644         strcpy(oldfile_backup, filename);
  645         strcat(oldfile_backup, ".zs-old");
  646 
  647         if (!access(filename, F_OK)) {
  648             /* Backup the old file. */
  649             /* First, remove any previous backup. We don't care if this fails -
  650              * the link below will catch any failure */
  651             unlink(oldfile_backup);
  652 
  653             /* Try linking the filename to the backup file name, so we will 
  654                atomically replace the target file in the next step.
  655                If that fails due to EPERM, it is probably a filesystem that
  656                doesn't support hard-links - so try just renaming it to the
  657                backup filename. */
  658             if (link(filename, oldfile_backup) != 0
  659                 && (errno != EPERM || rename(filename, oldfile_backup) != 0)) {
  660                 perror("linkname");
  661                 fprintf(stderr,
  662                         "Unable to back up old file %s - completed download left in %s\n",
  663                         filename, temp_file);
  664                 ok = 0;         /* Prevent overwrite of old file below */
  665             }
  666         }
  667         if (ok) {
  668             /* Rename the file to the desired name */
  669             if (rename(temp_file, filename) == 0) {
  670                 /* final, final thing - set the mtime on the file if we have one */
  671                 if (mtime != -1) set_mtime(filename, mtime);
  672             }
  673             else {
  674                 perror("rename");
  675                 fprintf(stderr,
  676                         "Unable to back up old file %s - completed download left in %s\n",
  677                         filename, temp_file);
  678             }
  679         }
  680         free(oldfile_backup);
  681         free(filename);
  682     }
  683     else {
  684         printf
  685             ("No filename specified for download - completed download left in %s\n",
  686              temp_file);
  687     }
  688 
  689     /* Final stats and cleanup */
  690     if (!no_progress)
  691         printf("used %lld local, fetched %lld\n", local_used, http_down);
  692     free(referer);
  693     free(temp_file);
  694     return 0;
  695 }