"Fossies" - the Fresh Open Source Software Archive

Member "src/Common/libzip/zip_source_buffer.c" (10 Oct 2018, 16389 Bytes) of package /windows/misc/VeraCrypt_1.23-Hotfix-2_Source.zip:


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 "zip_source_buffer.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.21_Source_vs_1.22_Source.

    1 /*
    2   zip_source_buffer.c -- create zip data source from buffer
    3   Copyright (C) 1999-2017 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 #ifndef WRITE_FRAGMENT_SIZE
   40 #define WRITE_FRAGMENT_SIZE (64 * 1024)
   41 #endif
   42 
   43 struct buffer {
   44     zip_buffer_fragment_t *fragments; /* fragments */
   45     zip_uint64_t *fragment_offsets;   /* offset of each fragment from start of buffer, nfragments+1 entries */
   46     zip_uint64_t nfragments;          /* number of allocated fragments */
   47     zip_uint64_t fragments_capacity;  /* size of fragments (number of pointers) */
   48 
   49     zip_uint64_t first_owned_fragment; /* first fragment to free data from */
   50 
   51     zip_uint64_t shared_fragments; /* number of shared fragments */
   52     struct buffer *shared_buffer;  /* buffer fragments are shared with */
   53     zip_uint64_t size;             /* size of buffer */
   54 
   55     zip_uint64_t offset;           /* current offset in buffer */
   56     zip_uint64_t current_fragment; /* fragment current offset is in */
   57 };
   58 
   59 typedef struct buffer buffer_t;
   60 
   61 struct read_data {
   62     zip_error_t error;
   63     time_t mtime;
   64     buffer_t *in;
   65     buffer_t *out;
   66 };
   67 
   68 #define buffer_capacity(buffer) ((buffer)->fragment_offsets[(buffer)->nfragments])
   69 #define buffer_size(buffer) ((buffer)->size)
   70 
   71 static buffer_t *buffer_clone(buffer_t *buffer, zip_uint64_t length, zip_error_t *error);
   72 static zip_uint64_t buffer_find_fragment(const buffer_t *buffer, zip_uint64_t offset);
   73 static void buffer_free(buffer_t *buffer);
   74 static bool buffer_grow_fragments(buffer_t *buffer, zip_uint64_t capacity, zip_error_t *error);
   75 static buffer_t *buffer_new(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int free_data, zip_error_t *error);
   76 static zip_int64_t buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length);
   77 static int buffer_seek(buffer_t *buffer, void *data, zip_uint64_t len, zip_error_t *error);
   78 static zip_int64_t buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *);
   79 
   80 static zip_int64_t read_data(void *, void *, zip_uint64_t, zip_source_cmd_t);
   81 
   82 
   83 ZIP_EXTERN zip_source_t *
   84 zip_source_buffer(zip_t *za, const void *data, zip_uint64_t len, int freep) {
   85     if (za == NULL)
   86     return NULL;
   87 
   88     return zip_source_buffer_create(data, len, freep, &za->error);
   89 }
   90 
   91 
   92 ZIP_EXTERN zip_source_t *
   93 zip_source_buffer_create(const void *data, zip_uint64_t len, int freep, zip_error_t *error) {
   94     zip_buffer_fragment_t fragment;
   95 
   96     if (data == NULL && len > 0) {
   97     zip_error_set(error, ZIP_ER_INVAL, 0);
   98     return NULL;
   99     }
  100 
  101     fragment.data = (zip_uint8_t *)data;
  102     fragment.length = len;
  103 
  104     return zip_source_buffer_fragment_create(&fragment, 1, freep, error);
  105 }
  106 
  107 
  108 ZIP_EXTERN zip_source_t *
  109 zip_source_buffer_fragment(zip_t *za, const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep) {
  110     if (za == NULL) {
  111     return NULL;
  112     }
  113 
  114     return zip_source_buffer_fragment_create(fragments, nfragments, freep, &za->error);
  115 }
  116 
  117 
  118 ZIP_EXTERN zip_source_t *
  119 zip_source_buffer_fragment_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_error_t *error) {
  120     struct read_data *ctx;
  121     zip_source_t *zs;
  122     buffer_t *buffer;
  123 
  124     if (fragments == NULL && nfragments > 0) {
  125     zip_error_set(error, ZIP_ER_INVAL, 0);
  126     return NULL;
  127     }
  128 
  129     if ((buffer = buffer_new(fragments, nfragments, freep, error)) == NULL) {
  130     return NULL;
  131     }
  132 
  133     if ((ctx = (struct read_data *)malloc(sizeof(*ctx))) == NULL) {
  134     zip_error_set(error, ZIP_ER_MEMORY, 0);
  135     buffer_free(buffer);
  136     return NULL;
  137     }
  138 
  139     ctx->in = buffer;
  140     ctx->out = NULL;
  141     ctx->mtime = time(NULL);
  142     zip_error_init(&ctx->error);
  143 
  144     if ((zs = zip_source_function_create(read_data, ctx, error)) == NULL) {
  145     buffer_free(ctx->in);
  146     free(ctx);
  147     return NULL;
  148     }
  149 
  150     return zs;
  151 }
  152 
  153 
  154 static zip_int64_t
  155 read_data(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
  156     struct read_data *ctx = (struct read_data *)state;
  157 
  158     switch (cmd) {
  159     case ZIP_SOURCE_BEGIN_WRITE:
  160     if ((ctx->out = buffer_new(NULL, 0, 0, &ctx->error)) == NULL) {
  161         return -1;
  162     }
  163     ctx->out->offset = 0;
  164     ctx->out->current_fragment = 0;
  165     return 0;
  166 
  167     case ZIP_SOURCE_BEGIN_WRITE_CLONING:
  168     if ((ctx->out = buffer_clone(ctx->in, len, &ctx->error)) == NULL) {
  169         return -1;
  170     }
  171     ctx->out->offset = len;
  172     ctx->out->current_fragment = ctx->out->nfragments;
  173     return 0;
  174 
  175     case ZIP_SOURCE_CLOSE:
  176     return 0;
  177 
  178     case ZIP_SOURCE_COMMIT_WRITE:
  179     buffer_free(ctx->in);
  180     ctx->in = ctx->out;
  181     ctx->out = NULL;
  182     return 0;
  183 
  184     case ZIP_SOURCE_ERROR:
  185     return zip_error_to_data(&ctx->error, data, len);
  186 
  187     case ZIP_SOURCE_FREE:
  188     buffer_free(ctx->in);
  189     buffer_free(ctx->out);
  190     free(ctx);
  191     return 0;
  192 
  193     case ZIP_SOURCE_OPEN:
  194     ctx->in->offset = 0;
  195     ctx->in->current_fragment = 0;
  196     return 0;
  197 
  198     case ZIP_SOURCE_READ:
  199     if (len > ZIP_INT64_MAX) {
  200         zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
  201         return -1;
  202     }
  203     return buffer_read(ctx->in, data, len);
  204 
  205     case ZIP_SOURCE_REMOVE: {
  206     buffer_t *empty = buffer_new(NULL, 0, 0, &ctx->error);
  207     if (empty == NULL) {
  208         return -1;
  209     }
  210 
  211     buffer_free(ctx->in);
  212     ctx->in = empty;
  213     return 0;
  214     }
  215 
  216     case ZIP_SOURCE_ROLLBACK_WRITE:
  217     buffer_free(ctx->out);
  218     ctx->out = NULL;
  219     return 0;
  220 
  221     case ZIP_SOURCE_SEEK:
  222     return buffer_seek(ctx->in, data, len, &ctx->error);
  223 
  224     case ZIP_SOURCE_SEEK_WRITE:
  225     return buffer_seek(ctx->out, data, len, &ctx->error);
  226 
  227     case ZIP_SOURCE_STAT: {
  228     zip_stat_t *st;
  229 
  230     if (len < sizeof(*st)) {
  231         zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
  232         return -1;
  233     }
  234 
  235     st = (zip_stat_t *)data;
  236 
  237     zip_stat_init(st);
  238     st->mtime = ctx->mtime;
  239     st->size = ctx->in->size;
  240     st->comp_size = st->size;
  241     st->comp_method = ZIP_CM_STORE;
  242     st->encryption_method = ZIP_EM_NONE;
  243     st->valid = ZIP_STAT_MTIME | ZIP_STAT_SIZE | ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD | ZIP_STAT_ENCRYPTION_METHOD;
  244 
  245     return sizeof(*st);
  246     }
  247 
  248     case ZIP_SOURCE_SUPPORTS:
  249     return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_SEEK, ZIP_SOURCE_TELL, ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_BEGIN_WRITE_CLONING, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_REMOVE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_WRITE, -1);
  250 
  251     case ZIP_SOURCE_TELL:
  252     if (ctx->in->offset > ZIP_INT64_MAX) {
  253         zip_error_set(&ctx->error, ZIP_ER_TELL, EOVERFLOW);
  254         return -1;
  255     }
  256     return (zip_int64_t)ctx->in->offset;
  257 
  258 
  259     case ZIP_SOURCE_TELL_WRITE:
  260     if (ctx->out->offset > ZIP_INT64_MAX) {
  261         zip_error_set(&ctx->error, ZIP_ER_TELL, EOVERFLOW);
  262         return -1;
  263     }
  264     return (zip_int64_t)ctx->out->offset;
  265 
  266     case ZIP_SOURCE_WRITE:
  267     if (len > ZIP_INT64_MAX) {
  268         zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
  269         return -1;
  270     }
  271     return buffer_write(ctx->out, data, len, &ctx->error);
  272 
  273     default:
  274     zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
  275     return -1;
  276     }
  277 }
  278 
  279 
  280 static buffer_t *
  281 buffer_clone(buffer_t *buffer, zip_uint64_t offset, zip_error_t *error) {
  282     zip_uint64_t fragment, fragment_offset, waste;
  283     buffer_t *clone;
  284 
  285     if (offset == 0) {
  286     return buffer_new(NULL, 0, 1, error);
  287     }
  288 
  289     if (offset > buffer->size) {
  290     zip_error_set(error, ZIP_ER_INVAL, 0);
  291     return NULL;
  292     }
  293     if (buffer->shared_buffer != NULL) {
  294     zip_error_set(error, ZIP_ER_INUSE, 0);
  295     return NULL;
  296     }
  297 
  298     fragment = buffer_find_fragment(buffer, offset);
  299     fragment_offset = offset - buffer->fragment_offsets[fragment];
  300 
  301     if (fragment_offset == 0) {
  302     fragment--;
  303     fragment_offset = buffer->fragments[fragment].length;
  304     }
  305 
  306     waste = buffer->fragments[fragment].length - fragment_offset;
  307     if (waste > offset) {
  308     zip_error_set(error, ZIP_ER_OPNOTSUPP, 0);
  309     return NULL;
  310     }
  311 
  312     if ((clone = buffer_new(buffer->fragments, fragment + 1, 0, error)) == NULL) {
  313     return NULL;
  314     }
  315 
  316 #ifndef __clang_analyzer__
  317     /* clone->fragments can't be null, since it was created with at least one fragment */
  318     clone->fragments[clone->nfragments - 1].length = fragment_offset;
  319 #endif
  320     clone->fragment_offsets[clone->nfragments] = offset;
  321     clone->size = offset;
  322 
  323     clone->first_owned_fragment = ZIP_MIN(buffer->first_owned_fragment, clone->nfragments - 1);
  324 
  325     buffer->shared_buffer = clone;
  326     clone->shared_buffer = buffer;
  327     buffer->shared_fragments = clone->nfragments;
  328     clone->shared_fragments = fragment + 1;
  329 
  330     return clone;
  331 }
  332 
  333 
  334 static zip_uint64_t
  335 buffer_find_fragment(const buffer_t *buffer, zip_uint64_t offset) {
  336     zip_uint64_t low, high, mid;
  337 
  338     low = 0;
  339     high = buffer->nfragments - 1;
  340 
  341     while (low < high) {
  342     mid = (high - low) / 2 + low;
  343     if (buffer->fragment_offsets[mid] > offset) {
  344         high = mid - 1;
  345     }
  346     else if (mid == buffer->nfragments || buffer->fragment_offsets[mid + 1] > offset) {
  347         return mid;
  348     }
  349     else {
  350         low = mid + 1;
  351     }
  352     }
  353 
  354     return low;
  355 }
  356 
  357 
  358 static void
  359 buffer_free(buffer_t *buffer) {
  360     zip_uint64_t i;
  361 
  362     if (buffer == NULL) {
  363     return;
  364     }
  365 
  366     if (buffer->shared_buffer != NULL) {
  367     buffer->shared_buffer->shared_buffer = NULL;
  368     buffer->shared_buffer->shared_fragments = 0;
  369 
  370     buffer->first_owned_fragment = ZIP_MAX(buffer->first_owned_fragment, buffer->shared_fragments);
  371     }
  372 
  373     for (i = buffer->first_owned_fragment; i < buffer->nfragments; i++) {
  374     free(buffer->fragments[i].data);
  375     }
  376     free(buffer->fragments);
  377     free(buffer->fragment_offsets);
  378     free(buffer);
  379 }
  380 
  381 
  382 static bool
  383 buffer_grow_fragments(buffer_t *buffer, zip_uint64_t capacity, zip_error_t *error) {
  384     zip_buffer_fragment_t *fragments;
  385     zip_uint64_t *offsets;
  386 
  387     if (capacity < buffer->fragments_capacity) {
  388     return true;
  389     }
  390 
  391     if ((fragments = realloc(buffer->fragments, sizeof(buffer->fragments[0]) * capacity)) == NULL) {
  392         zip_error_set(error, ZIP_ER_MEMORY, 0);
  393         return false;
  394     }
  395     buffer->fragments = fragments;
  396     if ((offsets = realloc(buffer->fragment_offsets, sizeof(buffer->fragment_offsets[0]) * (capacity + 1))) == NULL) {
  397     zip_error_set(error, ZIP_ER_MEMORY, 0);
  398     return false;
  399     }
  400     buffer->fragment_offsets = offsets;
  401     buffer->fragments_capacity = capacity;
  402 
  403     return true;
  404 }
  405 
  406 
  407 static buffer_t *
  408 buffer_new(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int free_data, zip_error_t *error) {
  409     buffer_t *buffer;
  410 
  411     if ((buffer = malloc(sizeof(*buffer))) == NULL) {
  412     return NULL;
  413     }
  414 
  415     buffer->offset = 0;
  416     buffer->first_owned_fragment = 0;
  417     buffer->size = 0;
  418     buffer->fragments = NULL;
  419     buffer->fragment_offsets = NULL;
  420     buffer->nfragments = 0;
  421     buffer->fragments_capacity = 0;
  422     buffer->shared_buffer = NULL;
  423     buffer->shared_fragments = 0;
  424 
  425     if (nfragments == 0) {
  426     if ((buffer->fragment_offsets = malloc(sizeof(buffer->fragment_offsets[0]))) == NULL) {
  427         free(buffer);
  428         zip_error_set(error, ZIP_ER_MEMORY, 0);
  429         return NULL;
  430     }
  431     buffer->fragment_offsets[0] = 0;
  432     }
  433     else {
  434     zip_uint64_t i, j, offset;
  435 
  436     if (!buffer_grow_fragments(buffer, nfragments, NULL)) {
  437         zip_error_set(error, ZIP_ER_MEMORY, 0);
  438         buffer_free(buffer);
  439         return NULL;
  440     }
  441 
  442     offset = 0;
  443     for (i = 0, j = 0; i < nfragments; i++) {
  444         if (fragments[i].length == 0) {
  445         continue;
  446         }
  447         if (fragments[i].data == NULL) {
  448         zip_error_set(error, ZIP_ER_INVAL, 0);
  449         buffer_free(buffer);
  450         return NULL;
  451         }
  452         buffer->fragments[j].data = fragments[i].data;
  453         buffer->fragments[j].length = fragments[i].length;
  454         buffer->fragment_offsets[i] = offset;
  455         offset += fragments[i].length;
  456         j++;
  457     }
  458     buffer->nfragments = j;
  459     buffer->first_owned_fragment = free_data ? 0 : buffer->nfragments;
  460     buffer->fragment_offsets[nfragments] = offset;
  461     buffer->size = offset;
  462     }
  463 
  464     return buffer;
  465 }
  466 
  467 static zip_int64_t
  468 buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length) {
  469     zip_uint64_t n, i, fragment_offset;
  470 
  471     length = ZIP_MIN(length, buffer->size - buffer->offset);
  472 
  473     if (length == 0) {
  474     return 0;
  475     }
  476     if (length > ZIP_INT64_MAX) {
  477     return -1;
  478     }
  479 
  480     i = buffer->current_fragment;
  481     fragment_offset = buffer->offset - buffer->fragment_offsets[i];
  482     n = 0;
  483     while (n < length) {
  484     zip_uint64_t left = ZIP_MIN(length - n, buffer->fragments[i].length - fragment_offset);
  485 
  486     memcpy(data + n, buffer->fragments[i].data + fragment_offset, left);
  487 
  488     if (left == buffer->fragments[i].length - fragment_offset) {
  489         i++;
  490     }
  491     n += left;
  492     fragment_offset = 0;
  493     }
  494 
  495     buffer->offset += n;
  496     buffer->current_fragment = i;
  497     return (zip_int64_t)n;
  498 }
  499 
  500 
  501 static int
  502 buffer_seek(buffer_t *buffer, void *data, zip_uint64_t len, zip_error_t *error) {
  503     zip_int64_t new_offset = zip_source_seek_compute_offset(buffer->offset, buffer->size, data, len, error);
  504 
  505     if (new_offset < 0) {
  506     return -1;
  507     }
  508 
  509     buffer->offset = (zip_uint64_t)new_offset;
  510     buffer->current_fragment = buffer_find_fragment(buffer, buffer->offset);
  511     return 0;
  512 }
  513 
  514 
  515 static zip_int64_t
  516 buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *error) {
  517     zip_uint64_t n, i, fragment_offset, capacity;
  518 
  519     if (buffer->offset + length + WRITE_FRAGMENT_SIZE - 1 < length) {
  520     zip_error_set(error, ZIP_ER_INVAL, 0);
  521     return -1;
  522     }
  523 
  524     /* grow buffer if needed */
  525     capacity = buffer_capacity(buffer);
  526     if (buffer->offset + length > capacity) {
  527     zip_uint64_t needed_fragments = buffer->nfragments + (length - (capacity - buffer->offset) + WRITE_FRAGMENT_SIZE - 1) / WRITE_FRAGMENT_SIZE;
  528 
  529     if (needed_fragments > buffer->fragments_capacity) {
  530         zip_uint64_t new_capacity = buffer->fragments_capacity;
  531 
  532         if (new_capacity == 0) {
  533         new_capacity = 16;
  534         }
  535         while (new_capacity < needed_fragments) {
  536         new_capacity *= 2;
  537         }
  538 
  539         if (!buffer_grow_fragments(buffer, new_capacity, error)) {
  540         zip_error_set(error, ZIP_ER_MEMORY, 0);
  541         return -1;
  542         }
  543     }
  544 
  545     while (buffer->nfragments < needed_fragments) {
  546         if ((buffer->fragments[buffer->nfragments].data = malloc(WRITE_FRAGMENT_SIZE)) == NULL) {
  547         zip_error_set(error, ZIP_ER_MEMORY, 0);
  548         return -1;
  549         }
  550         buffer->fragments[buffer->nfragments].length = WRITE_FRAGMENT_SIZE;
  551         buffer->nfragments++;
  552         capacity += WRITE_FRAGMENT_SIZE;
  553         buffer->fragment_offsets[buffer->nfragments] = capacity;
  554     }
  555     }
  556 
  557     i = buffer->current_fragment;
  558     fragment_offset = buffer->offset - buffer->fragment_offsets[i];
  559     n = 0;
  560     while (n < length) {
  561     zip_uint64_t left = ZIP_MIN(length - n, buffer->fragments[i].length - fragment_offset);
  562 
  563     memcpy(buffer->fragments[i].data + fragment_offset, data + n, left);
  564 
  565     if (n == buffer->fragments[i].length - fragment_offset) {
  566         i++;
  567     }
  568     n += left;
  569     fragment_offset = 0;
  570     }
  571 
  572     buffer->offset += n;
  573     buffer->current_fragment = i;
  574     if (buffer->offset > buffer->size) {
  575     buffer->size = buffer->offset;
  576     }
  577 
  578     return (zip_int64_t)n;
  579 }