blob: 191a81cf3cf08a2269249c52c12979fc6a314348 [file] [log] [blame]
Dieter Baronbbb63691999-07-26 22:04:20 +00001/*
Thomas Klausnerf2dc4362004-11-18 15:06:24 +00002 zip_source_filep.c -- create data source from FILE *
Thomas Klausnera1415de2015-04-29 15:36:30 +02003 Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner
Dieter Baronbbb63691999-07-26 22:04:20 +00004
Dieter Barondd9afca2003-10-02 14:13:37 +00005 This file is part of libzip, a library to manipulate ZIP archives.
Dieter Baronb86c4332007-11-07 14:35:13 +01006 The authors can be contacted at <libzip@nih.at>
Dieter Baronbbb63691999-07-26 22:04:20 +00007
Dieter Barondd9afca2003-10-02 14:13:37 +00008 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.
Dieter Baronbbb63691999-07-26 22:04:20 +000032*/
33
Dieter Baron0e339b62004-06-24 15:01:59 +000034#include <sys/stat.h>
Dieter Baron0e339b62004-06-24 15:01:59 +000035#include <stdio.h>
Dieter Baron91c5d811999-07-26 20:02:38 +000036#include <stdlib.h>
Dieter Baron0e339b62004-06-24 15:01:59 +000037#include <string.h>
Thomas Klausner24bba9d2015-05-04 10:54:29 +020038
Thomas Klausner51180602015-08-21 13:36:26 +020039#include "zipint.h"
40
Thomas Klausner8e09bec2015-02-19 01:13:17 +010041#ifdef _WIN32
42/* WIN32 needs <fcntl.h> for _O_BINARY */
Andrew Molyneuxad79c282014-12-11 16:58:26 +000043#include <fcntl.h>
Thomas Klausner8e09bec2015-02-19 01:13:17 +010044#endif
Thomas Klausner24bba9d2015-05-04 10:54:29 +020045
46/* Windows sys/types.h does not provide these */
47#ifndef S_ISREG
Andrew Molyneuxad79c282014-12-11 16:58:26 +000048#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
Thomas Klausner24bba9d2015-05-04 10:54:29 +020049#endif
Thomas Klausnerf9091822015-05-26 08:13:45 +020050#if defined(S_IXUSR) && defined(S_IRWXG) && defined(S_IRWXO)
51#define _SAFE_MASK (S_IXUSR | S_IRWXG | S_IRWXO)
52#elif defined(_S_IWRITE)
53#define _SAFE_MASK (_S_IWRITE)
54#else
55#error do not know safe values for umask, please report this
Thomas Klausner24bba9d2015-05-04 10:54:29 +020056#endif
57
58#ifdef _MSC_VER
Andrew Molyneuxad79c282014-12-11 16:58:26 +000059/* MSVC doesn't have mode_t */
60typedef int mode_t;
61#endif
Dieter Baron91c5d811999-07-26 20:02:38 +000062
Dieter Baron91c5d811999-07-26 20:02:38 +000063struct read_file {
Thomas Klausnerea8ba492014-09-23 16:54:47 +020064 zip_error_t error; /* last error information */
65 zip_int64_t supports;
Dieter Baron2f3f11c2009-02-14 18:58:01 +010066
Thomas Klausnerea8ba492014-09-23 16:54:47 +020067 /* reading */
68 char *fname; /* name of file to read from */
69 FILE *f; /* file to read from */
Thomas Klausnerea8ba492014-09-23 16:54:47 +020070 struct zip_stat st; /* stat information passed in */
71 zip_uint64_t start; /* start offset of data to read */
72 zip_uint64_t end; /* end offset of data to read, 0 for up to EOF */
73 zip_uint64_t current; /* current offset */
74
75 /* writing */
76 char *tmpname;
77 FILE *fout;
Dieter Baron91c5d811999-07-26 20:02:38 +000078};
79
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020080static zip_int64_t read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd);
Thomas Klausnerea8ba492014-09-23 16:54:47 +020081static int create_temp_output(struct read_file *ctx);
Thomas Klausner23f588e2014-12-02 12:40:45 +010082static int _zip_fseek_u(FILE *f, zip_uint64_t offset, int whence, zip_error_t *error);
83static int _zip_fseek(FILE *f, zip_int64_t offset, int whence, zip_error_t *error);
Dieter Baron91c5d811999-07-26 20:02:38 +000084
Dieter Baron91c5d811999-07-26 20:02:38 +000085
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020086ZIP_EXTERN zip_source_t *
87zip_source_filep(zip_t *za, FILE *file, zip_uint64_t start, zip_int64_t len)
Dieter Baronb2ed74d2004-04-14 14:01:31 +000088{
Thomas Klausner7b221722004-11-18 16:28:13 +000089 if (za == NULL)
90 return NULL;
Thomas Klausnerea8ba492014-09-23 16:54:47 +020091
92 return zip_source_filep_create(file, start, len, &za->error);
93}
Thomas Klausner7b221722004-11-18 16:28:13 +000094
Thomas Klausnerea8ba492014-09-23 16:54:47 +020095
96ZIP_EXTERN zip_source_t *
97zip_source_filep_create(FILE *file, zip_uint64_t start, zip_int64_t length, zip_error_t *error)
98{
99 if (file == NULL || length < -1) {
100 zip_error_set(error, ZIP_ER_INVAL, 0);
Thomas Klausner7b221722004-11-18 16:28:13 +0000101 return NULL;
102 }
103
Thomas Klausner851aebe2015-04-24 12:36:25 +0200104 return _zip_source_file_or_p(NULL, file, start, length, NULL, error);
Dieter Baronf26f8412008-07-21 17:31:25 +0200105}
106
Dieter Baronf26f8412008-07-21 17:31:25 +0200107
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200108zip_source_t *
Thomas Klausner851aebe2015-04-24 12:36:25 +0200109_zip_source_file_or_p(const char *fname, FILE *file, zip_uint64_t start, zip_int64_t len, const zip_stat_t *st, zip_error_t *error)
Dieter Baronf26f8412008-07-21 17:31:25 +0200110{
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200111 struct read_file *ctx;
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200112 zip_source_t *zs;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200113
Dieter Baronf26f8412008-07-21 17:31:25 +0200114 if (file == NULL && fname == NULL) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200115 zip_error_set(error, ZIP_ER_INVAL, 0);
116 return NULL;
117 }
118
119 if ((ctx=(struct read_file *)malloc(sizeof(struct read_file))) == NULL) {
120 zip_error_set(error, ZIP_ER_MEMORY, 0);
Dieter Baronf26f8412008-07-21 17:31:25 +0200121 return NULL;
122 }
123
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200124 ctx->fname = NULL;
Dieter Baronf26f8412008-07-21 17:31:25 +0200125 if (fname) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200126 if ((ctx->fname=strdup(fname)) == NULL) {
127 zip_error_set(error, ZIP_ER_MEMORY, 0);
128 free(ctx);
Dieter Baronf26f8412008-07-21 17:31:25 +0200129 return NULL;
130 }
131 }
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200132 ctx->f = file;
133 ctx->start = start;
134 ctx->end = (len < 0 ? 0 : start+(zip_uint64_t)len);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200135 if (st) {
136 memcpy(&ctx->st, st, sizeof(ctx->st));
137 ctx->st.name = NULL;
138 ctx->st.valid &= ~ZIP_STAT_NAME;
139 }
140 else {
141 zip_stat_init(&ctx->st);
142 }
143
144 ctx->tmpname = NULL;
145 ctx->fout = NULL;
146
147 zip_error_init(&ctx->error);
Dieter Baron2f3f11c2009-02-14 18:58:01 +0100148
Dieter Baron8631d4b2014-10-10 16:28:54 +0200149 ctx->supports = ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200150 if (ctx->fname) {
151 struct stat sb;
152
153 if (stat(ctx->fname, &sb) < 0 || S_ISREG(sb.st_mode)) {
Dieter Baron8631d4b2014-10-10 16:28:54 +0200154 ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200155 }
156 }
Thomas Klausnera42dae82014-10-23 18:53:05 +0200157 else if (fseeko(ctx->f, 0, SEEK_CUR) == 0) {
Dieter Baron8631d4b2014-10-10 16:28:54 +0200158 ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200159 }
160
161 if ((zs=zip_source_function_create(read_file, ctx, error)) == NULL) {
Thomas Klausnera7df0552015-01-27 14:58:33 +0100162 free(ctx->fname);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200163 free(ctx);
Thomas Klausnerf2dc4362004-11-18 15:06:24 +0000164 return NULL;
165 }
166
167 return zs;
Dieter Baron91c5d811999-07-26 20:02:38 +0000168}
169
Dieter Baron91c5d811999-07-26 20:02:38 +0000170
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200171static int
172create_temp_output(struct read_file *ctx)
Thomas Klausner6756cb82014-05-08 14:40:22 +0200173{
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200174 char *temp;
175 int tfd;
Thomas Klausner51ee9b92015-04-27 15:34:07 +0200176 mode_t mask;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200177 FILE *tfp;
178
179 if ((temp=(char *)malloc(strlen(ctx->fname)+8)) == NULL) {
180 zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
181 return -1;
Thomas Klausner6756cb82014-05-08 14:40:22 +0200182 }
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200183 sprintf(temp, "%s.XXXXXX", ctx->fname);
Thomas Klausner51ee9b92015-04-27 15:34:07 +0200184
Thomas Klausnerf9091822015-05-26 08:13:45 +0200185 mask = umask(_SAFE_MASK);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200186 if ((tfd=mkstemp(temp)) == -1) {
187 zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
Thomas Klausner51ee9b92015-04-27 15:34:07 +0200188 umask(mask);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200189 free(temp);
190 return -1;
191 }
Thomas Klausner51ee9b92015-04-27 15:34:07 +0200192 umask(mask);
193
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200194 if ((tfp=fdopen(tfd, "r+b")) == NULL) {
195 zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
196 close(tfd);
197 (void)remove(temp);
198 free(temp);
199 return -1;
200 }
201
202#ifdef _WIN32
203 /*
204 According to Pierre Joye, Windows in some environments per
205 default creates text files, so force binary mode.
206 */
207 _setmode(_fileno(tfp), _O_BINARY );
208#endif
209
210 ctx->fout = tfp;
211 ctx->tmpname = temp;
212
213 return 0;
Thomas Klausner6756cb82014-05-08 14:40:22 +0200214}
215
216
Dieter Baroncb1379d2009-03-10 14:46:51 +0100217static zip_int64_t
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200218read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd)
Dieter Baron91c5d811999-07-26 20:02:38 +0000219{
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200220 struct read_file *ctx;
Dieter Baron91c5d811999-07-26 20:02:38 +0000221 char *buf;
Dieter Barona1f8e2c2013-05-14 22:21:34 +0200222 zip_uint64_t n;
223 size_t i;
Dieter Baron91c5d811999-07-26 20:02:38 +0000224
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200225 ctx = (struct read_file *)state;
Dieter Baron91c5d811999-07-26 20:02:38 +0000226 buf = (char *)data;
227
228 switch (cmd) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200229 case ZIP_SOURCE_BEGIN_WRITE:
230 if (ctx->fname == NULL) {
231 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
Dieter Baronabc6fd72012-07-22 15:49:45 +0200232 return -1;
233 }
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200234 return create_temp_output(ctx);
235
236 case ZIP_SOURCE_COMMIT_WRITE: {
237 mode_t mask;
238
239 if (fclose(ctx->fout) < 0) {
240 ctx->fout = NULL;
241 zip_error_set(&ctx->error, ZIP_ER_WRITE, errno);
242 }
243 ctx->fout = NULL;
244 if (rename(ctx->tmpname, ctx->fname) < 0) {
245 zip_error_set(&ctx->error, ZIP_ER_RENAME, errno);
246 return -1;
247 }
248 mask = umask(022);
249 umask(mask);
Thomas Klausnerf5e55642015-04-29 18:04:00 +0200250 /* not much we can do if chmod fails except make the whole commit fail */
251 (void)chmod(ctx->fname, 0666&~mask);
Thomas Klausner60377f92014-12-15 10:22:39 +0100252 free(ctx->tmpname);
253 ctx->tmpname = NULL;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200254 return 0;
Dieter Baron91c5d811999-07-26 20:02:38 +0000255 }
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200256
257 case ZIP_SOURCE_CLOSE:
258 if (ctx->fname) {
259 fclose(ctx->f);
260 ctx->f = NULL;
261 }
262 return 0;
263
264 case ZIP_SOURCE_ERROR:
265 return zip_error_to_data(&ctx->error, data, len);
266
267 case ZIP_SOURCE_FREE:
268 free(ctx->fname);
Thomas Klausner60377f92014-12-15 10:22:39 +0100269 free(ctx->tmpname);
Thomas Klausner9c2fa922015-04-24 12:40:32 +0200270 if (ctx->f)
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200271 fclose(ctx->f);
272 free(ctx);
273 return 0;
274
275 case ZIP_SOURCE_OPEN:
276 if (ctx->fname) {
277 if ((ctx->f=fopen(ctx->fname, "rb")) == NULL) {
278 zip_error_set(&ctx->error, ZIP_ER_OPEN, errno);
279 return -1;
280 }
281 }
282
Thomas Klausner9c2fa922015-04-24 12:40:32 +0200283 if (ctx->start > 0) {
Thomas Klausner23f588e2014-12-02 12:40:45 +0100284 if (_zip_fseek_u(ctx->f, ctx->start, SEEK_SET, &ctx->error) < 0) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200285 return -1;
286 }
287 }
288 ctx->current = ctx->start;
289 return 0;
290
291 case ZIP_SOURCE_READ:
292 if (ctx->end > 0) {
293 n = ctx->end-ctx->current;
294 if (n > len) {
295 n = len;
296 }
297 }
298 else {
299 n = len;
300 }
301
302 if (n > SIZE_MAX)
303 n = SIZE_MAX;
Dieter Baron91c5d811999-07-26 20:02:38 +0000304
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200305 if ((i=fread(buf, 1, (size_t)n, ctx->f)) == 0) {
306 if (ferror(ctx->f)) {
307 zip_error_set(&ctx->error, ZIP_ER_READ, errno);
308 return -1;
309 }
310 }
311 ctx->current += i;
312
313 return (zip_int64_t)i;
314
315 case ZIP_SOURCE_REMOVE:
316 if (remove(ctx->fname) < 0) {
317 zip_error_set(&ctx->error, ZIP_ER_REMOVE, errno);
318 return -1;
319 }
320 return 0;
321
322 case ZIP_SOURCE_ROLLBACK_WRITE:
323 if (ctx->fout) {
324 fclose(ctx->fout);
325 ctx->fout = NULL;
326 }
Thomas Klausner07dab032015-04-27 15:01:14 +0200327 (void)remove(ctx->tmpname);
Thomas Klausner60377f92014-12-15 10:22:39 +0100328 free(ctx->tmpname);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200329 ctx->tmpname = NULL;
330 return 0;
Dieter Baron91c5d811999-07-26 20:02:38 +0000331
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200332 case ZIP_SOURCE_SEEK: {
333 zip_int64_t new_current;
334 int need_seek;
335 zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);
Thomas Klausner6756cb82014-05-08 14:40:22 +0200336
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200337 if (args == NULL)
338 return -1;
339
Thomas Klausner9c2fa922015-04-24 12:40:32 +0200340 need_seek = 1;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200341
342 switch (args->whence) {
343 case SEEK_SET:
344 new_current = args->offset;
345 break;
346
347 case SEEK_END:
348 if (ctx->end == 0) {
Thomas Klausner23f588e2014-12-02 12:40:45 +0100349 if (_zip_fseek(ctx->f, args->offset, SEEK_END, &ctx->error) < 0) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200350 return -1;
351 }
352 if ((new_current = ftello(ctx->f)) < 0) {
353 zip_error_set(&ctx->error, ZIP_ER_SEEK, errno);
354 return -1;
355 }
356 need_seek = 0;
357 }
358 else {
359 new_current = (zip_int64_t)ctx->end + args->offset;
360 }
361 break;
362 case SEEK_CUR:
363 new_current = (zip_int64_t)ctx->current + args->offset;
364 break;
Dieter Baron0e339b62004-06-24 15:01:59 +0000365
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200366 default:
367 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
368 return -1;
369 }
Thomas Klausner6756cb82014-05-08 14:40:22 +0200370
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200371 if (new_current < 0 || (zip_uint64_t)new_current < ctx->start || (ctx->end != 0 && (zip_uint64_t)new_current > ctx->end)) {
372 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
373 return -1;
374 }
375
376 ctx->current = (zip_uint64_t)new_current;
377
378 if (need_seek) {
Thomas Klausner23f588e2014-12-02 12:40:45 +0100379 if (_zip_fseek_u(ctx->f, ctx->current, SEEK_SET, &ctx->error) < 0) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200380 return -1;
381 }
382 }
383 return 0;
384 }
385
386 case ZIP_SOURCE_SEEK_WRITE: {
Dieter Baron8a7278c2014-10-07 21:31:16 +0200387 zip_source_args_seek_t *args;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200388
Dieter Baron8a7278c2014-10-07 21:31:16 +0200389 args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);
390 if (args == NULL) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200391 return -1;
392 }
Dieter Baron8a7278c2014-10-07 21:31:16 +0200393
Thomas Klausner23f588e2014-12-02 12:40:45 +0100394 if (_zip_fseek(ctx->fout, args->offset, args->whence, &ctx->error) < 0) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200395 return -1;
396 }
397 return 0;
398 }
399
400 case ZIP_SOURCE_STAT: {
401 if (len < sizeof(ctx->st))
Dieter Baron0e339b62004-06-24 15:01:59 +0000402 return -1;
403
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200404 if (ctx->st.valid != 0)
405 memcpy(data, &ctx->st, sizeof(ctx->st));
Dieter Baron2f3f11c2009-02-14 18:58:01 +0100406 else {
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200407 zip_stat_t *st;
Dieter Baron10155932009-03-11 18:07:55 +0100408 struct stat fst;
409 int err;
410
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200411 if (ctx->f)
412 err = fstat(fileno(ctx->f), &fst);
Dieter Baron2f3f11c2009-02-14 18:58:01 +0100413 else
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200414 err = stat(ctx->fname, &fst);
Dieter Baronf26f8412008-07-21 17:31:25 +0200415
Dieter Baron2f3f11c2009-02-14 18:58:01 +0100416 if (err != 0) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200417 zip_error_set(&ctx->error, ZIP_ER_READ, errno);
Dieter Baron2f3f11c2009-02-14 18:58:01 +0100418 return -1;
419 }
420
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200421 st = (zip_stat_t *)data;
Dieter Baron2f3f11c2009-02-14 18:58:01 +0100422
423 zip_stat_init(st);
424 st->mtime = fst.st_mtime;
Dieter Barondc094e22009-03-12 11:49:05 +0100425 st->valid |= ZIP_STAT_MTIME;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200426 if (ctx->end != 0) {
427 st->size = ctx->end - ctx->start;
Dieter Barondc094e22009-03-12 11:49:05 +0100428 st->valid |= ZIP_STAT_SIZE;
429 }
430 else if ((fst.st_mode&S_IFMT) == S_IFREG) {
Dieter Baronabc6fd72012-07-22 15:49:45 +0200431 st->size = (zip_uint64_t)fst.st_size;
Dieter Barondc094e22009-03-12 11:49:05 +0100432 st->valid |= ZIP_STAT_SIZE;
433 }
Dieter Baron0e339b62004-06-24 15:01:59 +0000434 }
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200435 return sizeof(ctx->st);
Dieter Baron91c5d811999-07-26 20:02:38 +0000436 }
Dieter Baron0e339b62004-06-24 15:01:59 +0000437
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200438 case ZIP_SOURCE_SUPPORTS:
439 return ctx->supports;
440
441 case ZIP_SOURCE_TELL:
442 return (zip_int64_t)ctx->current;
443
444 case ZIP_SOURCE_TELL_WRITE:
445 {
446 off_t ret = ftello(ctx->fout);
447
448 if (ret < 0) {
449 zip_error_set(&ctx->error, ZIP_ER_TELL, errno);
450 return -1;
451 }
452 return ret;
453 }
454
455 case ZIP_SOURCE_WRITE:
456 {
457 size_t ret;
458
459 clearerr(ctx->fout);
460 ret = fwrite(data, 1, len, ctx->fout);
461 if (ret != len || ferror(ctx->fout)) {
462 zip_error_set(&ctx->error, ZIP_ER_WRITE, errno);
463 return -1;
464 }
465
466 return (zip_int64_t)ret;
467 }
Dieter Baron0e339b62004-06-24 15:01:59 +0000468
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200469 default:
470 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
471 return -1;
Dieter Baron91c5d811999-07-26 20:02:38 +0000472 }
Thomas Klausner6756cb82014-05-08 14:40:22 +0200473}
Thomas Klausner23f588e2014-12-02 12:40:45 +0100474
475
476static int
477_zip_fseek_u(FILE *f, zip_uint64_t offset, int whence, zip_error_t *error)
478{
479 if (offset > ZIP_INT64_MAX) {
480 zip_error_set(error, ZIP_ER_SEEK, EOVERFLOW);
481 return -1;
482 }
483 return _zip_fseek(f, (zip_int64_t)offset, whence, error);
484}
485
486
487static int
488_zip_fseek(FILE *f, zip_int64_t offset, int whence, zip_error_t *error)
489{
490 if (offset > ZIP_FSEEK_MAX || offset < ZIP_FSEEK_MIN) {
491 zip_error_set(error, ZIP_ER_SEEK, EOVERFLOW);
492 return -1;
493 }
494 if (fseeko(f, (off_t)offset, whence) < 0) {
495 zip_error_set(error, ZIP_ER_SEEK, errno);
496 return -1;
497 }
498 return 0;
499}