This source file includes following definitions.
- zip_source_filep
- zip_source_filep_create
- _zip_source_file_or_p
- create_temp_output
- read_file
- _zip_fseek_u
- _zip_fseek
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 #include <sys/stat.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include "zipint.h"
40
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
44
45 #ifdef _WIN32
46
47 #include <fcntl.h>
48 #endif
49
50
51 #ifndef S_ISREG
52 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
53 #endif
54 #if defined(S_IXUSR) && defined(S_IRWXG) && defined(S_IRWXO)
55 #define _SAFE_MASK (S_IXUSR | S_IRWXG | S_IRWXO)
56 #elif defined(_S_IWRITE)
57 #define _SAFE_MASK (_S_IWRITE)
58 #else
59 #error do not know safe values for umask, please report this
60 #endif
61
62 #ifdef _MSC_VER
63
64 typedef int mode_t;
65 #endif
66
67 struct read_file {
68 zip_error_t error;
69 zip_int64_t supports;
70
71
72 char *fname;
73 FILE *f;
74 struct zip_stat st;
75 zip_uint64_t start;
76 zip_uint64_t end;
77 zip_uint64_t current;
78
79
80 char *tmpname;
81 FILE *fout;
82 };
83
84 static zip_int64_t read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd);
85 static int create_temp_output(struct read_file *ctx);
86 static int _zip_fseek_u(FILE *f, zip_uint64_t offset, int whence, zip_error_t *error);
87 static int _zip_fseek(FILE *f, zip_int64_t offset, int whence, zip_error_t *error);
88
89
90 ZIP_EXTERN zip_source_t *
91 zip_source_filep(zip_t *za, FILE *file, zip_uint64_t start, zip_int64_t len)
92 {
93 if (za == NULL)
94 return NULL;
95
96 return zip_source_filep_create(file, start, len, &za->error);
97 }
98
99
100 ZIP_EXTERN zip_source_t *
101 zip_source_filep_create(FILE *file, zip_uint64_t start, zip_int64_t length, zip_error_t *error)
102 {
103 if (file == NULL || length < -1) {
104 zip_error_set(error, ZIP_ER_INVAL, 0);
105 return NULL;
106 }
107
108 return _zip_source_file_or_p(NULL, file, start, length, NULL, error);
109 }
110
111
112 zip_source_t *
113 _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)
114 {
115 struct read_file *ctx;
116 zip_source_t *zs;
117
118 if (file == NULL && fname == NULL) {
119 zip_error_set(error, ZIP_ER_INVAL, 0);
120 return NULL;
121 }
122
123 if ((ctx=(struct read_file *)malloc(sizeof(struct read_file))) == NULL) {
124 zip_error_set(error, ZIP_ER_MEMORY, 0);
125 return NULL;
126 }
127
128 ctx->fname = NULL;
129 if (fname) {
130 if ((ctx->fname=strdup(fname)) == NULL) {
131 zip_error_set(error, ZIP_ER_MEMORY, 0);
132 free(ctx);
133 return NULL;
134 }
135 }
136 ctx->f = file;
137 ctx->start = start;
138 ctx->end = (len < 0 ? 0 : start+(zip_uint64_t)len);
139 if (st) {
140 memcpy(&ctx->st, st, sizeof(ctx->st));
141 ctx->st.name = NULL;
142 ctx->st.valid &= ~ZIP_STAT_NAME;
143 }
144 else {
145 zip_stat_init(&ctx->st);
146 }
147
148 ctx->tmpname = NULL;
149 ctx->fout = NULL;
150
151 zip_error_init(&ctx->error);
152
153 ctx->supports = ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1);
154 if (ctx->fname) {
155 struct stat sb;
156
157 if (stat(ctx->fname, &sb) < 0 || S_ISREG(sb.st_mode)) {
158 ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE;
159 }
160 }
161 else if (fseeko(ctx->f, 0, SEEK_CUR) == 0) {
162 ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE;
163 }
164
165 if ((zs=zip_source_function_create(read_file, ctx, error)) == NULL) {
166 free(ctx->fname);
167 free(ctx);
168 return NULL;
169 }
170
171 return zs;
172 }
173
174
175 static int
176 create_temp_output(struct read_file *ctx)
177 {
178 char *temp;
179 int tfd;
180 mode_t mask;
181 FILE *tfp;
182
183 if ((temp=(char *)malloc(strlen(ctx->fname)+8)) == NULL) {
184 zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
185 return -1;
186 }
187 sprintf(temp, "%s.XXXXXX", ctx->fname);
188
189 mask = umask(_SAFE_MASK);
190 if ((tfd=mkstemp(temp)) == -1) {
191 zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
192 umask(mask);
193 free(temp);
194 return -1;
195 }
196 umask(mask);
197
198 if ((tfp=fdopen(tfd, "r+b")) == NULL) {
199 zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
200 close(tfd);
201 (void)remove(temp);
202 free(temp);
203 return -1;
204 }
205
206 #ifdef _WIN32
207
208
209
210
211 _setmode(_fileno(tfp), _O_BINARY );
212 #endif
213
214 ctx->fout = tfp;
215 ctx->tmpname = temp;
216
217 return 0;
218 }
219
220
221 static zip_int64_t
222 read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd)
223 {
224 struct read_file *ctx;
225 char *buf;
226 zip_uint64_t n;
227 size_t i;
228
229 ctx = (struct read_file *)state;
230 buf = (char *)data;
231
232 switch (cmd) {
233 case ZIP_SOURCE_BEGIN_WRITE:
234 if (ctx->fname == NULL) {
235 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
236 return -1;
237 }
238 return create_temp_output(ctx);
239
240 case ZIP_SOURCE_COMMIT_WRITE: {
241 mode_t mask;
242
243 if (fclose(ctx->fout) < 0) {
244 ctx->fout = NULL;
245 zip_error_set(&ctx->error, ZIP_ER_WRITE, errno);
246 }
247 ctx->fout = NULL;
248 if (rename(ctx->tmpname, ctx->fname) < 0) {
249 zip_error_set(&ctx->error, ZIP_ER_RENAME, errno);
250 return -1;
251 }
252 mask = umask(022);
253 umask(mask);
254
255 (void)chmod(ctx->fname, 0666&~mask);
256 free(ctx->tmpname);
257 ctx->tmpname = NULL;
258 return 0;
259 }
260
261 case ZIP_SOURCE_CLOSE:
262 if (ctx->fname) {
263 fclose(ctx->f);
264 ctx->f = NULL;
265 }
266 return 0;
267
268 case ZIP_SOURCE_ERROR:
269 return zip_error_to_data(&ctx->error, data, len);
270
271 case ZIP_SOURCE_FREE:
272 free(ctx->fname);
273 free(ctx->tmpname);
274 if (ctx->f)
275 fclose(ctx->f);
276 free(ctx);
277 return 0;
278
279 case ZIP_SOURCE_OPEN:
280 if (ctx->fname) {
281 if ((ctx->f=fopen(ctx->fname, "rb")) == NULL) {
282 zip_error_set(&ctx->error, ZIP_ER_OPEN, errno);
283 return -1;
284 }
285 }
286
287 if (ctx->start > 0) {
288 if (_zip_fseek_u(ctx->f, ctx->start, SEEK_SET, &ctx->error) < 0) {
289 return -1;
290 }
291 }
292 ctx->current = ctx->start;
293 return 0;
294
295 case ZIP_SOURCE_READ:
296 if (ctx->end > 0) {
297 n = ctx->end-ctx->current;
298 if (n > len) {
299 n = len;
300 }
301 }
302 else {
303 n = len;
304 }
305
306 if (n > SIZE_MAX)
307 n = SIZE_MAX;
308
309 if ((i=fread(buf, 1, (size_t)n, ctx->f)) == 0) {
310 if (ferror(ctx->f)) {
311 zip_error_set(&ctx->error, ZIP_ER_READ, errno);
312 return -1;
313 }
314 }
315 ctx->current += i;
316
317 return (zip_int64_t)i;
318
319 case ZIP_SOURCE_REMOVE:
320 if (remove(ctx->fname) < 0) {
321 zip_error_set(&ctx->error, ZIP_ER_REMOVE, errno);
322 return -1;
323 }
324 return 0;
325
326 case ZIP_SOURCE_ROLLBACK_WRITE:
327 if (ctx->fout) {
328 fclose(ctx->fout);
329 ctx->fout = NULL;
330 }
331 (void)remove(ctx->tmpname);
332 free(ctx->tmpname);
333 ctx->tmpname = NULL;
334 return 0;
335
336 case ZIP_SOURCE_SEEK: {
337 zip_int64_t new_current;
338 int need_seek;
339 zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);
340
341 if (args == NULL)
342 return -1;
343
344 need_seek = 1;
345
346 switch (args->whence) {
347 case SEEK_SET:
348 new_current = args->offset;
349 break;
350
351 case SEEK_END:
352 if (ctx->end == 0) {
353 if (_zip_fseek(ctx->f, args->offset, SEEK_END, &ctx->error) < 0) {
354 return -1;
355 }
356 if ((new_current = ftello(ctx->f)) < 0) {
357 zip_error_set(&ctx->error, ZIP_ER_SEEK, errno);
358 return -1;
359 }
360 need_seek = 0;
361 }
362 else {
363 new_current = (zip_int64_t)ctx->end + args->offset;
364 }
365 break;
366 case SEEK_CUR:
367 new_current = (zip_int64_t)ctx->current + args->offset;
368 break;
369
370 default:
371 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
372 return -1;
373 }
374
375 if (new_current < 0 || (zip_uint64_t)new_current < ctx->start || (ctx->end != 0 && (zip_uint64_t)new_current > ctx->end)) {
376 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
377 return -1;
378 }
379
380 ctx->current = (zip_uint64_t)new_current;
381
382 if (need_seek) {
383 if (_zip_fseek_u(ctx->f, ctx->current, SEEK_SET, &ctx->error) < 0) {
384 return -1;
385 }
386 }
387 return 0;
388 }
389
390 case ZIP_SOURCE_SEEK_WRITE: {
391 zip_source_args_seek_t *args;
392
393 args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);
394 if (args == NULL) {
395 return -1;
396 }
397
398 if (_zip_fseek(ctx->fout, args->offset, args->whence, &ctx->error) < 0) {
399 return -1;
400 }
401 return 0;
402 }
403
404 case ZIP_SOURCE_STAT: {
405 if (len < sizeof(ctx->st))
406 return -1;
407
408 if (ctx->st.valid != 0)
409 memcpy(data, &ctx->st, sizeof(ctx->st));
410 else {
411 zip_stat_t *st;
412 struct stat fst;
413 int err;
414
415 if (ctx->f)
416 err = fstat(fileno(ctx->f), &fst);
417 else
418 err = stat(ctx->fname, &fst);
419
420 if (err != 0) {
421 zip_error_set(&ctx->error, ZIP_ER_READ, errno);
422 return -1;
423 }
424
425 st = (zip_stat_t *)data;
426
427 zip_stat_init(st);
428 st->mtime = fst.st_mtime;
429 st->valid |= ZIP_STAT_MTIME;
430 if (ctx->end != 0) {
431 st->size = ctx->end - ctx->start;
432 st->valid |= ZIP_STAT_SIZE;
433 }
434 else if ((fst.st_mode&S_IFMT) == S_IFREG) {
435 st->size = (zip_uint64_t)fst.st_size;
436 st->valid |= ZIP_STAT_SIZE;
437 }
438 }
439 return sizeof(ctx->st);
440 }
441
442 case ZIP_SOURCE_SUPPORTS:
443 return ctx->supports;
444
445 case ZIP_SOURCE_TELL:
446 return (zip_int64_t)ctx->current;
447
448 case ZIP_SOURCE_TELL_WRITE:
449 {
450 off_t ret = ftello(ctx->fout);
451
452 if (ret < 0) {
453 zip_error_set(&ctx->error, ZIP_ER_TELL, errno);
454 return -1;
455 }
456 return ret;
457 }
458
459 case ZIP_SOURCE_WRITE:
460 {
461 size_t ret;
462
463 clearerr(ctx->fout);
464 ret = fwrite(data, 1, len, ctx->fout);
465 if (ret != len || ferror(ctx->fout)) {
466 zip_error_set(&ctx->error, ZIP_ER_WRITE, errno);
467 return -1;
468 }
469
470 return (zip_int64_t)ret;
471 }
472
473 default:
474 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
475 return -1;
476 }
477 }
478
479
480 static int
481 _zip_fseek_u(FILE *f, zip_uint64_t offset, int whence, zip_error_t *error)
482 {
483 if (offset > ZIP_INT64_MAX) {
484 zip_error_set(error, ZIP_ER_SEEK, EOVERFLOW);
485 return -1;
486 }
487 return _zip_fseek(f, (zip_int64_t)offset, whence, error);
488 }
489
490
491 static int
492 _zip_fseek(FILE *f, zip_int64_t offset, int whence, zip_error_t *error)
493 {
494 if (offset > ZIP_FSEEK_MAX || offset < ZIP_FSEEK_MIN) {
495 zip_error_set(error, ZIP_ER_SEEK, EOVERFLOW);
496 return -1;
497 }
498 if (fseeko(f, (off_t)offset, whence) < 0) {
499 zip_error_set(error, ZIP_ER_SEEK, errno);
500 return -1;
501 }
502 return 0;
503 }