root/ext/zip/lib/zip_extra_field.c

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

DEFINITIONS

This source file includes following definitions.
  1. _zip_ef_clone
  2. _zip_ef_delete_by_id
  3. _zip_ef_free
  4. _zip_ef_get_by_id
  5. _zip_ef_merge
  6. _zip_ef_new
  7. _zip_ef_parse
  8. _zip_ef_remove_internal
  9. _zip_ef_size
  10. _zip_ef_write
  11. _zip_read_local_ef

   1 /*
   2   zip_extra_field.c -- manipulate extra fields
   3   Copyright (C) 2012-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 #include <stdlib.h>
  35 #include <string.h>
  36 
  37 #include "zipint.h"
  38 
  39 
  40 zip_extra_field_t *
  41 _zip_ef_clone(const zip_extra_field_t *ef, zip_error_t *error)
  42 {
  43     zip_extra_field_t *head, *prev, *def;
  44     
  45     head = prev = NULL;
  46     
  47     while (ef) {
  48         if ((def=_zip_ef_new(ef->id, ef->size, ef->data, ef->flags)) == NULL) {
  49             zip_error_set(error, ZIP_ER_MEMORY, 0);
  50             _zip_ef_free(head);
  51             return NULL;
  52         }
  53         
  54         if (head == NULL)
  55             head = def;
  56         if (prev)
  57             prev->next = def;
  58         prev = def;
  59 
  60         ef = ef->next;
  61     }
  62     
  63     return head;
  64 }
  65 
  66 
  67 zip_extra_field_t *
  68 _zip_ef_delete_by_id(zip_extra_field_t *ef, zip_uint16_t id, zip_uint16_t id_idx, zip_flags_t flags)
  69 {
  70     zip_extra_field_t *head, *prev;
  71     int i;
  72 
  73     i = 0;
  74     head = ef;
  75     prev = NULL;
  76     for (; ef; ef=(prev ? prev->next : head)) {
  77         if ((ef->flags & flags & ZIP_EF_BOTH) && ((ef->id == id) || (id == ZIP_EXTRA_FIELD_ALL))) {
  78             if (id_idx == ZIP_EXTRA_FIELD_ALL || i == id_idx) {
  79                 ef->flags &= ~(flags & ZIP_EF_BOTH);
  80                 if ((ef->flags & ZIP_EF_BOTH) == 0) {
  81                     if (prev)
  82                         prev->next = ef->next;
  83                     else
  84                         head = ef->next;
  85                     ef->next = NULL;
  86                     _zip_ef_free(ef);
  87 
  88                     if (id_idx == ZIP_EXTRA_FIELD_ALL)
  89                         continue;
  90                 }
  91             }
  92             
  93             i++;
  94             if (i > id_idx)
  95                 break;
  96         }
  97         prev = ef;
  98     }
  99 
 100     return head;
 101 }
 102 
 103 
 104 
 105 void
 106 _zip_ef_free(zip_extra_field_t *ef)
 107 {
 108     zip_extra_field_t *ef2;
 109 
 110     while (ef) {
 111         ef2 = ef->next;
 112         free(ef->data);
 113         free(ef);
 114         ef = ef2;
 115     }
 116 }
 117 
 118 
 119 const zip_uint8_t *
 120 _zip_ef_get_by_id(const zip_extra_field_t *ef, zip_uint16_t *lenp, zip_uint16_t id, zip_uint16_t id_idx, zip_flags_t flags, zip_error_t *error)
 121 {
 122     static const zip_uint8_t empty[1] = { '\0' };
 123     
 124     int i;
 125 
 126     i = 0;
 127     for (; ef; ef=ef->next) {
 128         if (ef->id == id && (ef->flags & flags & ZIP_EF_BOTH)) {
 129             if (i < id_idx) {
 130                 i++;
 131                 continue;
 132             }
 133 
 134             if (lenp)
 135                 *lenp = ef->size;
 136             if (ef->size > 0)
 137                 return ef->data;
 138             else
 139                 return empty;
 140         }
 141     }
 142 
 143     zip_error_set(error, ZIP_ER_NOENT, 0);
 144     return NULL;
 145 }
 146 
 147 
 148 zip_extra_field_t *
 149 _zip_ef_merge(zip_extra_field_t *to, zip_extra_field_t *from)
 150 {
 151     zip_extra_field_t *ef2, *tt, *tail;
 152     int duplicate;
 153 
 154     if (to == NULL)
 155         return from;
 156 
 157     for (tail=to; tail->next; tail=tail->next)
 158         ;
 159 
 160     for (; from; from=ef2) {
 161         ef2 = from->next;
 162 
 163         duplicate = 0;
 164         for (tt=to; tt; tt=tt->next) {
 165             if (tt->id == from->id && tt->size == from->size && memcmp(tt->data, from->data, tt->size) == 0) {
 166                 tt->flags |= (from->flags & ZIP_EF_BOTH);
 167                 duplicate = 1;
 168                 break;
 169             }
 170         }
 171 
 172         from->next = NULL;
 173         if (duplicate)
 174             _zip_ef_free(from);
 175         else
 176             tail = tail->next = from;
 177     }
 178 
 179     return to;
 180 }
 181 
 182 
 183 zip_extra_field_t *
 184 _zip_ef_new(zip_uint16_t id, zip_uint16_t size, const zip_uint8_t *data, zip_flags_t flags)
 185 {
 186     zip_extra_field_t *ef;
 187 
 188     if ((ef=(zip_extra_field_t *)malloc(sizeof(*ef))) == NULL)
 189         return NULL;
 190 
 191     ef->next = NULL;
 192     ef->flags = flags;
 193     ef->id = id;
 194     ef->size = size;
 195     if (size > 0) {
 196         if ((ef->data=(zip_uint8_t *)_zip_memdup(data, size, NULL)) == NULL) {
 197             free(ef);
 198             return NULL;
 199         }
 200     }
 201     else
 202         ef->data = NULL;
 203 
 204     return ef;
 205 }
 206 
 207 
 208 bool
 209 _zip_ef_parse(const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags, zip_extra_field_t **ef_head_p, zip_error_t *error)
 210 {
 211     zip_buffer_t *buffer;
 212     zip_extra_field_t *ef, *ef2, *ef_head;
 213 
 214     if ((buffer = _zip_buffer_new((zip_uint8_t *)data, len)) == NULL) {
 215         zip_error_set(error, ZIP_ER_MEMORY, 0);
 216         return false;
 217     }
 218     
 219     ef_head = ef = NULL;
 220     
 221     while (_zip_buffer_ok(buffer) && _zip_buffer_left(buffer) >= 4) {
 222         zip_uint16_t fid, flen;
 223         zip_uint8_t *ef_data;
 224         
 225         fid = _zip_buffer_get_16(buffer);
 226         flen = _zip_buffer_get_16(buffer);
 227         ef_data = _zip_buffer_get(buffer, flen);
 228 
 229         if (ef_data == NULL) {
 230             zip_error_set(error, ZIP_ER_INCONS, 0);
 231             _zip_buffer_free(buffer);
 232             _zip_ef_free(ef_head);
 233             return false;
 234         }
 235         
 236         if ((ef2=_zip_ef_new(fid, flen, ef_data, flags)) == NULL) {
 237             zip_error_set(error, ZIP_ER_MEMORY, 0);
 238             _zip_buffer_free(buffer);
 239             _zip_ef_free(ef_head);
 240             return false;
 241         }
 242 
 243         if (ef_head) {
 244             ef->next = ef2;
 245             ef = ef2;
 246         }
 247         else
 248             ef_head = ef = ef2;
 249     }
 250 
 251     if (!_zip_buffer_eof(buffer)) {
 252         /* Android APK files align stored file data with padding in extra fields; ignore. */
 253         /* see https://android.googlesource.com/platform/build/+/master/tools/zipalign/ZipAlign.cpp */
 254         size_t glen = _zip_buffer_left(buffer);
 255         zip_uint8_t *garbage;
 256         garbage = _zip_buffer_get(buffer, glen);
 257         if (glen >= 4 || garbage == NULL || memcmp(garbage, "\0\0\0", glen) != 0) {
 258             zip_error_set(error, ZIP_ER_INCONS, 0);
 259             _zip_buffer_free(buffer);
 260             _zip_ef_free(ef_head);
 261             return false;
 262         }
 263     }
 264 
 265     _zip_buffer_free(buffer);
 266 
 267     if (ef_head_p) {
 268         *ef_head_p = ef_head;
 269     }
 270     else {
 271         _zip_ef_free(ef_head);
 272     }
 273     
 274     return true;
 275 }
 276 
 277 
 278 zip_extra_field_t *
 279 _zip_ef_remove_internal(zip_extra_field_t *ef)
 280 {
 281     zip_extra_field_t *ef_head;
 282     zip_extra_field_t *prev, *next;
 283     
 284     ef_head = ef;
 285     prev = NULL;
 286     
 287     while (ef) {
 288         if (ZIP_EF_IS_INTERNAL(ef->id)) {
 289             next = ef->next;
 290             if (ef_head == ef)
 291                 ef_head = next;
 292             ef->next = NULL;
 293             _zip_ef_free(ef);
 294             if (prev)
 295                 prev->next = next;
 296             ef = next;
 297         }
 298         else {
 299             prev = ef;
 300             ef = ef->next;
 301         }
 302     }
 303     
 304     return ef_head;
 305 }
 306 
 307 
 308 zip_uint16_t
 309 _zip_ef_size(const zip_extra_field_t *ef, zip_flags_t flags)
 310 {
 311     zip_uint16_t size;
 312 
 313     size = 0;
 314     for (; ef; ef=ef->next) {
 315         if (ef->flags & flags & ZIP_EF_BOTH)
 316             size = (zip_uint16_t)(size+4+ef->size);
 317     }
 318 
 319     return size;
 320 }
 321 
 322 
 323 int
 324 _zip_ef_write(zip_t *za, const zip_extra_field_t *ef, zip_flags_t flags)
 325 {
 326     zip_uint8_t b[4];
 327     zip_buffer_t *buffer = _zip_buffer_new(b, sizeof(b));
 328 
 329     if (buffer == NULL) {
 330         return -1;
 331     }
 332 
 333     for (; ef; ef=ef->next) {
 334         if (ef->flags & flags & ZIP_EF_BOTH) {
 335             _zip_buffer_set_offset(buffer, 0);
 336             _zip_buffer_put_16(buffer, ef->id);
 337             _zip_buffer_put_16(buffer, ef->size);
 338             if (!_zip_buffer_ok(buffer)) {
 339                 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
 340                 _zip_buffer_free(buffer);
 341                 return -1;
 342             }
 343             if (_zip_write(za, b, 4) < 0) {
 344                 _zip_buffer_free(buffer);
 345                 return -1;
 346             }
 347             if (ef->size > 0) {
 348                 if (_zip_write(za, ef->data, ef->size) < 0) {
 349                     _zip_buffer_free(buffer);
 350                     return -1;
 351                 }
 352             }
 353         }
 354     }
 355     
 356     _zip_buffer_free(buffer);
 357     return 0;
 358 }
 359 
 360 
 361 int
 362 _zip_read_local_ef(zip_t *za, zip_uint64_t idx)
 363 {
 364     zip_entry_t *e;
 365     unsigned char b[4];
 366     zip_buffer_t *buffer;
 367     zip_uint16_t fname_len, ef_len;
 368 
 369     if (idx >= za->nentry) {
 370         zip_error_set(&za->error, ZIP_ER_INVAL, 0);
 371         return -1;
 372     }
 373 
 374     e = za->entry+idx;
 375 
 376     if (e->orig == NULL || e->orig->local_extra_fields_read)
 377         return 0;
 378 
 379     if (e->orig->offset + 26 > ZIP_INT64_MAX) {
 380         zip_error_set(&za->error, ZIP_ER_SEEK, EFBIG);
 381         return -1;
 382     }   
 383 
 384     if (zip_source_seek(za->src, (zip_int64_t)(e->orig->offset + 26), SEEK_SET) < 0) {
 385         _zip_error_set_from_source(&za->error, za->src);
 386         return -1;
 387     }
 388     
 389     if ((buffer = _zip_buffer_new_from_source(za->src, sizeof(b), b, &za->error)) == NULL) {
 390         return -1;
 391     }
 392     
 393     fname_len = _zip_buffer_get_16(buffer);
 394     ef_len = _zip_buffer_get_16(buffer);
 395     
 396     if (!_zip_buffer_eof(buffer)) {
 397         _zip_buffer_free(buffer);
 398         zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
 399         return -1;
 400     }
 401     
 402     _zip_buffer_free(buffer);
 403     
 404     if (ef_len > 0) {
 405         zip_extra_field_t *ef;
 406         zip_uint8_t *ef_raw;
 407 
 408         if (zip_source_seek(za->src, fname_len, SEEK_CUR) < 0) {
 409             zip_error_set(&za->error, ZIP_ER_SEEK, errno);
 410             return -1;
 411         }
 412 
 413         ef_raw = _zip_read_data(NULL, za->src, ef_len, 0, &za->error);
 414 
 415         if (ef_raw == NULL)
 416             return -1;
 417 
 418         if (!_zip_ef_parse(ef_raw, ef_len, ZIP_EF_LOCAL, &ef, &za->error)) {
 419             free(ef_raw);
 420             return -1;
 421         }
 422         free(ef_raw);
 423 
 424         if (ef) {
 425             ef = _zip_ef_remove_internal(ef);
 426             e->orig->extra_fields = _zip_ef_merge(e->orig->extra_fields, ef);
 427         }
 428     }
 429 
 430     e->orig->local_extra_fields_read = 1;
 431     
 432     if (e->changes && e->changes->local_extra_fields_read == 0) {
 433         e->changes->extra_fields = e->orig->extra_fields;
 434         e->changes->local_extra_fields_read = 1;
 435     }
 436 
 437     return 0;
 438 }

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