1 /*
2 zip_source_window.c -- return part of lower source
3 Copyright (C) 2012-2019 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 <stdlib.h>
36 #include <string.h>
37
38 #include "zipint.h"
39
40 struct window {
41 zip_uint64_t start; /* where in file we start reading */
42 zip_uint64_t end; /* where in file we stop reading */
43
44 /* if not NULL, read file data for this file */
45 zip_t *source_archive;
46 zip_uint64_t source_index;
47
48 zip_uint64_t offset; /* offset in src for next read */
49
50 zip_stat_t stat;
51 zip_file_attributes_t attributes;
52 zip_error_t error;
53 zip_int64_t supports;
54 bool needs_seek;
55 };
56
57 static zip_int64_t window_read(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);
58
59
60 zip_source_t *
zip_source_window(zip_t * za,zip_source_t * src,zip_uint64_t start,zip_uint64_t len)61 zip_source_window(zip_t *za, zip_source_t *src, zip_uint64_t start, zip_uint64_t len) {
62 return _zip_source_window_new(src, start, len, NULL, 0, NULL, 0, &za->error);
63 }
64
65
66 zip_source_t *
_zip_source_window_new(zip_source_t * src,zip_uint64_t start,zip_uint64_t length,zip_stat_t * st,zip_file_attributes_t * attributes,zip_t * source_archive,zip_uint64_t source_index,zip_error_t * error)67 _zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_uint64_t length, zip_stat_t *st, zip_file_attributes_t *attributes, zip_t *source_archive, zip_uint64_t source_index, zip_error_t *error) {
68 struct window *ctx;
69
70 if (src == NULL || start + length < start || (source_archive == NULL && source_index != 0)) {
71 zip_error_set(error, ZIP_ER_INVAL, 0);
72 return NULL;
73 }
74
75 if ((ctx = (struct window *)malloc(sizeof(*ctx))) == NULL) {
76 zip_error_set(error, ZIP_ER_MEMORY, 0);
77 return NULL;
78 }
79
80 ctx->start = start;
81 ctx->end = start + length;
82 zip_stat_init(&ctx->stat);
83 if (attributes != NULL) {
84 memcpy(&ctx->attributes, attributes, sizeof(ctx->attributes));
85 }
86 else {
87 zip_file_attributes_init(&ctx->attributes);
88 }
89 ctx->source_archive = source_archive;
90 ctx->source_index = source_index;
91 zip_error_init(&ctx->error);
92 ctx->supports = (zip_source_supports(src) & ZIP_SOURCE_SUPPORTS_SEEKABLE) | (zip_source_make_command_bitmap(ZIP_SOURCE_GET_FILE_ATTRIBUTES, ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1));
93 ctx->needs_seek = (ctx->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK)) ? true : false;
94
95 if (st) {
96 if (_zip_stat_merge(&ctx->stat, st, error) < 0) {
97 free(ctx);
98 return NULL;
99 }
100 }
101
102 return zip_source_layered_create(src, window_read, ctx, error);
103 }
104
105
106 int
_zip_source_set_source_archive(zip_source_t * src,zip_t * za)107 _zip_source_set_source_archive(zip_source_t *src, zip_t *za) {
108 src->source_archive = za;
109 return _zip_register_source(za, src);
110 }
111
112
113 /* called by zip_discard to avoid operating on file from closed archive */
114 void
_zip_source_invalidate(zip_source_t * src)115 _zip_source_invalidate(zip_source_t *src) {
116 src->source_closed = 1;
117
118 if (zip_error_code_zip(&src->error) == ZIP_ER_OK) {
119 zip_error_set(&src->error, ZIP_ER_ZIPCLOSED, 0);
120 }
121 }
122
123
124 static zip_int64_t
window_read(zip_source_t * src,void * _ctx,void * data,zip_uint64_t len,zip_source_cmd_t cmd)125 window_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
126 struct window *ctx;
127 zip_int64_t ret;
128 zip_uint64_t n, i;
129
130 ctx = (struct window *)_ctx;
131
132 switch (cmd) {
133 case ZIP_SOURCE_CLOSE:
134 return 0;
135
136 case ZIP_SOURCE_ERROR:
137 return zip_error_to_data(&ctx->error, data, len);
138
139 case ZIP_SOURCE_FREE:
140 free(ctx);
141 return 0;
142
143 case ZIP_SOURCE_OPEN:
144 if (ctx->source_archive) {
145 zip_uint64_t offset;
146
147 if ((offset = _zip_file_get_offset(ctx->source_archive, ctx->source_index, &ctx->error)) == 0) {
148 return -1;
149 }
150 if (ctx->end + offset < ctx->end) {
151 /* zip archive data claims end of data past zip64 limits */
152 zip_error_set(&ctx->error, ZIP_ER_INCONS, 0);
153 return -1;
154 }
155 ctx->start += offset;
156 ctx->end += offset;
157 ctx->source_archive = NULL;
158 }
159
160 if (!ctx->needs_seek) {
161 DEFINE_BYTE_ARRAY(b, BUFSIZE);
162
163 if (!byte_array_init(b, BUFSIZE)) {
164 zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
165 return -1;
166 }
167
168 for (n = 0; n < ctx->start; n += (zip_uint64_t)ret) {
169 i = (ctx->start - n > BUFSIZE ? BUFSIZE : ctx->start - n);
170 if ((ret = zip_source_read(src, b, i)) < 0) {
171 _zip_error_set_from_source(&ctx->error, src);
172 byte_array_fini(b);
173 return -1;
174 }
175 if (ret == 0) {
176 zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
177 byte_array_fini(b);
178 return -1;
179 }
180 }
181
182 byte_array_fini(b);
183 }
184
185 ctx->offset = ctx->start;
186 return 0;
187
188 case ZIP_SOURCE_READ:
189 if (len > ctx->end - ctx->offset)
190 len = ctx->end - ctx->offset;
191
192 if (len == 0)
193 return 0;
194
195 if (ctx->needs_seek) {
196 if (zip_source_seek(src, (zip_int64_t)ctx->offset, SEEK_SET) < 0) {
197 _zip_error_set_from_source(&ctx->error, src);
198 return -1;
199 }
200 }
201
202 if ((ret = zip_source_read(src, data, len)) < 0) {
203 zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
204 return -1;
205 }
206
207 ctx->offset += (zip_uint64_t)ret;
208
209 if (ret == 0) {
210 if (ctx->offset < ctx->end) {
211 zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
212 return -1;
213 }
214 }
215 return ret;
216
217 case ZIP_SOURCE_SEEK: {
218 zip_int64_t new_offset = zip_source_seek_compute_offset(ctx->offset - ctx->start, ctx->end - ctx->start, data, len, &ctx->error);
219
220 if (new_offset < 0) {
221 return -1;
222 }
223
224 ctx->offset = (zip_uint64_t)new_offset + ctx->start;
225 return 0;
226 }
227
228 case ZIP_SOURCE_STAT: {
229 zip_stat_t *st;
230
231 st = (zip_stat_t *)data;
232
233 if (_zip_stat_merge(st, &ctx->stat, &ctx->error) < 0) {
234 return -1;
235 }
236 return 0;
237 }
238
239 case ZIP_SOURCE_GET_FILE_ATTRIBUTES:
240 if (len < sizeof(ctx->attributes)) {
241 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
242 return -1;
243 }
244
245 memcpy(data, &ctx->attributes, sizeof(ctx->attributes));
246 return sizeof(ctx->attributes);
247
248 case ZIP_SOURCE_SUPPORTS:
249 return ctx->supports;
250
251 case ZIP_SOURCE_TELL:
252 return (zip_int64_t)(ctx->offset - ctx->start);
253
254 default:
255 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
256 return -1;
257 }
258 }
259
260
261 void
_zip_deregister_source(zip_t * za,zip_source_t * src)262 _zip_deregister_source(zip_t *za, zip_source_t *src) {
263 unsigned int i;
264
265 for (i = 0; i < za->nopen_source; i++) {
266 if (za->open_source[i] == src) {
267 za->open_source[i] = za->open_source[za->nopen_source - 1];
268 za->nopen_source--;
269 break;
270 }
271 }
272 }
273
274
275 int
_zip_register_source(zip_t * za,zip_source_t * src)276 _zip_register_source(zip_t *za, zip_source_t *src) {
277 zip_source_t **open_source;
278
279 if (za->nopen_source + 1 >= za->nopen_source_alloc) {
280 unsigned int n;
281 n = za->nopen_source_alloc + 10;
282 open_source = (zip_source_t **)realloc(za->open_source, n * sizeof(zip_source_t *));
283 if (open_source == NULL) {
284 zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
285 return -1;
286 }
287 za->nopen_source_alloc = n;
288 za->open_source = open_source;
289 }
290
291 za->open_source[za->nopen_source++] = src;
292
293 return 0;
294 }
295