blob: d2f1a1687440f7488bd1251b9bcaa9a0c749f531 [file] [log] [blame]
Dieter Baron91374c72014-10-09 22:14:55 +02001/*
Thomas Klausner28c97922016-01-12 13:48:48 +01002 source_hole.c -- source for handling huge files that are mostly NULs
Thomas Klausner00ff6bb2016-01-08 08:21:22 +01003 Copyright (C) 2014-2016 Dieter Baron and Thomas Klausner
Thomas Klausner28c97922016-01-12 13:48:48 +01004
Dieter Baron91374c72014-10-09 22:14:55 +02005 This file is part of libzip, a library to manipulate ZIP archives.
6 The authors can be contacted at <libzip@nih.at>
Thomas Klausner28c97922016-01-12 13:48:48 +01007
Dieter Baron91374c72014-10-09 22:14:55 +02008 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.
Thomas Klausner28c97922016-01-12 13:48:48 +010020
Dieter Baron91374c72014-10-09 22:14:55 +020021 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 <errno.h>
Thomas Klausner17c98372015-10-24 10:42:24 +020035#include <limits.h>
Dieter Baron91374c72014-10-09 22:14:55 +020036#include <stdlib.h>
37#include <stdio.h>
38#include <string.h>
39
40#include "zip.h"
41
42/* public API */
43
44zip_source_t *source_hole_create(const char *, int flags, zip_error_t *);
45
46
Dieter Barond50c6ee2014-10-20 13:07:27 +020047#ifndef EFTYPE
48#define EFTYPE EINVAL
49#endif
50
51
Dieter Baron91374c72014-10-09 22:14:55 +020052#define MY_MIN(a, b) ((a) < (b) ? (a) : (b))
53
54#define FRAGMENT_SIZE (8*1024)
55
56#define MARK_BEGIN "NiH0"
57#define MARK_DATA "NiH1"
58#define MARK_NUL "NiH2"
59
60
61typedef struct buffer {
62 zip_uint64_t fragment_size;
63 zip_uint8_t **fragment;
64 zip_uint64_t nfragments;
65 zip_uint64_t size;
66 zip_uint64_t offset;
67} buffer_t;
68
69static void buffer_free(buffer_t *buffer);
70static buffer_t *buffer_from_file(const char *fname, int flags, zip_error_t *error);
71static buffer_t *buffer_new(void);
72static zip_int64_t buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length, zip_error_t *error);
73static int buffer_read_file(buffer_t *buffer, FILE *f, zip_error_t *error);
74static zip_int64_t buffer_seek(buffer_t *buffer, void *data, zip_uint64_t length, zip_error_t *error);
75static int buffer_to_file(buffer_t *buffer, const char *fname, zip_error_t *error);
76static zip_int64_t buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *error);
77static zip_uint64_t get_u64(const zip_uint8_t *b);
78static int only_nul(const zip_uint8_t *data, zip_uint64_t length);
79static int write_nuls(zip_uint64_t n, FILE *f);
80static int write_u64(zip_uint64_t u64, FILE *f);
81
82
83typedef struct hole {
84 zip_error_t error;
85 char *fname;
86 buffer_t *in;
87 buffer_t *out;
88} hole_t;
89
90static hole_t *hole_new(const char *fname, int flags, zip_error_t *error);
91static zip_int64_t source_hole_cb(void *ud, void *data, zip_uint64_t length, zip_source_cmd_t command);
92
93
94zip_source_t *source_hole_create(const char *fname, int flags, zip_error_t *error)
95{
96 hole_t *ud = hole_new(fname, flags, error);
Thomas Klausner28c97922016-01-12 13:48:48 +010097
Dieter Baron91374c72014-10-09 22:14:55 +020098 if (ud == NULL) {
99 return NULL;
100 }
101 return zip_source_function_create(source_hole_cb, ud, error);
102}
103
104
105static void
106buffer_free(buffer_t *buffer)
107{
108 zip_uint64_t i;
Thomas Klausner28c97922016-01-12 13:48:48 +0100109
Dieter Baron91374c72014-10-09 22:14:55 +0200110 if (buffer == NULL) {
111 return;
112 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100113
Dieter Baron91374c72014-10-09 22:14:55 +0200114 if (buffer->fragment) {
115 for (i=0; i<buffer->nfragments; i++) {
116 free(buffer->fragment[i]);
117 }
118 free(buffer->fragment);
119 }
120 free(buffer);
121}
122
123
124static buffer_t *
125buffer_from_file(const char *fname, int flags, zip_error_t *error)
126{
127 buffer_t *buffer;
128 FILE *f;
Thomas Klausner28c97922016-01-12 13:48:48 +0100129
Dieter Baron91374c72014-10-09 22:14:55 +0200130 if ((buffer = buffer_new()) == NULL) {
131 zip_error_set(error, ZIP_ER_MEMORY, 0);
132 return NULL;
Thomas Klausner28c97922016-01-12 13:48:48 +0100133
Dieter Baron91374c72014-10-09 22:14:55 +0200134 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100135
Dieter Baron91374c72014-10-09 22:14:55 +0200136 if ((flags & ZIP_TRUNCATE) == 0) {
137 if ((f = fopen(fname, "rb")) == NULL) {
138 if (!(errno == ENOENT && (flags & ZIP_CREATE))) {
139 buffer_free(buffer);
140 return NULL;
141 }
142 }
143 else {
144 if (buffer_read_file(buffer, f, error) < 0) {
145 buffer_free(buffer);
Thomas Klausner068665c2015-04-28 00:58:30 +0200146 fclose(f);
Dieter Baron91374c72014-10-09 22:14:55 +0200147 return NULL;
148 }
Thomas Klausnera0702aa2015-04-22 21:29:00 +0200149 fclose(f);
Dieter Baron91374c72014-10-09 22:14:55 +0200150 }
151 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100152
Dieter Baron91374c72014-10-09 22:14:55 +0200153 return buffer;
154}
155
156
157static buffer_t *
158buffer_new(void)
159{
160 buffer_t *buffer;
Thomas Klausner28c97922016-01-12 13:48:48 +0100161
Dieter Baron91374c72014-10-09 22:14:55 +0200162 if ((buffer = (buffer_t *)malloc(sizeof(*buffer))) == NULL) {
163 return NULL;
164 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100165
Dieter Baron91374c72014-10-09 22:14:55 +0200166 buffer->fragment = NULL;
167 buffer->nfragments = 0;
168 buffer->fragment_size = FRAGMENT_SIZE;
169 buffer->size = 0;
170 buffer->offset = 0;
Thomas Klausner28c97922016-01-12 13:48:48 +0100171
Dieter Baron91374c72014-10-09 22:14:55 +0200172 return buffer;
173}
174
175
176static zip_int64_t
177buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length, zip_error_t *error)
178{
179 zip_uint64_t n, i, fragment_offset;
Thomas Klausner28c97922016-01-12 13:48:48 +0100180
Dieter Baron91374c72014-10-09 22:14:55 +0200181 length = MY_MIN(length, buffer->size - buffer->offset);
Thomas Klausner28c97922016-01-12 13:48:48 +0100182
Dieter Baron91374c72014-10-09 22:14:55 +0200183 if (length == 0) {
184 return 0;
185 }
186 if (length > ZIP_INT64_MAX) {
187 return -1;
188 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100189
Dieter Baron91374c72014-10-09 22:14:55 +0200190 i = buffer->offset / buffer->fragment_size;
191 fragment_offset = buffer->offset % buffer->fragment_size;
192 n = 0;
193 while (n < length) {
194 zip_uint64_t left = MY_MIN(length - n, buffer->fragment_size - fragment_offset);
Thomas Klausner28c97922016-01-12 13:48:48 +0100195
Dieter Baron91374c72014-10-09 22:14:55 +0200196 if (buffer->fragment[i]) {
197 memcpy(data + n, buffer->fragment[i] + fragment_offset, left);
198 }
199 else {
200 memset(data + n, 0, left);
201 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100202
Dieter Baron91374c72014-10-09 22:14:55 +0200203 n += left;
204 i++;
205 fragment_offset = 0;
206 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100207
Dieter Baron91374c72014-10-09 22:14:55 +0200208 buffer->offset += n;
209 return (zip_int64_t)n;
210}
211
212
213static int
214buffer_read_file(buffer_t *buffer, FILE *f, zip_error_t *error)
215{
216 zip_uint8_t b[20];
217 zip_uint64_t i;
Thomas Klausner28c97922016-01-12 13:48:48 +0100218
Dieter Baron91374c72014-10-09 22:14:55 +0200219 if (fread(b, 20, 1, f) != 1) {
220 zip_error_set(error, ZIP_ER_READ, errno);
221 return -1;
222 }
223
224 if (memcmp(b, MARK_BEGIN, 4) != 0) {
225 zip_error_set(error, ZIP_ER_READ, EFTYPE);
226 return -1;
227 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100228
Dieter Baron91374c72014-10-09 22:14:55 +0200229 buffer->fragment_size = get_u64(b+4);
230 buffer->size = get_u64(b+12);
Thomas Klausner9cc8f112015-04-28 01:02:03 +0200231
232 if (buffer->size + buffer->fragment_size < buffer->size) {
233 zip_error_set(error, ZIP_ER_MEMORY, 0);
234 return -1;
235 }
Dieter Baron91374c72014-10-09 22:14:55 +0200236 buffer->nfragments = (buffer->size + buffer->fragment_size - 1) / buffer->fragment_size;
Thomas Klausner2e127402015-04-27 15:12:04 +0200237 if ((buffer->nfragments > SIZE_MAX/sizeof(buffer->fragment[0]))
238 || ((buffer->fragment = (zip_uint8_t **)malloc(sizeof(buffer->fragment[0]) * buffer->nfragments)) == NULL)) {
Dieter Baron91374c72014-10-09 22:14:55 +0200239 zip_error_set(error, ZIP_ER_MEMORY, 0);
240 return -1;
241 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100242
Dieter Baron91374c72014-10-09 22:14:55 +0200243 for (i = 0; i < buffer->nfragments; i++) {
244 buffer->fragment[i] = NULL;
245 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100246
Dieter Baron91374c72014-10-09 22:14:55 +0200247 i = 0;
248 while (i < buffer->nfragments) {
249 if (fread(b, 4, 1, f) != 1) {
250 zip_error_set(error, ZIP_ER_READ, errno);
251 return -1;
252 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100253
Dieter Baron91374c72014-10-09 22:14:55 +0200254 if (memcmp(b, MARK_DATA, 4) == 0) {
Thomas Klausner3cc58fa2015-04-29 18:04:25 +0200255 if (buffer->fragment_size > SIZE_MAX) {
256 zip_error_set(error, ZIP_ER_MEMORY, 0);
257 return -1;
258 }
Dieter Baron91374c72014-10-09 22:14:55 +0200259 if ((buffer->fragment[i] = (zip_uint8_t *)malloc(buffer->fragment_size)) == NULL) {
260 zip_error_set(error, ZIP_ER_MEMORY, 0);
261 return -1;
262 }
263 if (fread(buffer->fragment[i], buffer->fragment_size, 1, f) != 1) {
264 zip_error_set(error, ZIP_ER_READ, errno);
265 return -1;
266 }
267 i++;
268 }
269 else if (memcmp(b, MARK_NUL, 4) == 0) {
270 if (fread(b, 8, 1, f) != 1) {
271 zip_error_set(error, ZIP_ER_READ, errno);
272 return -1;
273 }
274 i += get_u64(b);
275 }
276 else {
277 zip_error_set(error, ZIP_ER_READ, EFTYPE);
278 return -1;
279 }
280 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100281
Dieter Baron91374c72014-10-09 22:14:55 +0200282 return 0;
283}
284
285static zip_int64_t
286buffer_seek(buffer_t *buffer, void *data, zip_uint64_t length, zip_error_t *error)
287{
Dieter Baronc548a182014-10-10 18:27:50 +0200288 zip_int64_t new_offset = zip_source_seek_compute_offset(buffer->offset, buffer->size, data, length, error);
289
290 if (new_offset < 0) {
Dieter Baron91374c72014-10-09 22:14:55 +0200291 return -1;
292 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100293
Dieter Baronc548a182014-10-10 18:27:50 +0200294 buffer->offset = (zip_uint64_t)new_offset;
Dieter Baron91374c72014-10-09 22:14:55 +0200295 return 0;
296}
297
298
299static int
300buffer_to_file(buffer_t *buffer, const char *fname, zip_error_t *error)
301{
302 FILE *f = fopen(fname, "wb");
303 zip_uint64_t i;
304 zip_uint64_t nul_run;
Thomas Klausner28c97922016-01-12 13:48:48 +0100305
Dieter Baron91374c72014-10-09 22:14:55 +0200306 if (f == NULL) {
307 zip_error_set(error, ZIP_ER_OPEN, errno);
308 return -1;
309 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100310
Dieter Baron91374c72014-10-09 22:14:55 +0200311 fwrite(MARK_BEGIN, 4, 1, f);
312 write_u64(buffer->fragment_size, f);
313 write_u64(buffer->size, f);
Thomas Klausner28c97922016-01-12 13:48:48 +0100314
Dieter Baron91374c72014-10-09 22:14:55 +0200315 nul_run = 0;
316 for (i=0; i * buffer->fragment_size <buffer->size; i++) {
317 if (buffer->fragment[i] == NULL || only_nul(buffer->fragment[i], buffer->fragment_size)) {
318 nul_run++;
319 }
320 else {
321 if (nul_run > 0) {
322 write_nuls(nul_run, f);
323 nul_run = 0;
324 }
325 fwrite(MARK_DATA, 4, 1, f);
Thomas Klausner28c97922016-01-12 13:48:48 +0100326
Dieter Baron91374c72014-10-09 22:14:55 +0200327 fwrite(buffer->fragment[i], 1, buffer->fragment_size, f);
328 }
329 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100330
Dieter Baron91374c72014-10-09 22:14:55 +0200331 if (nul_run > 0) {
332 write_nuls(nul_run, f);
333 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100334
Dieter Baron91374c72014-10-09 22:14:55 +0200335 if (fclose(f) != 0) {
336 zip_error_set(error, ZIP_ER_WRITE, errno);
337 return -1;
338 }
339
340 return 0;
341}
342
343
344static zip_int64_t
345buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *error)
346{
Thomas Klausnerb51f6132016-01-05 14:07:07 +0100347 zip_uint8_t **fragment;
Dieter Baron91374c72014-10-09 22:14:55 +0200348 if (buffer->offset + length > buffer->nfragments * buffer->fragment_size) {
349 zip_uint64_t needed_fragments = (buffer->offset + length + buffer->fragment_size - 1) / buffer->fragment_size;
350 zip_uint64_t new_capacity = buffer->nfragments;
351 zip_uint64_t i;
Thomas Klausner28c97922016-01-12 13:48:48 +0100352
Dieter Baron91374c72014-10-09 22:14:55 +0200353 if (new_capacity == 0) {
354 new_capacity = 4;
355 }
356 while (new_capacity < needed_fragments) {
357 new_capacity *= 2;
358 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100359
Thomas Klausnerb51f6132016-01-05 14:07:07 +0100360 fragment = realloc(buffer->fragment, new_capacity * sizeof(*fragment));
Thomas Klausner28c97922016-01-12 13:48:48 +0100361
Dieter Baron91374c72014-10-09 22:14:55 +0200362 if (fragment == NULL) {
363 zip_error_set(error, ZIP_ER_MEMORY, 0);
364 return -1;
365 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100366
Dieter Baron91374c72014-10-09 22:14:55 +0200367 for (i = buffer->nfragments; i < new_capacity; i++) {
368 fragment[i] = NULL;
369 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100370
Dieter Baron91374c72014-10-09 22:14:55 +0200371 buffer->fragment = fragment;
372 buffer->nfragments = new_capacity;
373 }
374
375 if (!only_nul(data, length)) {
376 zip_uint64_t idx, n, fragment_offset;
Thomas Klausner28c97922016-01-12 13:48:48 +0100377
Dieter Baron91374c72014-10-09 22:14:55 +0200378 idx = buffer->offset / buffer->fragment_size;
379 fragment_offset = buffer->offset % buffer->fragment_size;
380 n = 0;
Thomas Klausner28c97922016-01-12 13:48:48 +0100381
Dieter Baron91374c72014-10-09 22:14:55 +0200382 while (n < length) {
383 zip_uint64_t left = MY_MIN(length - n, buffer->fragment_size - fragment_offset);
Thomas Klausner28c97922016-01-12 13:48:48 +0100384
Dieter Baron91374c72014-10-09 22:14:55 +0200385 if (buffer->fragment[idx] == NULL) {
386 if ((buffer->fragment[idx] = (zip_uint8_t *)malloc(buffer->fragment_size)) == NULL) {
387 zip_error_set(error, ZIP_ER_MEMORY, 0);
388 return -1;
389 }
390 memset(buffer->fragment[idx], 0, buffer->fragment_size);
391 }
392 memcpy(buffer->fragment[idx] + fragment_offset, data + n, left);
Thomas Klausner28c97922016-01-12 13:48:48 +0100393
Dieter Baron91374c72014-10-09 22:14:55 +0200394 n += left;
395 idx++;
396 fragment_offset = 0;
397 }
398 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100399
Dieter Baron91374c72014-10-09 22:14:55 +0200400 buffer->offset += length;
401 if (buffer->offset > buffer->size) {
402 buffer->size = buffer->offset;
403 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100404
Dieter Baron91374c72014-10-09 22:14:55 +0200405 return (zip_int64_t)length;
406}
407
408
409static zip_uint64_t
410get_u64(const zip_uint8_t *b)
411{
412 zip_uint64_t i;
Thomas Klausner28c97922016-01-12 13:48:48 +0100413
Dieter Baron91374c72014-10-09 22:14:55 +0200414 i = (zip_uint64_t)b[0] << 56 | (zip_uint64_t)b[1] << 48 | (zip_uint64_t)b[2] << 40 | (zip_uint64_t)b[3] << 32 | (zip_uint64_t)b[4] << 24 | (zip_uint64_t)b[5] << 16 | (zip_uint64_t)b[6] << 8 | (zip_uint64_t)b[7];
Thomas Klausner28c97922016-01-12 13:48:48 +0100415
Dieter Baron91374c72014-10-09 22:14:55 +0200416 return i;
417}
418
419
420static int
421only_nul(const zip_uint8_t *data, zip_uint64_t length)
422{
423 zip_uint64_t i;
Thomas Klausner28c97922016-01-12 13:48:48 +0100424
Dieter Baron91374c72014-10-09 22:14:55 +0200425 for (i=0; i< length; i++) {
426 if (data[i] != '\0') {
427 return 0;
428 }
429 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100430
Dieter Baron91374c72014-10-09 22:14:55 +0200431 return 1;
432}
433
434
435static int
436write_nuls(zip_uint64_t n, FILE *f)
437{
438 if (fwrite(MARK_NUL, 4, 1, f) != 1) {
439 return -1;
440 }
441 return write_u64(n, f);
442}
443
444
445static int
446write_u64(zip_uint64_t u64, FILE *f)
447{
448 zip_uint8_t b[8];
Thomas Klausner28c97922016-01-12 13:48:48 +0100449
Thomas Klausner8cff4bd2014-12-02 12:17:39 +0100450 b[0] = (zip_uint8_t)((u64 >> 56) & 0xff);
451 b[1] = (zip_uint8_t)((u64 >> 48) & 0xff);
452 b[2] = (zip_uint8_t)((u64 >> 40) & 0xff);
453 b[3] = (zip_uint8_t)((u64 >> 32) & 0xff);
454 b[4] = (zip_uint8_t)((u64 >> 24) & 0xff);
455 b[5] = (zip_uint8_t)((u64 >> 16) & 0xff);
456 b[6] = (zip_uint8_t)((u64 >> 8) & 0xff);
457 b[7] = (zip_uint8_t)(u64 & 0xff);
Thomas Klausner28c97922016-01-12 13:48:48 +0100458
Dieter Baron91374c72014-10-09 22:14:55 +0200459 return fwrite(b, 8, 1, f) == 1 ? 0 : -1;
460}
461
462
463static void
464hole_free(hole_t *hole) {
465 if (hole == NULL) {
466 return;
467 }
468 zip_error_fini(&hole->error);
469 buffer_free(hole->in);
470 buffer_free(hole->out);
471 free(hole->fname);
472 free(hole);
473}
474
475
476static hole_t *
477hole_new(const char *fname, int flags, zip_error_t *error)
478{
479 hole_t *ctx = (hole_t *)malloc(sizeof(*ctx));
Thomas Klausner28c97922016-01-12 13:48:48 +0100480
Dieter Baron91374c72014-10-09 22:14:55 +0200481 if (ctx == NULL) {
482 zip_error_set(error, ZIP_ER_MEMORY, 0);
483 return NULL;
484 }
485
486 if ((ctx->fname = strdup(fname)) == NULL) {
487 free(ctx);
488 zip_error_set(error, ZIP_ER_MEMORY, 0);
489 return NULL;
490 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100491
Dieter Baron91374c72014-10-09 22:14:55 +0200492 if ((ctx->in = buffer_from_file(fname, flags, error)) == NULL) {
493 free(ctx);
494 return NULL;
495 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100496
Dieter Baron91374c72014-10-09 22:14:55 +0200497 zip_error_init(&ctx->error);
498 ctx->out = NULL;
Thomas Klausner28c97922016-01-12 13:48:48 +0100499
Dieter Baron91374c72014-10-09 22:14:55 +0200500 return ctx;
501}
502
503
504static zip_int64_t
505source_hole_cb(void *ud, void *data, zip_uint64_t length, zip_source_cmd_t command)
506{
507 hole_t *ctx = (hole_t *)ud;
Thomas Klausner28c97922016-01-12 13:48:48 +0100508
Dieter Baron91374c72014-10-09 22:14:55 +0200509 switch (command) {
510 case ZIP_SOURCE_BEGIN_WRITE:
511 ctx->out = buffer_new();
512 return 0;
Thomas Klausner28c97922016-01-12 13:48:48 +0100513
Dieter Baron91374c72014-10-09 22:14:55 +0200514 case ZIP_SOURCE_CLOSE:
515 return 0;
Thomas Klausner28c97922016-01-12 13:48:48 +0100516
Dieter Baron91374c72014-10-09 22:14:55 +0200517 case ZIP_SOURCE_COMMIT_WRITE:
518 if (buffer_to_file(ctx->out, ctx->fname, &ctx->error) < 0) {
519 return -1;
520 }
521 buffer_free(ctx->in);
522 ctx->in = ctx->out;
523 ctx->out = NULL;
524 return 0;
Thomas Klausner28c97922016-01-12 13:48:48 +0100525
Dieter Baron91374c72014-10-09 22:14:55 +0200526 case ZIP_SOURCE_ERROR:
527 return zip_error_to_data(&ctx->error, data, length);
Thomas Klausner28c97922016-01-12 13:48:48 +0100528
Dieter Baron91374c72014-10-09 22:14:55 +0200529 case ZIP_SOURCE_FREE:
530 hole_free(ctx);
531 return 0;
Thomas Klausner28c97922016-01-12 13:48:48 +0100532
Dieter Baron91374c72014-10-09 22:14:55 +0200533 case ZIP_SOURCE_OPEN:
534 ctx->in->offset = 0;
535 return 0;
Thomas Klausner28c97922016-01-12 13:48:48 +0100536
Dieter Baron91374c72014-10-09 22:14:55 +0200537 case ZIP_SOURCE_READ:
538 return buffer_read(ctx->in, data, length, &ctx->error);
539
540 case ZIP_SOURCE_REMOVE:
541 buffer_free(ctx->in);
542 ctx->in = buffer_new();
543 buffer_free(ctx->out);
544 ctx->out = NULL;
Thomas Klausner1f6d0152015-04-27 14:59:55 +0200545 (void)remove(ctx->fname);
Dieter Baron91374c72014-10-09 22:14:55 +0200546 return 0;
Thomas Klausner28c97922016-01-12 13:48:48 +0100547
Dieter Baron91374c72014-10-09 22:14:55 +0200548 case ZIP_SOURCE_ROLLBACK_WRITE:
549 buffer_free(ctx->out);
550 ctx->out = NULL;
551 return 0;
Thomas Klausner28c97922016-01-12 13:48:48 +0100552
Dieter Baron91374c72014-10-09 22:14:55 +0200553 case ZIP_SOURCE_SEEK:
554 return buffer_seek(ctx->in, data, length, &ctx->error);
Thomas Klausner28c97922016-01-12 13:48:48 +0100555
Dieter Baron91374c72014-10-09 22:14:55 +0200556 case ZIP_SOURCE_SEEK_WRITE:
557 return buffer_seek(ctx->out, data, length, &ctx->error);
Thomas Klausner28c97922016-01-12 13:48:48 +0100558
Dieter Baron91374c72014-10-09 22:14:55 +0200559 case ZIP_SOURCE_STAT: {
560 zip_stat_t *st = ZIP_SOURCE_GET_ARGS(zip_stat_t, data, length, &ctx->error);
Thomas Klausner28c97922016-01-12 13:48:48 +0100561
Dieter Baron91374c72014-10-09 22:14:55 +0200562 if (st == NULL) {
563 return -1;
564 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100565
Dieter Baron91374c72014-10-09 22:14:55 +0200566 /* TODO: return ENOENT if fname doesn't exist */
Thomas Klausner28c97922016-01-12 13:48:48 +0100567
Dieter Baron91374c72014-10-09 22:14:55 +0200568 st->valid |= ZIP_STAT_SIZE;
569 st->size = ctx->in->size;
570 return 0;
571 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100572
Dieter Baron91374c72014-10-09 22:14:55 +0200573 case ZIP_SOURCE_TELL:
574 return (zip_int64_t)ctx->in->offset;
575
576 case ZIP_SOURCE_TELL_WRITE:
577 return (zip_int64_t)ctx->out->offset;
Thomas Klausner28c97922016-01-12 13:48:48 +0100578
Dieter Baron91374c72014-10-09 22:14:55 +0200579 case ZIP_SOURCE_WRITE:
580 return buffer_write(ctx->out, data, length, &ctx->error);
Thomas Klausner28c97922016-01-12 13:48:48 +0100581
Dieter Baron91374c72014-10-09 22:14:55 +0200582 case ZIP_SOURCE_SUPPORTS:
583 return zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_CLOSE, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_REMOVE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_STAT, ZIP_SOURCE_TELL, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_WRITE, -1);
Thomas Klausner28c97922016-01-12 13:48:48 +0100584
Dieter Baron91374c72014-10-09 22:14:55 +0200585 default:
586 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
587 return -1;
588 }
589}