root/ext/zip/lib/zip_close.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zip_close
  2. add_data
  3. copy_data
  4. copy_source
  5. write_cdir
  6. _zip_changed
  7. _zip_create_temp_output
  8. _zip_torrentzip_cmp

   1 /*
   2   zip_close.c -- close zip archive and update changes
   3   Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner
   4 
   5   This file is part of libzip, a library to manipulate ZIP archives.
   6   The authors can be contacted at <libzip@nih.at>
   7 
   8   Redistribution and use in source and binary forms, with or without
   9   modification, are permitted provided that the following conditions
  10   are met:
  11   1. Redistributions of source code must retain the above copyright
  12      notice, this list of conditions and the following disclaimer.
  13   2. Redistributions in binary form must reproduce the above copyright
  14      notice, this list of conditions and the following disclaimer in
  15      the documentation and/or other materials provided with the
  16      distribution.
  17   3. The names of the authors may not be used to endorse or promote
  18      products derived from this software without specific prior
  19      written permission.
  20  
  21   THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
  22   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  23   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
  25   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  27   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  28   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  29   IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  30   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  31   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32 */
  33 
  34 
  35 
  36 #include "zipint.h"
  37 
  38 #include <stdio.h>
  39 #include <stdlib.h>
  40 #include <string.h>
  41 #ifdef HAVE_STRINGS_H
  42 #include <strings.h>
  43 #endif
  44 #include <errno.h>
  45 #ifdef HAVE_UNISTD_H
  46 #include <unistd.h>
  47 #endif
  48 #include <sys/types.h>
  49 #include <sys/stat.h>
  50 #ifdef _WIN32
  51 #include <io.h>
  52 #include <fcntl.h>
  53 #endif
  54 
  55 
  56 
  57 /* max deflate size increase: size + ceil(size/16k)*5+6 */
  58 #define MAX_DEFLATE_SIZE_32     4293656963u
  59 
  60 static int add_data(struct zip *, struct zip_source *, struct zip_dirent *, FILE *);
  61 static int copy_data(FILE *, zip_uint64_t, FILE *, struct zip_error *);
  62 static int copy_source(struct zip *, struct zip_source *, FILE *);
  63 static int write_cdir(struct zip *, const struct zip_filelist *, zip_uint64_t, FILE *);
  64 static char *_zip_create_temp_output(struct zip *, FILE **);
  65 static int _zip_torrentzip_cmp(const void *, const void *);
  66 
  67 
  68 
  69 ZIP_EXTERN int
  70 zip_close(struct zip *za)
  71 {
  72     zip_uint64_t i, j, survivors;
  73     int error;
  74     char *temp;
  75     FILE *out;
  76 #ifndef _WIN32
  77     mode_t mask;
  78 #endif
  79     struct zip_filelist *filelist;
  80     int reopen_on_error;
  81     int new_torrentzip;
  82     int changed;
  83 
  84     reopen_on_error = 0;
  85 
  86     if (za == NULL)
  87         return -1;
  88 
  89     changed = _zip_changed(za, &survivors);
  90 
  91     /* don't create zip files with no entries */
  92     if (survivors == 0) {
  93         if (za->zn && ((za->open_flags & ZIP_TRUNCATE) || (changed && za->zp))) {
  94             if (remove(za->zn) != 0) {
  95                 _zip_error_set(&za->error, ZIP_ER_REMOVE, errno);
  96                 return -1;
  97             }
  98         }
  99         zip_discard(za);
 100         return 0;
 101     }          
 102 
 103     if (!changed) {
 104         zip_discard(za);
 105         return 0;
 106     }
 107 
 108     if (survivors > za->nentry) {
 109         _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
 110         return -1;
 111     }
 112     
 113     if ((filelist=(struct zip_filelist *)malloc(sizeof(filelist[0])*(size_t)survivors)) == NULL)
 114         return -1;
 115 
 116     /* archive comment is special for torrentzip */
 117     if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) {
 118         /* TODO: use internal function when zip_set_archive_comment clears TORRENT flag */
 119         if (zip_set_archive_comment(za, TORRENT_SIG "XXXXXXXX", TORRENT_SIG_LEN + TORRENT_CRC_LEN) < 0) {
 120             free(filelist);
 121             return -1;
 122         }
 123     }
 124     /* TODO: if no longer torrentzip and archive comment not changed by user, delete it */
 125 
 126 
 127     /* create list of files with index into original archive  */
 128     for (i=j=0; i<za->nentry; i++) {
 129         if (za->entry[i].deleted)
 130             continue;
 131 
 132         if (j >= survivors) {
 133             free(filelist);
 134             _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
 135             return -1;
 136         }
 137         
 138         filelist[j].idx = i;
 139         filelist[j].name = zip_get_name(za, i, 0);
 140         j++;
 141     }
 142     if (j < survivors) {
 143         free(filelist);
 144         _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
 145         return -1;
 146     }
 147 
 148 
 149     if ((temp=_zip_create_temp_output(za, &out)) == NULL) {
 150         free(filelist);
 151         return -1;
 152     }
 153     
 154     
 155     if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0))
 156         qsort(filelist, (size_t)survivors, sizeof(filelist[0]),
 157               _zip_torrentzip_cmp);
 158 
 159     new_torrentzip = (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 1
 160                       && zip_get_archive_flag(za, ZIP_AFL_TORRENT,
 161                                               ZIP_FL_UNCHANGED) == 0);
 162     error = 0;
 163     for (j=0; j<survivors; j++) {
 164         int new_data;
 165         struct zip_entry *entry;
 166         struct zip_dirent *de;
 167 
 168         i = filelist[j].idx;
 169         entry = za->entry+i;
 170 
 171         new_data = (ZIP_ENTRY_DATA_CHANGED(entry) || new_torrentzip || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_COMP_METHOD));
 172 
 173         /* create new local directory entry */
 174         if (entry->changes == NULL) {
 175             if ((entry->changes=_zip_dirent_clone(entry->orig)) == NULL) {
 176                 _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
 177                 error = 1;
 178                 break;
 179             }
 180         }
 181         de = entry->changes;
 182 
 183         if (_zip_read_local_ef(za, i) < 0) {
 184             error = 1;
 185             break;
 186         }
 187 
 188         if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0))
 189             _zip_dirent_torrent_normalize(entry->changes);
 190 
 191 
 192         de->offset = (zip_uint64_t)ftello(out); /* TODO: check for errors */
 193 
 194         if (new_data) {
 195             struct zip_source *zs;
 196 
 197             zs = NULL;
 198             if (!ZIP_ENTRY_DATA_CHANGED(entry)) {
 199                 if ((zs=_zip_source_zip_new(za, za, i, ZIP_FL_UNCHANGED, 0, 0, NULL)) == NULL) {
 200                     error = 1;
 201                     break;
 202                 }
 203             }
 204 
 205             /* add_data writes dirent */
 206             if (add_data(za, zs ? zs : entry->source, de, out) < 0) {
 207                 error = 1;
 208                 if (zs)
 209                     zip_source_free(zs);
 210                 break;
 211             }
 212             if (zs)
 213                 zip_source_free(zs);
 214         }
 215         else {
 216             zip_uint64_t offset;
 217 
 218             /* when copying data, all sizes are known -> no data descriptor needed */
 219             de->bitflags &= ~ZIP_GPBF_DATA_DESCRIPTOR;
 220             if (_zip_dirent_write(de, out, ZIP_FL_LOCAL, &za->error) < 0) {
 221                 error = 1;
 222                 break;
 223             }
 224             if ((offset=_zip_file_get_offset(za, i, &za->error)) == 0) {
 225                 error = 1;
 226                 break;
 227             }
 228             if ((fseeko(za->zp, (off_t)offset, SEEK_SET) < 0)) {
 229                 _zip_error_set(&za->error, ZIP_ER_SEEK, errno);
 230                 error = 1;
 231                 break;
 232             }
 233             if (copy_data(za->zp, de->comp_size, out, &za->error) < 0) {
 234                 error = 1;
 235                 break;
 236             }
 237         }
 238     }
 239 
 240     if (!error) {
 241         if (write_cdir(za, filelist, survivors, out) < 0)
 242             error = 1;
 243     }
 244 
 245     free(filelist);
 246 
 247     if (error) {
 248         fclose(out);
 249         (void)remove(temp);
 250         free(temp);
 251         return -1;
 252     }
 253 
 254     if (fclose(out) != 0) {
 255         _zip_error_set(&za->error, ZIP_ER_CLOSE, errno);
 256         (void)remove(temp);
 257         free(temp);
 258         return -1;
 259     }
 260     
 261     if (za->zp) {
 262         fclose(za->zp);
 263         za->zp = NULL;
 264         reopen_on_error = 1;
 265     }
 266     if (_zip_rename(temp, za->zn) != 0) {
 267         _zip_error_set(&za->error, ZIP_ER_RENAME, errno);
 268         (void)remove(temp);
 269         free(temp);
 270         if (reopen_on_error) {
 271             /* ignore errors, since we're already in an error case */
 272             za->zp = fopen(za->zn, "rb");
 273         }
 274         return -1;
 275     }
 276 #ifndef _WIN32
 277     mask = umask(0);
 278     umask(mask);
 279     chmod(za->zn, 0666&~mask);
 280 #endif
 281 
 282     zip_discard(za);
 283     free(temp);
 284     
 285     return 0;
 286 }
 287 
 288 
 289 
 290 static int
 291 add_data(struct zip *za, struct zip_source *src, struct zip_dirent *de, FILE *ft)
 292 {
 293     off_t offstart, offdata, offend;
 294     struct zip_stat st;
 295     struct zip_source *s2;
 296     int ret;
 297     int is_zip64;
 298     zip_flags_t flags;
 299     
 300     if (zip_source_stat(src, &st) < 0) {
 301         _zip_error_set_from_source(&za->error, src);
 302         return -1;
 303     }
 304 
 305     if ((st.valid & ZIP_STAT_COMP_METHOD) == 0) {
 306         st.valid |= ZIP_STAT_COMP_METHOD;
 307         st.comp_method = ZIP_CM_STORE;
 308     }
 309 
 310     if (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != ZIP_CM_STORE)
 311         de->comp_method = st.comp_method;
 312     else if (de->comp_method == ZIP_CM_STORE && (st.valid & ZIP_STAT_SIZE)) {
 313         st.valid |= ZIP_STAT_COMP_SIZE;
 314         st.comp_size = st.size;
 315     }
 316     else {
 317         /* we'll recompress */
 318         st.valid &= ~ZIP_STAT_COMP_SIZE;
 319     }
 320 
 321 
 322     flags = ZIP_EF_LOCAL;
 323 
 324     if ((st.valid & ZIP_STAT_SIZE) == 0)
 325         flags |= ZIP_FL_FORCE_ZIP64;
 326     else {
 327         de->uncomp_size = st.size;
 328         
 329         if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) {
 330             if (( ((de->comp_method == ZIP_CM_DEFLATE || ZIP_CM_IS_DEFAULT(de->comp_method)) && st.size > MAX_DEFLATE_SIZE_32)
 331                  || (de->comp_method != ZIP_CM_STORE && de->comp_method != ZIP_CM_DEFLATE && !ZIP_CM_IS_DEFAULT(de->comp_method))))
 332                 flags |= ZIP_FL_FORCE_ZIP64;
 333         }
 334         else
 335             de->comp_size = st.comp_size;
 336     }
 337 
 338 
 339     offstart = ftello(ft);
 340 
 341     /* as long as we don't support non-seekable output, clear data descriptor bit */
 342     de->bitflags &= ~ZIP_GPBF_DATA_DESCRIPTOR;
 343     if ((is_zip64=_zip_dirent_write(de, ft, flags, &za->error)) < 0)
 344         return -1;
 345 
 346 
 347     if (st.comp_method == ZIP_CM_STORE || (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != de->comp_method)) {
 348         struct zip_source *s_store, *s_crc;
 349         zip_compression_implementation comp_impl;
 350         
 351         if (st.comp_method != ZIP_CM_STORE) {
 352             if ((comp_impl=_zip_get_compression_implementation(st.comp_method)) == NULL) {
 353                 _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
 354                 return -1;
 355             }
 356             if ((s_store=comp_impl(za, src, st.comp_method, ZIP_CODEC_DECODE)) == NULL) {
 357                 /* error set by comp_impl */
 358                 return -1;
 359             }
 360         }
 361         else
 362             s_store = src;
 363 
 364         if ((s_crc=zip_source_crc(za, s_store, 0)) == NULL) {
 365             if (s_store != src)
 366                 zip_source_pop(s_store);
 367             return -1;
 368         }
 369 
 370         /* TODO: deflate 0-byte files for torrentzip? */
 371         if (de->comp_method != ZIP_CM_STORE && ((st.valid & ZIP_STAT_SIZE) == 0 || st.size != 0)) {
 372             if ((comp_impl=_zip_get_compression_implementation(de->comp_method)) == NULL) {
 373                 _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
 374                 zip_source_pop(s_crc);
 375                 if (s_store != src)
 376                     zip_source_pop(s_store);
 377                 return -1;
 378             }
 379             if ((s2=comp_impl(za, s_crc, de->comp_method, ZIP_CODEC_ENCODE)) == NULL) {
 380                 zip_source_pop(s_crc);
 381                 if (s_store != src)
 382                     zip_source_pop(s_store);
 383                 return -1;
 384             }
 385         }
 386         else
 387             s2 = s_crc;
 388     }
 389     else
 390         s2 = src;
 391 
 392     offdata = ftello(ft);
 393         
 394     ret = copy_source(za, s2, ft);
 395         
 396     if (zip_source_stat(s2, &st) < 0)
 397         ret = -1;
 398     
 399     while (s2 != src) {
 400         if ((s2=zip_source_pop(s2)) == NULL) {
 401             /* TODO: set erorr */
 402             ret = -1;
 403             break;
 404         }
 405     }
 406 
 407     if (ret < 0)
 408         return -1;
 409 
 410     offend = ftello(ft);
 411 
 412     if (fseeko(ft, offstart, SEEK_SET) < 0) {
 413         _zip_error_set(&za->error, ZIP_ER_SEEK, errno);
 414         return -1;
 415     }
 416 
 417     if ((st.valid & (ZIP_STAT_COMP_METHOD|ZIP_STAT_CRC|ZIP_STAT_SIZE)) != (ZIP_STAT_COMP_METHOD|ZIP_STAT_CRC|ZIP_STAT_SIZE)) {
 418         _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
 419         return -1;
 420     }
 421 
 422     if (st.valid & ZIP_STAT_MTIME)
 423         de->last_mod = st.mtime;
 424     else
 425         time(&de->last_mod);
 426     de->comp_method = st.comp_method;
 427     de->crc = st.crc;
 428     de->uncomp_size = st.size;
 429     de->comp_size = (zip_uint64_t)(offend - offdata);
 430 
 431     if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0))
 432         _zip_dirent_torrent_normalize(de);
 433 
 434     if ((ret=_zip_dirent_write(de, ft, flags, &za->error)) < 0)
 435         return -1;
 436  
 437     if (is_zip64 != ret) {
 438         /* Zip64 mismatch between preliminary file header written before data and final file header written afterwards */
 439         _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
 440         return -1;
 441     }
 442 
 443    
 444     if (fseeko(ft, offend, SEEK_SET) < 0) {
 445         _zip_error_set(&za->error, ZIP_ER_SEEK, errno);
 446         return -1;
 447     }
 448 
 449     return 0;
 450 }
 451 
 452 
 453 
 454 static int
 455 copy_data(FILE *fs, zip_uint64_t len, FILE *ft, struct zip_error *error)
 456 {
 457     char buf[BUFSIZE];
 458     size_t n, nn;
 459 
 460     if (len == 0)
 461         return 0;
 462 
 463     while (len > 0) {
 464         nn = len > sizeof(buf) ? sizeof(buf) : len > SIZE_MAX ? SIZE_MAX : (size_t)len;
 465         if ((n=fread(buf, 1, nn, fs)) == 0) {
 466             if (ferror(fs)) {
 467                 _zip_error_set(error, ZIP_ER_READ, errno);
 468                 return -1;
 469             }
 470             else {
 471                 _zip_error_set(error, ZIP_ER_EOF, 0);
 472                 return -1;
 473             }
 474         }
 475 
 476         if (fwrite(buf, 1, n, ft) != (size_t)n) {
 477             _zip_error_set(error, ZIP_ER_WRITE, errno);
 478             return -1;
 479         }
 480         
 481         len -= n;
 482     }
 483 
 484     return 0;
 485 }
 486 
 487 
 488 
 489 static int
 490 copy_source(struct zip *za, struct zip_source *src, FILE *ft)
 491 {
 492     char buf[BUFSIZE];
 493     zip_int64_t n;
 494     int ret;
 495 
 496     if (zip_source_open(src) < 0) {
 497         _zip_error_set_from_source(&za->error, src);
 498         return -1;
 499     }
 500 
 501     ret = 0;
 502     while ((n=zip_source_read(src, buf, sizeof(buf))) > 0) {
 503         if (fwrite(buf, 1, (size_t)n, ft) != (size_t)n) {
 504             _zip_error_set(&za->error, ZIP_ER_WRITE, errno);
 505             ret = -1;
 506             break;
 507         }
 508     }
 509     
 510     if (n < 0) {
 511         if (ret == 0)
 512             _zip_error_set_from_source(&za->error, src);
 513         ret = -1;
 514     }   
 515 
 516     zip_source_close(src);
 517     
 518     return ret;
 519 }
 520 
 521 
 522 
 523 static int
 524 write_cdir(struct zip *za, const struct zip_filelist *filelist, zip_uint64_t survivors, FILE *out)
 525 {
 526     off_t cd_start, end;
 527     zip_int64_t size;
 528     uLong crc;
 529     char buf[TORRENT_CRC_LEN+1];
 530     
 531     cd_start = ftello(out);
 532 
 533     if ((size=_zip_cdir_write(za, filelist, survivors, out)) < 0)
 534         return -1;
 535     
 536     end = ftello(out);
 537 
 538     if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0)
 539         return 0;
 540 
 541 
 542     /* fix up torrentzip comment */
 543 
 544     if (_zip_filerange_crc(out, cd_start, size, &crc, &za->error) < 0)
 545         return -1;
 546 
 547     snprintf(buf, sizeof(buf), "%08lX", (long)crc);
 548 
 549     if (fseeko(out, end-TORRENT_CRC_LEN, SEEK_SET) < 0) {
 550         _zip_error_set(&za->error, ZIP_ER_SEEK, errno);
 551         return -1;
 552     }
 553 
 554     if (fwrite(buf, TORRENT_CRC_LEN, 1, out) != 1) {
 555         _zip_error_set(&za->error, ZIP_ER_WRITE, errno);
 556         return -1;
 557     }
 558 
 559     return 0;
 560 }
 561 
 562 
 563 
 564 int
 565 _zip_changed(const struct zip *za, zip_uint64_t *survivorsp)
 566 {
 567     int changed;
 568     zip_uint64_t i, survivors;
 569 
 570     changed = 0;
 571     survivors = 0;
 572 
 573     if (za->comment_changed || za->ch_flags != za->flags)
 574         changed = 1;
 575 
 576     for (i=0; i<za->nentry; i++) {
 577         if (za->entry[i].deleted || za->entry[i].source || (za->entry[i].changes && za->entry[i].changes->changed != 0))
 578             changed = 1;
 579         if (!za->entry[i].deleted)
 580             survivors++;
 581     }
 582 
 583     if (survivorsp)
 584         *survivorsp = survivors;
 585 
 586     return changed;
 587 }
 588 
 589 
 590 
 591 static char *
 592 _zip_create_temp_output(struct zip *za, FILE **outp)
 593 {
 594     char *temp;
 595     int tfd;
 596     FILE *tfp;
 597     
 598     if (za->tempdir) {
 599         if ((temp=(char *)malloc(strlen(za->tempdir)+13)) == NULL) {
 600             _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
 601             return NULL;
 602         }
 603         sprintf(temp, "%s/.zip.XXXXXX", za->tempdir);
 604     }
 605     else {
 606         if ((temp=(char *)malloc(strlen(za->zn)+8)) == NULL) {
 607             _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
 608             return NULL;
 609         }
 610         sprintf(temp, "%s.XXXXXX", za->zn);
 611     }
 612 
 613     if ((tfd=mkstemp(temp)) == -1) {
 614         _zip_error_set(&za->error, ZIP_ER_TMPOPEN, errno);
 615         free(temp);
 616         return NULL;
 617     }
 618     
 619     if ((tfp=fdopen(tfd, "r+b")) == NULL) {
 620         _zip_error_set(&za->error, ZIP_ER_TMPOPEN, errno);
 621         close(tfd);
 622         (void)remove(temp);
 623         free(temp);
 624         return NULL;
 625     }
 626 
 627 #ifdef _WIN32
 628     /*
 629       According to Pierre Joye, Windows in some environments per
 630       default creates text files, so force binary mode.
 631     */
 632     _setmode(_fileno(tfp), _O_BINARY );
 633 #endif
 634 
 635     *outp = tfp;
 636     return temp;
 637 }
 638 
 639 
 640 
 641 static int
 642 _zip_torrentzip_cmp(const void *a, const void *b)
 643 {
 644     const char *aname = ((const struct zip_filelist *)a)->name;
 645     const char *bname = ((const struct zip_filelist *)b)->name;
 646 
 647     if (aname == NULL)
 648         return (bname != NULL) * -1;
 649     else if (bname == NULL)
 650         return 1;
 651 
 652     return strcasecmp(aname, bname);
 653 }

/* [<][>][^][v][top][bottom][index][help] */