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