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

   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 #include "zipint.h"
  36 
  37 #include <stdio.h>
  38 #include <stdlib.h>
  39 #include <string.h>
  40 #ifdef HAVE_STRINGS_H
  41 #include <strings.h>
  42 #endif
  43 #ifdef HAVE_UNISTD_H
  44 #include <unistd.h>
  45 #endif
  46 #include <sys/types.h>
  47 #include <sys/stat.h>
  48 #ifdef _WIN32
  49 #include <io.h>
  50 #include <fcntl.h>
  51 #endif
  52 
  53 
  54 /* max deflate size increase: size + ceil(size/16k)*5+6 */
  55 #define MAX_DEFLATE_SIZE_32     4293656963u
  56 
  57 static int add_data(zip_t *, zip_source_t *, zip_dirent_t *);
  58 static int copy_data(zip_t *, zip_uint64_t);
  59 static int copy_source(zip_t *, zip_source_t *);
  60 static int write_cdir(zip_t *, const zip_filelist_t *, zip_uint64_t);
  61 
  62 
  63 ZIP_EXTERN int
  64 zip_close(zip_t *za)
  65 {
  66     zip_uint64_t i, j, survivors;
  67     zip_int64_t off;
  68     int error;
  69     zip_filelist_t *filelist;
  70     int changed;
  71 
  72     if (za == NULL)
  73         return -1;
  74 
  75     changed = _zip_changed(za, &survivors);
  76 
  77     /* don't create zip files with no entries */
  78     if (survivors == 0) {
  79         if ((za->open_flags & ZIP_TRUNCATE) || changed) {
  80             if (zip_source_remove(za->src) < 0) {
  81                 _zip_error_set_from_source(&za->error, za->src);
  82                 return -1;
  83             }
  84         }
  85         zip_discard(za);
  86         return 0;
  87     }          
  88 
  89     if (!changed) {
  90         zip_discard(za);
  91         return 0;
  92     }
  93 
  94     if (survivors > za->nentry) {
  95         zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
  96         return -1;
  97     }
  98     
  99     if ((filelist=(zip_filelist_t *)malloc(sizeof(filelist[0])*(size_t)survivors)) == NULL)
 100         return -1;
 101 
 102     /* create list of files with index into original archive  */
 103     for (i=j=0; i<za->nentry; i++) {
 104         if (za->entry[i].deleted)
 105             continue;
 106 
 107         if (j >= survivors) {
 108             free(filelist);
 109             zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
 110             return -1;
 111         }
 112         
 113         filelist[j].idx = i;
 114         j++;
 115     }
 116     if (j < survivors) {
 117         free(filelist);
 118         zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
 119         return -1;
 120     }
 121 
 122     if (zip_source_begin_write(za->src) < 0) {
 123         _zip_error_set_from_source(&za->error, za->src);
 124         free(filelist);
 125         return -1;
 126     }
 127     
 128     error = 0;
 129     for (j=0; j<survivors; j++) {
 130         int new_data;
 131         zip_entry_t *entry;
 132         zip_dirent_t *de;
 133 
 134         i = filelist[j].idx;
 135         entry = za->entry+i;
 136 
 137         new_data = (ZIP_ENTRY_DATA_CHANGED(entry) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_COMP_METHOD));
 138 
 139         /* create new local directory entry */
 140         if (entry->changes == NULL) {
 141             if ((entry->changes=_zip_dirent_clone(entry->orig)) == NULL) {
 142                 zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
 143                 error = 1;
 144                 break;
 145             }
 146         }
 147         de = entry->changes;
 148 
 149         if (_zip_read_local_ef(za, i) < 0) {
 150             error = 1;
 151             break;
 152         }
 153 
 154         if ((off = zip_source_tell_write(za->src)) < 0) {
 155             error = 1;
 156             break;
 157         }
 158         de->offset = (zip_uint64_t)off;
 159 
 160         if (new_data) {
 161             zip_source_t *zs;
 162 
 163             zs = NULL;
 164             if (!ZIP_ENTRY_DATA_CHANGED(entry)) {
 165                 if ((zs=_zip_source_zip_new(za, za, i, ZIP_FL_UNCHANGED, 0, 0, NULL)) == NULL) {
 166                     error = 1;
 167                     break;
 168                 }
 169             }
 170 
 171             /* add_data writes dirent */
 172             if (add_data(za, zs ? zs : entry->source, de) < 0) {
 173                 error = 1;
 174                 if (zs)
 175                     zip_source_free(zs);
 176                 break;
 177             }
 178             if (zs)
 179                 zip_source_free(zs);
 180         }
 181         else {
 182             zip_uint64_t offset;
 183 
 184             /* when copying data, all sizes are known -> no data descriptor needed */
 185             de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR;
 186             if (_zip_dirent_write(za, de, ZIP_FL_LOCAL) < 0) {
 187                 error = 1;
 188                 break;
 189             }
 190             if ((offset=_zip_file_get_offset(za, i, &za->error)) == 0) {
 191                 error = 1;
 192                 break;
 193             }
 194             if (zip_source_seek(za->src, (zip_int64_t)offset, SEEK_SET) < 0) {
 195                 _zip_error_set_from_source(&za->error, za->src);
 196                 error = 1;
 197                 break;
 198             }
 199             if (copy_data(za, de->comp_size) < 0) {
 200                 error = 1;
 201                 break;
 202             }
 203         }
 204     }
 205 
 206     if (!error) {
 207         if (write_cdir(za, filelist, survivors) < 0)
 208             error = 1;
 209     }
 210 
 211     free(filelist);
 212 
 213     if (!error) {
 214         if (zip_source_commit_write(za->src) != 0) {
 215             _zip_error_set_from_source(&za->error, za->src);
 216             error = 1;
 217         }
 218     }
 219 
 220     if (error) {
 221         zip_source_rollback_write(za->src);
 222         return -1;
 223     }
 224 
 225     zip_discard(za);
 226     
 227     return 0;
 228 }
 229 
 230 
 231 static int
 232 add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de)
 233 {
 234     zip_int64_t offstart, offdata, offend;
 235     struct zip_stat st;
 236     zip_source_t *s2;
 237     int ret;
 238     int is_zip64;
 239     zip_flags_t flags;
 240     
 241     if (zip_source_stat(src, &st) < 0) {
 242         _zip_error_set_from_source(&za->error, src);
 243         return -1;
 244     }
 245 
 246     if ((st.valid & ZIP_STAT_COMP_METHOD) == 0) {
 247         st.valid |= ZIP_STAT_COMP_METHOD;
 248         st.comp_method = ZIP_CM_STORE;
 249     }
 250 
 251     if (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != ZIP_CM_STORE)
 252         de->comp_method = st.comp_method;
 253     else if (de->comp_method == ZIP_CM_STORE && (st.valid & ZIP_STAT_SIZE)) {
 254         st.valid |= ZIP_STAT_COMP_SIZE;
 255         st.comp_size = st.size;
 256     }
 257     else {
 258         /* we'll recompress */
 259         st.valid &= ~ZIP_STAT_COMP_SIZE;
 260     }
 261 
 262 
 263     flags = ZIP_EF_LOCAL;
 264 
 265     if ((st.valid & ZIP_STAT_SIZE) == 0)
 266         flags |= ZIP_FL_FORCE_ZIP64;
 267     else {
 268         de->uncomp_size = st.size;
 269         
 270         if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) {
 271             if (( ((de->comp_method == ZIP_CM_DEFLATE || ZIP_CM_IS_DEFAULT(de->comp_method)) && st.size > MAX_DEFLATE_SIZE_32)
 272                   || (de->comp_method != ZIP_CM_STORE && de->comp_method != ZIP_CM_DEFLATE && !ZIP_CM_IS_DEFAULT(de->comp_method))))
 273                 flags |= ZIP_FL_FORCE_ZIP64;
 274         }
 275         else
 276             de->comp_size = st.comp_size;
 277     }
 278 
 279     if ((offstart = zip_source_tell_write(za->src)) < 0) {
 280         return -1;
 281     }
 282 
 283     /* as long as we don't support non-seekable output, clear data descriptor bit */
 284     de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR;
 285     if ((is_zip64=_zip_dirent_write(za, de, flags)) < 0)
 286         return -1;
 287 
 288 
 289     if (st.comp_method == ZIP_CM_STORE || (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != de->comp_method)) {
 290         zip_source_t *s_store, *s_crc;
 291         zip_compression_implementation comp_impl;
 292         
 293         if (st.comp_method != ZIP_CM_STORE) {
 294             if ((comp_impl=_zip_get_compression_implementation(st.comp_method)) == NULL) {
 295                 zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
 296                 return -1;
 297             }
 298             if ((s_store=comp_impl(za, src, st.comp_method, ZIP_CODEC_DECODE)) == NULL) {
 299                 /* error set by comp_impl */
 300                 return -1;
 301             }
 302         }
 303         else {
 304             /* to have the same reference count to src as in the case where it's not stored */
 305             zip_source_keep(src);
 306             s_store = src;
 307         }
 308 
 309         s_crc = zip_source_crc(za, s_store, 0);
 310         zip_source_free(s_store);
 311         if (s_crc == NULL) {
 312             return -1;
 313         }
 314 
 315         if (de->comp_method != ZIP_CM_STORE && ((st.valid & ZIP_STAT_SIZE) == 0 || st.size != 0)) {
 316             if ((comp_impl=_zip_get_compression_implementation(de->comp_method)) == NULL) {
 317                 zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
 318                 zip_source_free(s_crc);
 319                 return -1;
 320             }
 321             s2 = comp_impl(za, s_crc, de->comp_method, ZIP_CODEC_ENCODE);
 322             zip_source_free(s_crc);
 323             if (s2 == NULL) {
 324                 return -1;
 325             }
 326         }
 327         else {
 328             s2 = s_crc;
 329         }
 330     }
 331     else {
 332         zip_source_keep(src);
 333         s2 = src;
 334     }
 335 
 336     if ((offdata = zip_source_tell_write(za->src)) < 0) {
 337         return -1;
 338     }
 339 
 340     ret = copy_source(za, s2);
 341         
 342     if (zip_source_stat(s2, &st) < 0)
 343         ret = -1;
 344 
 345     zip_source_free(s2);
 346 
 347     if (ret < 0)
 348         return -1;
 349 
 350     if ((offend = zip_source_tell_write(za->src)) < 0) {
 351         return -1;
 352     }
 353 
 354     if (zip_source_seek_write(za->src, offstart, SEEK_SET) < 0) {
 355         _zip_error_set_from_source(&za->error, za->src);
 356         return -1;
 357     }
 358 
 359     if ((st.valid & (ZIP_STAT_COMP_METHOD|ZIP_STAT_CRC|ZIP_STAT_SIZE)) != (ZIP_STAT_COMP_METHOD|ZIP_STAT_CRC|ZIP_STAT_SIZE)) {
 360         zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
 361         return -1;
 362     }
 363 
 364     if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0) {
 365         if (st.valid & ZIP_STAT_MTIME)
 366             de->last_mod = st.mtime;
 367         else
 368             time(&de->last_mod);
 369     }
 370     de->comp_method = st.comp_method;
 371     de->crc = st.crc;
 372     de->uncomp_size = st.size;
 373     de->comp_size = (zip_uint64_t)(offend - offdata);
 374 
 375     if ((ret=_zip_dirent_write(za, de, flags)) < 0)
 376         return -1;
 377  
 378     if (is_zip64 != ret) {
 379         /* Zip64 mismatch between preliminary file header written before data and final file header written afterwards */
 380         zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
 381         return -1;
 382     }
 383 
 384    
 385     if (zip_source_seek_write(za->src, offend, SEEK_SET) < 0) {
 386         _zip_error_set_from_source(&za->error, za->src);
 387         return -1;
 388     }
 389 
 390     return 0;
 391 }
 392 
 393 
 394 static int
 395 copy_data(zip_t *za, zip_uint64_t len)
 396 {
 397     zip_uint8_t buf[BUFSIZE];
 398     size_t n;
 399 
 400     while (len > 0) {
 401         n = len > sizeof(buf) ? sizeof(buf) : len;
 402         if (_zip_read(za->src, buf, n, &za->error) < 0) {
 403             return -1;
 404         }
 405 
 406         if (_zip_write(za, buf, n) < 0) {
 407             return -1;
 408         }
 409         
 410         len -= n;
 411     }
 412 
 413     return 0;
 414 }
 415 
 416 
 417 static int
 418 copy_source(zip_t *za, zip_source_t *src)
 419 {
 420     zip_uint8_t buf[BUFSIZE];
 421     zip_int64_t n;
 422     int ret;
 423 
 424     if (zip_source_open(src) < 0) {
 425         _zip_error_set_from_source(&za->error, src);
 426         return -1;
 427     }
 428 
 429     ret = 0;
 430     while ((n=zip_source_read(src, buf, sizeof(buf))) > 0) {
 431         if (_zip_write(za, buf, (zip_uint64_t)n) < 0) {
 432             ret = -1;
 433             break;
 434         }
 435     }
 436     
 437     if (n < 0) {
 438         _zip_error_set_from_source(&za->error, src);
 439         ret = -1;
 440     }
 441 
 442     zip_source_close(src);
 443     
 444     return ret;
 445 }
 446 
 447 
 448 static int
 449 write_cdir(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors)
 450 {
 451     zip_int64_t cd_start, end, size;
 452     
 453     if ((cd_start = zip_source_tell_write(za->src)) < 0) {
 454         return -1;
 455     }
 456 
 457     if ((size=_zip_cdir_write(za, filelist, survivors)) < 0) {
 458         return -1;
 459     }
 460     
 461     if ((end = zip_source_tell_write(za->src)) < 0) {
 462         return -1;
 463     }
 464 
 465     return 0;
 466 }
 467 
 468 
 469 int
 470 _zip_changed(const zip_t *za, zip_uint64_t *survivorsp)
 471 {
 472     int changed;
 473     zip_uint64_t i, survivors;
 474 
 475     changed = 0;
 476     survivors = 0;
 477 
 478     if (za->comment_changed || za->ch_flags != za->flags)
 479         changed = 1;
 480 
 481     for (i=0; i<za->nentry; i++) {
 482         if (za->entry[i].deleted || za->entry[i].source || (za->entry[i].changes && za->entry[i].changes->changed != 0))
 483             changed = 1;
 484         if (!za->entry[i].deleted)
 485             survivors++;
 486     }
 487 
 488     if (survivorsp)
 489         *survivorsp = survivors;
 490 
 491     return changed;
 492 }

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