1
2 /*
3 * Author:
4 * Guido Draheim <guidod@gmx.de>
5 * Tomi Ollila <Tomi.Ollila@iki.fi>
6 *
7 * Copyright (c) Guido Draheim, use under copyleft (LGPL,MPL)
8 */
9
10 #include <zzip/lib.h> /* exported... */
11 #include <zzip/file.h>
12
13 #include <string.h>
14 #include <sys/stat.h>
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <ctype.h>
18
19 #include <zzip/format.h>
20 #include <zzip/fetch.h>
21 #include <zzip/zzip32.h>
22 #include <zzip/__debug.h>
23
24 #if 0
25 # if defined ZZIP_HAVE_IO_H
26 # include <io.h> /* tell */
27 # else
28 # define tell(fd) lseek(fd,0,SEEK_CUR)
29 # endif
30 #else
31 #define tells(fd) seeks(fd,0,SEEK_CUR)
32 #endif
33
34 /** end usage.
35 * This function is the direct call of => zzip_close(fp). It will cleanup the
36 * inflate-portion of => zlib and free the structure given.
37 *
38 * it is called quite from the error-cleanup parts
39 * of the various => _open functions.
40 *
41 * the .refcount is decreased and if zero the fp->dir is closed just as well.
42 */
43 int
zzip_file_close(ZZIP_FILE * fp)44 zzip_file_close(ZZIP_FILE * fp)
45 {
46 auto int self;
47 ZZIP_DIR *dir = fp->dir;
48
49 if (fp->method)
50 inflateEnd(&fp->d_stream); /* inflateEnd() can be called many times */
51
52 if (dir->cache.locked == NULL)
53 dir->cache.locked = &self;
54
55 if (fp->buf32k)
56 {
57 if (dir->cache.locked == &self && dir->cache.buf32k == NULL)
58 dir->cache.buf32k = fp->buf32k;
59 else
60 free(fp->buf32k);
61 }
62
63 if (dir->currentfp == fp)
64 dir->currentfp = NULL;
65
66 dir->refcount--;
67 /* ease to notice possible dangling reference errors */
68 memset(fp, 0, sizeof(*fp));
69
70 if (dir->cache.locked == &self && dir->cache.fp == NULL)
71 dir->cache.fp = fp;
72 else
73 free(fp);
74
75 if (dir->cache.locked == &self)
76 dir->cache.locked = NULL;
77
78 if (! dir->refcount)
79 return zzip_dir_close(dir);
80 else
81 return 0;
82 }
83
84
85 static int
zzip_file_saveoffset(ZZIP_FILE * fp)86 zzip_file_saveoffset(ZZIP_FILE * fp)
87 {
88 if (fp)
89 {
90 int fd = fp->dir->fd;
91 zzip_off_t off = fp->io->fd.seeks(fd, 0, SEEK_CUR);
92
93 if (off < 0)
94 return -1;
95
96 fp->offset = off;
97 }
98 return 0;
99 }
100
101
102 /* user-definition */
103 #ifndef ZZIP_BACKSLASH_DIRSEP
104 #if defined HAVE_WINDOWS_H || defined ZZIP_HAVE_WINDOWS_H || defined _WIN32
105 #define ZZIP_BACKSLASH_DIRSEP 1
106 #elif defined ZZIP_CHECK_BACKSLASH_DIRSEPARATOR
107 #define ZZIP_BACKSLASH_DIRSEP 1
108 #else
109 #define ZZIP_BACKSLASH_DIRSEP 0
110 #endif
111 #endif
112
113 static zzip_char_t*
strrchr_basename(zzip_char_t * name)114 strrchr_basename(zzip_char_t* name)
115 {
116 register zzip_char_t *n = strrchr(name, '/');
117 if (n) return n + 1;
118 return name;
119 }
120
121 static zzip_char_t*
dirsep_basename(zzip_char_t * name)122 dirsep_basename(zzip_char_t* name)
123 {
124 register zzip_char_t *n = strrchr(name, '/');
125
126 if (ZZIP_BACKSLASH_DIRSEP)
127 {
128 register zzip_char_t *m = strrchr(name, '\\');
129 if (!n || (m && n < m))
130 n = m;
131 }
132
133 if (n) return n + 1;
134 return name;
135 }
136
137 #if defined strcasecmp
138 #define dirsep_strcasecmp strcasecmp
139 #else
140 static int
dirsep_strcasecmp(zzip_char_t * s1,zzip_char_t * s2)141 dirsep_strcasecmp(zzip_char_t * s1, zzip_char_t * s2)
142 {
143 /* ASCII tolower - including mapping of backslash in normal slash */
144 static const char mapping[] = "@abcdefghijklmnopqrstuvwxyz[/]^_";
145 int c1, c2;
146
147 while (*s1 && *s2)
148 {
149 c1 = (int) (unsigned char) *s1;
150 c2 = (int) (unsigned char) *s2;
151 if ((c1 & 0xE0) == 0x40)
152 c1 = mapping[c1 & 0x1f];
153 if ((c2 & 0xE0) == 0x40)
154 c2 = mapping[c2 & 0x1f];
155 if (c1 != c2)
156 return (c1 - c2);
157 s1++;
158 s2++;
159 }
160
161 return (((int) (unsigned char) *s1) - ((int) (unsigned char) *s2));
162 }
163 #endif
164
165 static int zzip_inflate_init(ZZIP_FILE *, struct zzip_dir_hdr *);
166
167 /** start usage.
168 * This function opens an => ZZIP_FILE from an already open => ZZIP_DIR handle.
169 * Since we have a chance to reuse a cached => buf32k and => ZZIP_FILE memchunk
170 * this is the best choice to unpack multiple files.
171 *
172 * Note: the zlib supports 2..15 bit windowsize, hence we provide a 32k
173 * memchunk here... just to be safe.
174 *
175 * On error it returns null and sets errcode in the ZZIP_DIR.
176 */
177 ZZIP_FILE *
zzip_file_open(ZZIP_DIR * dir,zzip_char_t * name,int o_mode)178 zzip_file_open(ZZIP_DIR * dir, zzip_char_t * name, int o_mode)
179 {
180 auto int self;
181 zzip_error_t err = 0;
182 struct zzip_file *fp = 0;
183 struct zzip_dir_hdr *hdr = dir->hdr0;
184 int (*filename_strcmp) (zzip_char_t *, zzip_char_t *);
185 zzip_char_t* (*filename_basename)(zzip_char_t*);
186
187 filename_strcmp = (o_mode & ZZIP_CASELESS) ? dirsep_strcasecmp : strcmp;
188 filename_basename = (o_mode & ZZIP_CASELESS) ? dirsep_basename : strrchr_basename;
189
190 if (! dir)
191 return NULL;
192 if (! dir->fd || dir->fd == -1)
193 { dir->errcode = EBADF; return NULL; }
194 if (! hdr)
195 { dir->errcode = ENOENT; return NULL; }
196
197 if (o_mode & ZZIP_NOPATHS)
198 name = filename_basename(name);
199
200 while (1)
201 {
202 register zzip_char_t *hdr_name = hdr->d_name;
203
204 if (o_mode & ZZIP_NOPATHS)
205 hdr_name = filename_basename(hdr_name);
206
207 HINT4("name='%s', compr=%d, size=%d\n",
208 hdr->d_name, hdr->d_compr, hdr->d_usize);
209
210 if (! filename_strcmp(hdr_name, name))
211 {
212 switch (hdr->d_compr)
213 {
214 case 0: /* store */
215 case 8: /* inflate */
216 break;
217 default:
218 { err = ZZIP_UNSUPP_COMPR; goto error; }
219 }
220
221 if (dir->cache.locked == NULL)
222 dir->cache.locked = &self;
223
224 if (dir->cache.locked == &self && dir->cache.fp)
225 {
226 fp = dir->cache.fp;
227 dir->cache.fp = NULL;
228 /* memset(zfp, 0, sizeof *fp); cleared in zzip_file_close() */
229 } else
230 {
231 if (! (fp = (ZZIP_FILE *) calloc(1, sizeof(*fp))))
232 { err = ZZIP_OUTOFMEM; goto error; }
233 }
234
235 fp->dir = dir;
236 fp->io = dir->io;
237 dir->refcount++;
238
239 if (dir->cache.locked == &self && dir->cache.buf32k)
240 {
241 fp->buf32k = dir->cache.buf32k;
242 dir->cache.buf32k = NULL;
243 } else
244 {
245 if (! (fp->buf32k = (char *) malloc(ZZIP_32K)))
246 { err = ZZIP_OUTOFMEM; goto error; }
247 }
248
249 if (dir->cache.locked == &self)
250 dir->cache.locked = NULL;
251 /*
252 * In order to support simultaneous open files in one zip archive
253 * we'll fix the fd offset when opening new file/changing which
254 * file to read...
255 */
256
257 if (zzip_file_saveoffset(dir->currentfp) < 0)
258 { err = ZZIP_DIR_SEEK; goto error; }
259
260 fp->offset = hdr->d_off;
261 dir->currentfp = fp;
262
263 if (dir->io->fd.seeks(dir->fd, hdr->d_off, SEEK_SET) < 0)
264 { err = ZZIP_DIR_SEEK; goto error; }
265
266 {
267 /* skip local header - should test tons of other info,
268 * but trust that those are correct */
269 zzip_ssize_t dataoff;
270 struct zzip_file_header *p = (void *) fp->buf32k;
271
272 dataoff = dir->io->fd.read(dir->fd, (void *) p, sizeof(*p));
273 if (dataoff < (zzip_ssize_t) sizeof(*p))
274 { err = ZZIP_DIR_READ; goto error; }
275 if (! zzip_file_header_check_magic(p)) /* PK\3\4 */
276 { err = ZZIP_CORRUPTED; goto error; }
277
278 dataoff = zzip_file_header_sizeof_tail(p);
279
280 if (dir->io->fd.seeks(dir->fd, dataoff, SEEK_CUR) < 0)
281 { err = ZZIP_DIR_SEEK; goto error; }
282
283 fp->dataoffset = dir->io->fd.tells(dir->fd);
284 fp->usize = hdr->d_usize;
285 fp->csize = hdr->d_csize;
286 }
287
288 err = zzip_inflate_init(fp, hdr);
289 if (err)
290 goto error;
291
292 return fp;
293 } else
294 {
295 if (hdr->d_reclen == 0)
296 break;
297 hdr = (struct zzip_dir_hdr *) ((char *) hdr + hdr->d_reclen);
298 } /*filename_strcmp */
299 } /*forever */
300 dir->errcode = ZZIP_ENOENT;
301 return NULL;
302 error:
303 if (fp)
304 zzip_file_close(fp);
305 dir->errcode = err;
306 return NULL;
307 }
308
309 /** internal.
310 * call => inflateInit and setup fp's iterator variables,
311 * used by lowlevel => _open functions.
312 */
313 static int
zzip_inflate_init(ZZIP_FILE * fp,struct zzip_dir_hdr * hdr)314 zzip_inflate_init(ZZIP_FILE * fp, struct zzip_dir_hdr *hdr)
315 {
316 int err;
317
318 fp->method = hdr->d_compr;
319 fp->restlen = hdr->d_usize;
320
321 if (fp->method)
322 {
323 memset(&fp->d_stream, 0, sizeof(fp->d_stream));
324
325 err = inflateInit2(&fp->d_stream, -MAX_WBITS);
326 if (err != Z_OK)
327 goto error;
328
329 fp->crestlen = hdr->d_csize;
330 }
331 return 0;
332 error:
333 if (fp)
334 zzip_file_close(fp);
335 return err;
336 }
337
338 /** end usage.
339 * This function closes the given ZZIP_FILE handle.
340 *
341 * If the ZZIP_FILE wraps a normal stat'fd then it is just that int'fd
342 * that is being closed and the otherwise empty ZZIP_FILE gets freed.
343 */
344 int
zzip_fclose(ZZIP_FILE * fp)345 zzip_fclose(ZZIP_FILE * fp)
346 {
347 if (! fp)
348 return 0;
349 if (! fp->dir) /* stat fd */
350 { int r = fp->io->fd.close(fp->fd); free(fp); return r; }
351 else
352 return zzip_file_close(fp);
353 }
354
355 /** => zzip_fclose
356 */
357 int
zzip_close(ZZIP_FILE * fp)358 zzip_close(ZZIP_FILE * fp)
359 {
360 return zzip_fclose(fp);
361 }
362
363 /** read data.
364 * This function reads data from zip-contained file.
365 *
366 * This fuction works like => read(2) and will fill the given buffer with bytes from
367 * the opened file. It will return the number of bytes read, so if the => EOF
368 * is encountered you will be prompted with the number of bytes actually read.
369 *
370 * This is the routines that needs the => buf32k buffer, and it would have
371 * need for much more polishing but it does already work quite well.
372 *
373 * Note: the 32K buffer is rather big. The original inflate-algorithm
374 * required just that but the latest zlib would work just fine with
375 * a smaller buffer.
376 */
377 zzip_ssize_t
zzip_file_read(ZZIP_FILE * fp,void * buf,zzip_size_t len)378 zzip_file_read(ZZIP_FILE * fp, void *buf, zzip_size_t len)
379 {
380 ZZIP_DIR *dir;
381 zzip_size_t l;
382 zzip_ssize_t rv;
383
384 if (! fp || ! fp->dir)
385 return 0;
386
387 dir = fp->dir;
388 l = fp->restlen > len ? len : fp->restlen;
389 if (fp->restlen == 0)
390 return 0;
391
392 /*
393 * If this is other handle than previous, save current seek pointer
394 * and read the file position of `this' handle.
395 */
396 if (dir->currentfp != fp)
397 {
398 if (zzip_file_saveoffset(dir->currentfp) < 0
399 || fp->io->fd.seeks(dir->fd, fp->offset, SEEK_SET) < 0)
400 { dir->errcode = ZZIP_DIR_SEEK; return -1; }
401 else
402 { dir->currentfp = fp; }
403 }
404
405 /* if more methods is to be supported, change this to `switch ()' */
406 if (fp->method) /* method != 0 == 8, inflate */
407 {
408 fp->d_stream.avail_out = l;
409 fp->d_stream.next_out = (unsigned char *) buf;
410
411 do
412 {
413 int err;
414 zzip_size_t startlen;
415
416 if (fp->crestlen > 0 && fp->d_stream.avail_in == 0)
417 {
418 zzip_size_t cl = (fp->crestlen < ZZIP_32K ?
419 fp->crestlen : ZZIP_32K);
420 /* zzip_size_t cl =
421 * fp->crestlen > 128 ? 128 : fp->crestlen;
422 */
423 zzip_ssize_t i = fp->io->fd.read(dir->fd, fp->buf32k, cl);
424
425 if (i <= 0)
426 {
427 dir->errcode = ZZIP_DIR_READ;
428 /* or ZZIP_DIR_READ_EOF ? */
429 return -1;
430 }
431 fp->crestlen -= i;
432 fp->d_stream.avail_in = i;
433 fp->d_stream.next_in = (unsigned char *) fp->buf32k;
434 }
435
436 startlen = fp->d_stream.total_out;
437 err = inflate(&fp->d_stream, Z_NO_FLUSH);
438
439 if (err == Z_STREAM_END)
440 { fp->restlen = 0; }
441 else if (err == Z_OK)
442 { fp->restlen -= (fp->d_stream.total_out - startlen); }
443 else
444 { dir->errcode = err; return -1; }
445 }
446 while (fp->restlen && fp->d_stream.avail_out);
447
448 return l - fp->d_stream.avail_out;
449 } else
450 { /* method == 0 -- unstore */
451 rv = fp->io->fd.read(dir->fd, buf, l);
452 if (rv > 0)
453 { fp->restlen-= rv; }
454 else if (rv < 0)
455 { dir->errcode = ZZIP_DIR_READ; }
456 return rv;
457 }
458 }
459
460 /** read data.
461 * This function will read(2) data from a real/zipped file.
462 *
463 * This function is the replacement for => read(2) will fill the given buffer with
464 * bytes from the opened file. It will return the number of bytes read, so if the EOF
465 * is encountered you will be prompted with the number of bytes actually read.
466 *
467 * If the file-handle is wrapping a stat'able file then it will actually just
468 * perform a normal => read(2)-call, otherwise => zzip_file_read is called
469 * to decompress the data stream and any error is mapped to => errno(3).
470 */
471 zzip_ssize_t
zzip_read(ZZIP_FILE * fp,void * buf,zzip_size_t len)472 zzip_read(ZZIP_FILE * fp, void *buf, zzip_size_t len)
473 {
474 if (! fp)
475 return 0;
476 if (! fp->dir)
477 { return fp->io->fd.read(fp->fd, buf, len); } /* stat fd */
478 else
479 {
480 register zzip_ssize_t v;
481
482 v = zzip_file_read(fp, buf, len);
483 if (v == -1)
484 { errno = zzip_errno(fp->dir->errcode); }
485 return v;
486 }
487 }
488
489 static zzip_size_t
zzip_pread_fallback(ZZIP_FILE * file,void * ptr,zzip_size_t size,zzip_off_t offset)490 zzip_pread_fallback(ZZIP_FILE *file, void *ptr, zzip_size_t size,
491 zzip_off_t offset)
492 {
493 zzip_off_t new_offset = zzip_seek(file, offset, SEEK_SET);
494 if (new_offset < 0)
495 return -1;
496
497 return zzip_read(file, ptr, size);
498 }
499
500 zzip_size_t
zzip_pread(ZZIP_FILE * file,void * ptr,zzip_size_t size,zzip_off_t offset)501 zzip_pread(ZZIP_FILE *file, void *ptr, zzip_size_t size, zzip_off_t offset)
502 {
503 #ifdef ZZIP_HAVE_PREAD
504 if (file->dir == NULL) {
505 /* reading from a regular file */
506 return pread(file->fd, ptr, size, offset);
507 } else if (file->method == 0) {
508 /* uncompressed: can read directly from the ZIP file using
509 pread() */
510 offset += file->dataoffset;
511 return pread(file->dir->fd, ptr, size, offset);
512 } else {
513 #endif
514 /* compressed (or no pread() system call): fall back to
515 zzip_seek() + zzip_read() */
516 return zzip_pread_fallback(file, ptr, size, offset);
517 #ifdef ZZIP_HAVE_PREAD
518 }
519 #endif
520 }
521
522 /** => zzip_read
523 */
524 zzip_size_t
zzip_fread(void * ptr,zzip_size_t size,zzip_size_t nmemb,ZZIP_FILE * file)525 zzip_fread(void *ptr, zzip_size_t size, zzip_size_t nmemb, ZZIP_FILE * file)
526 {
527 if (! size)
528 size = 1;
529 return zzip_read(file, ptr, size * nmemb) / size;
530 }
531
532
533 #define ZZIP_WRONLY O_WRONLY
534 #define ZZIP_EXCL O_EXCL
535
536 #if defined O_SYNC
537 #define ZZIP_SYNC O_SYNC
538 #else
539 #define ZZIP_SYNC 0
540 #endif
541
542 #if defined O_NONBLOCK
543 #define ZZIP_NONBLOCK O_NONBLOCK
544 #elif defined O_NDELAY
545 #define ZZIP_NOCTTY O_NDELAY
546 #else
547 #define ZZIP_NOCTTY 0
548 #endif
549
550 /* ------------------------------------------------------------------- */
551
552 /** start usage. also: fopen(2)
553 * This function will => fopen(3) a real/zipped file.
554 *
555 * It has some magic functionality builtin - it will first try to open
556 * the given <em>filename</em> as a normal file. If it does not
557 * exist, the given path to the filename (if any) is split into
558 * its directory-part and the file-part. A ".zip" extension is
559 * then added to the directory-part to create the name of a
560 * zip-archive. That zip-archive (if it exists) is being searched
561 * for the file-part, and if found a zzip-handle is returned.
562 *
563 * Note that if the file is found in the normal fs-directory the
564 * returned structure is mostly empty and the => zzip_read call will
565 * use the libc => read(2) to obtain data. Otherwise a => zzip_file_open
566 * is performed and any error mapped to => errno(3).
567 *
568 * unlike the posix-wrapper => zzip_open the mode-argument is
569 * a string which allows for more freedom to support the extra
570 * zzip modes called ZZIP_CASEINSENSITIVE and ZZIP_IGNOREPATH.
571 * Currently, this => zzip_fopen call will convert the following
572 * characters in the mode-string into their corrsponding mode-bits:
573 * * <code> "r" : O_RDONLY : </code> read-only
574 * * <code> "b" : O_BINARY : </code> binary (win32 specific)
575 * * <code> "f" : O_NOCTTY : </code> no char device (unix)
576 * * <code> "i" : ZZIP_CASELESS : </code> inside zip file
577 * * <code> "*" : ZZIP_NOPATHS : </code> inside zip file only
578 * all other modes will be ignored for zip-contained entries
579 * but they are transferred for compatibility and portability,
580 * including these extra sugar bits:
581 * * <code> "x" : O_EXCL :</code> fail if file did exist
582 * * <code> "s" : O_SYNC :</code> synchronized access
583 * * <code> "n" : O_NONBLOCK :</code> nonblocking access
584 * * <code> "z#" : compression level :</code> for zlib
585 * * <code> "g#" : group access :</code> unix access bits
586 * * <code> "u#" : owner access :</code> unix access bits
587 * * <code> "o#" : world access :</code> unix access bits
588 * ... the access bits are in traditional unix bit format
589 * with 7 = read/write/execute, 6 = read/write, 4 = read-only.
590 *
591 * The default access mode is 0664, and the compression level
592 * is ignored since the lib can not yet write zip files, otherwise
593 * it would be the initialisation value for the zlib deflateInit
594 * where 0 = no-compression, 1 = best-speed, 9 = best-compression.
595 *
596 * This function returns a new zzip-handle (use => zzip_close to return
597 * it). On error this function will return null setting => errno(3).
598 */
599 ZZIP_FILE *
zzip_fopen(zzip_char_t * filename,zzip_char_t * mode)600 zzip_fopen(zzip_char_t * filename, zzip_char_t * mode)
601 {
602 return zzip_freopen(filename, mode, 0);
603 }
604
605 /** => zzip_fopen
606 *
607 * This function receives an additional argument pointing to
608 * a ZZIP_FILE* being already in use. If this extra argument is
609 * null then this function is identical with calling => zzip_fopen
610 *
611 * Per default, the old file stream is closed and only the internal
612 * structures associated with it are kept. These internal structures
613 * may be reused for the return value, and this is a lot quicker when
614 * the filename matches a zipped file that is incidentally in the very
615 * same zip arch as the old filename wrapped in the stream struct.
616 *
617 * That's simply because the zip arch's central directory does not
618 * need to be read again. As an extension for this function, if the
619 * mode-string contains a "q" then the old stream is not closed but
620 * left untouched, instead it is only given as a hint that a new
621 * file handle may share/copy the zip arch structures of the old file
622 * handle if that is possible, i.e when they are in the same zip arch.
623 *
624 * This function returns a new zzip-handle (use => zzip_close to return
625 * it). On error this function will return null setting => errno(3).
626 */
627 ZZIP_FILE *
zzip_freopen(zzip_char_t * filename,zzip_char_t * mode,ZZIP_FILE * stream)628 zzip_freopen(zzip_char_t * filename, zzip_char_t * mode, ZZIP_FILE * stream)
629 {
630 int o_flags = 0;
631 int o_modes = 0664;
632
633 if (! mode)
634 mode = "rb";
635
636 # ifndef O_BINARY
637 # define O_BINARY 0
638 # endif
639 # ifndef O_NOCTTY
640 # define O_NOCTTY 0
641 # endif
642 # ifndef O_SYNC
643 # define O_SYNC 0
644 # endif
645 # ifndef O_NONBLOCK
646 # define O_NONBLOCK 0
647 # endif
648
649 for (; *mode; mode++)
650 {
651 switch (*mode)
652 {
653 /* *INDENT-OFF* */
654 case '0': case '1': case '2': case '3': case '4':
655 case '5': case '6': case '7': case '8': case '9':
656 continue; /* ignore if not attached to other info */
657 case 'r': o_flags |= mode[1] == '+' ? O_RDWR : O_RDONLY; break;
658 case 'w': o_flags |= mode[1] == '+' ? O_RDWR : O_WRONLY;
659 o_flags |= O_TRUNC; break;
660 case 'b': o_flags |= O_BINARY; break;
661 case 'f': o_flags |= O_NOCTTY; break;
662 case 'i': o_modes |= ZZIP_CASELESS; break;
663 case '*': o_modes |= ZZIP_NOPATHS; break;
664 case 'x': o_flags |= O_EXCL; break;
665 case 's': o_flags |= O_SYNC; break;
666 case 'n': o_flags |= O_NONBLOCK; break;
667 case 'o': o_modes &=~ 07;
668 o_modes |= ((mode[1] - '0')) & 07; continue;
669 case 'g': o_modes &=~ 070;
670 o_modes |= ((mode[1] - '0') << 3) & 070; continue;
671 case 'u': o_modes &=~ 0700;
672 o_modes |= ((mode[1] - '0') << 6) & 0700; continue;
673 case 'q': o_modes |= ZZIP_FACTORY; break;
674 case 'z': /* compression level */
675 continue; /* currently ignored, just for write mode */
676 /* *INDENT-ON* */
677 }
678 }
679
680 {
681 ZZIP_FILE *fp =
682 zzip_open_shared_io(stream, filename, o_flags, o_modes, 0, 0);
683
684 if (! (o_modes & ZZIP_FACTORY) && stream)
685 zzip_file_close(stream);
686
687 return fp;
688 }
689 }
690
691 /** start usage.
692 * This function will => open(2) a real/zipped file
693 *
694 * It has some magic functionality builtin - it will first try to open
695 * the given <em>filename</em> as a normal file. If it does not
696 * exist, the given path to the filename (if any) is split into
697 * its directory-part and the file-part. A ".zip" extension is
698 * then added to the directory-part to create the name of a
699 * zip-archive. That zip-archive (if it exists) is being searched
700 * for the file-part, and if found a zzip-handle is returned.
701 *
702 * Note that if the file is found in the normal fs-directory the
703 * returned structure is mostly empty and the => zzip_read call will
704 * use the libc => read(2) to obtain data. Otherwise a => zzip_file_open
705 * is performed and any error mapped to => errno(3).
706 *
707 * There was a possibility to transfer zziplib-specific openmodes
708 * through o_flags but you should please not use them anymore and
709 * look into => zzip_open_ext_io to submit them down. This function
710 * is shallow in that it just extracts the zzipflags and calls
711 * * <code>zzip_open_ext_io(filename, o_flags, zzipflags|0664, 0, 0) </code>
712 * you must stop using this extra functionality (not well known anyway)
713 * since zzip_open might be later usable to open files for writing
714 * in which case the _EXTRAFLAGS will get in conflict.
715 *
716 * compare with => open(2) and => zzip_fopen
717 */
718 ZZIP_FILE *
zzip_open(zzip_char_t * filename,int o_flags)719 zzip_open(zzip_char_t * filename, int o_flags)
720 {
721 /* backward compatibility */
722 int o_modes = 0664;
723
724 if (o_flags & ZZIP_CASEINSENSITIVE)
725 { o_flags ^= ZZIP_CASEINSENSITIVE; o_modes |= ZZIP_CASELESS; }
726 if (o_flags & ZZIP_IGNOREPATH)
727 { o_flags ^= ZZIP_IGNOREPATH; o_modes |= ZZIP_NOPATHS; }
728 return zzip_open_ext_io(filename, o_flags, o_modes, 0, 0);
729 }
730
731 /* ZZIP_ONLYZIP won't work on platforms with sizeof(int) == 16bit */
732 #if ZZIP_SIZEOF_INT+0 == 2
733 #undef ZZIP_ONLYZIP
734 #endif
735
736 /** => zzip_open
737 *
738 * This function uses explicit ext and io instead of the internal
739 * defaults, setting them to zero is equivalent to => zzip_open
740 *
741 * note that the two flag types have been split into an o_flags
742 * (for fcntl-like openflags) and o_modes where the latter shall
743 * carry the zzip_flags and possibly accessmodes for unix filesystems.
744 * Since this version of zziplib can not write zipfiles, it is not
745 * yet used for anything else than zzip-specific modeflags.
746 *
747 * This function returns a new zzip-handle (use => zzip_close to return
748 * it). On error this function will return null setting => errno(3).
749 *
750 * If any ext_io handlers were used then the referenced structure
751 * should be static as the allocated ZZIP_FILE does not copy them.
752 */
753 ZZIP_FILE *
zzip_open_ext_io(zzip_char_t * filename,int o_flags,int o_modes,zzip_strings_t * ext,zzip_plugin_io_t io)754 zzip_open_ext_io(zzip_char_t * filename, int o_flags, int o_modes,
755 zzip_strings_t * ext, zzip_plugin_io_t io)
756 {
757 return zzip_open_shared_io(0, filename, o_flags, o_modes, ext, io);
758 }
759
760 /** => zzip_open
761 *
762 * This function takes an extra stream argument - if a handle has been
763 * then ext/io can be left null and the new stream handle will pick up
764 * the ext/io. This should be used only in specific environment however
765 * since => zzip_file_real does not store any ext-sequence.
766 *
767 * The benefit for this function comes in when the old file handle
768 * was openened from a file within a zip archive. When the new file
769 * is in the same zip archive then the internal zzip_dir structures
770 * will be shared. It is even quicker, as no check needs to be done
771 * anymore trying to guess the zip archive place in the filesystem,
772 * here we just check whether the zip archive's filepath is a prefix
773 * part of the filename to be opened.
774 *
775 * Note that this function is also used by => zzip_freopen that
776 * will unshare the old handle, thereby possibly closing the handle.
777 *
778 * This function returns a new zzip-handle (use => zzip_close to return
779 * it). On error this function will return null setting => errno(3).
780 */
781 ZZIP_FILE *
zzip_open_shared_io(ZZIP_FILE * stream,zzip_char_t * filename,int o_flags,int o_modes,zzip_strings_t * ext,zzip_plugin_io_t io)782 zzip_open_shared_io(ZZIP_FILE * stream,
783 zzip_char_t * filename, int o_flags, int o_modes,
784 zzip_strings_t * ext, zzip_plugin_io_t io)
785 {
786 if (stream && stream->dir)
787 {
788 if (! ext)
789 ext = stream->dir->fileext;
790 if (! io)
791 io = stream->dir->io;
792 }
793 if (! io)
794 io = zzip_get_default_io();
795
796 if (o_modes & (ZZIP_PREFERZIP | ZZIP_ONLYZIP))
797 goto try_zzip;
798 try_real:
799 /* prefer an existing real file */
800 {
801 zzip_plugin_io_t os = (o_modes & ZZIP_ALLOWREAL)
802 ? zzip_get_default_io() : io;
803 int fd = (os->fd.open)(filename, o_flags); /* io->fd.open */
804
805 if (fd != -1)
806 {
807 ZZIP_FILE *fp = calloc(1, sizeof(ZZIP_FILE));
808
809 if (! fp)
810 { os->fd.close(fd); return 0; } /* io->fd.close */
811
812 fp->fd = fd;
813 fp->io = os;
814 return fp;
815 }
816 if (o_modes & ZZIP_PREFERZIP)
817 return 0;
818 }
819 try_zzip:
820
821 /* if the user had it in place of a normal xopen, then
822 * we better defend this lib against illegal usage */
823 if (o_flags & (O_CREAT | O_WRONLY))
824 { errno = EINVAL; return 0; }
825 if (o_flags & (O_RDWR))
826 { o_flags ^= O_RDWR; o_flags |= O_RDONLY; }
827
828 /* this is just for backward compatibility -and strictly needed to
829 * prepare ourselves for more options and more options later on... */
830 /*# if (o_modes & ZZIP_CASELESS) { o_flags |= ZZIP_CASEINSENSITIVE; } */
831 /*# if (o_modes & ZZIP_NOPATHS) { o_flags |= ZZIP_IGNOREPATH; } */
832
833 /* see if we can open a file that is a zip file */
834 {
835 char basename[PATH_MAX];
836 char *p;
837 int filename_len = strlen(filename);
838
839 if (filename_len >= PATH_MAX)
840 { errno = ENAMETOOLONG; return 0; }
841 memcpy(basename, filename, filename_len + 1);
842
843 /* see if we can share the same zip directory */
844 if (stream && stream->dir && stream->dir->realname)
845 {
846 zzip_size_t len = strlen(stream->dir->realname);
847
848 if (! memcmp(filename, stream->dir->realname, len) &&
849 filename[len] == '/' && filename[len + 1])
850 {
851 ZZIP_FILE *fp =
852 zzip_file_open(stream->dir, filename + len + 1, o_modes);
853 if (! fp)
854 { errno = zzip_errno (stream->dir->errcode); }
855 return fp;
856 }
857 }
858
859 /* per each slash in filename, check if it there is a zzip around */
860 while ((p = strrchr(basename, '/')))
861 {
862 zzip_error_t e = 0;
863 ZZIP_DIR *dir;
864 ZZIP_FILE *fp;
865 int fd;
866
867 *p = '\0';
868 /* i.e. cut at path separator == possible zipfile basename */
869 fd = __zzip_try_open(basename, o_flags | O_RDONLY | O_BINARY,
870 ext, io);
871 if (fd == -1)
872 { continue; }
873
874 /* found zip-file .... now try to parse it */
875 dir = zzip_dir_fdopen_ext_io(fd, &e, ext, io);
876 if (e)
877 { errno = zzip_errno(e); io->fd.close(fd); return 0; }
878
879 /* (p - basename) is the lenghtof zzip_dir part of the filename */
880 fp = zzip_file_open(dir, filename + (p - basename) + 1, o_modes);
881 if (! fp)
882 { errno = zzip_errno(dir->errcode); }
883 else
884 { if (! dir->realname) dir->realname = strdup (basename); }
885
886 zzip_dir_close(dir);
887 /* note: since (fp) is attached that (dir) will survive */
888 /* but (dir) is implicitly closed on next zzip_close(fp) */
889
890 return fp;
891 }
892
893 if (o_modes & ZZIP_PREFERZIP)
894 goto try_real;
895 else
896 { errno = ENOENT; return 0; }
897 }
898 }
899
900 #if defined ZZIP_LARGEFILE_RENAME && defined EOVERFLOW && defined PIC
901
902 /* DLL compatibility layer - so that 32bit code can link with this lib too */
903
904 #undef zzip_open_shared_io /* zzip_open_shared_io64 */
905 #undef zzip_open_ext_io /* zzip_open_ext_io64 */
906 #undef zzip_opendir_ext_io /* zzip_opendir_ext_io64 */
907
908 ZZIP_FILE *zzip_open_shared_io(ZZIP_FILE * stream,
909 zzip_char_t * name, int o_flags,
910 int o_modes, zzip_strings_t * ext,
911 zzip_plugin_io_t io);
912 ZZIP_FILE *zzip_open_ext_io(zzip_char_t * name, int o_flags,
913 int o_modes, zzip_strings_t * ext,
914 zzip_plugin_io_t io);
915 ZZIP_DIR *zzip_opendir_ext_io(zzip_char_t * name, int o_modes,
916 zzip_strings_t * ext, zzip_plugin_io_t io);
917
918 ZZIP_FILE *
zzip_open_shared_io(ZZIP_FILE * stream,zzip_char_t * name,int o_flags,int o_modes,zzip_strings_t * ext,zzip_plugin_io_t io)919 zzip_open_shared_io(ZZIP_FILE * stream,
920 zzip_char_t * name, int o_flags,
921 int o_modes, zzip_strings_t * ext, zzip_plugin_io_t io)
922 {
923 if (! io)
924 return zzip_open_shared_io64(stream, name, o_flags, o_modes, ext, io);
925 errno = EOVERFLOW;
926 return NULL;
927 }
928
929 ZZIP_FILE *
zzip_open_ext_io(zzip_char_t * name,int o_flags,int o_modes,zzip_strings_t * ext,zzip_plugin_io_t io)930 zzip_open_ext_io(zzip_char_t * name, int o_flags, int o_modes,
931 zzip_strings_t * ext, zzip_plugin_io_t io)
932 {
933 if (! io)
934 return zzip_open_ext_io64(name, o_flags, o_modes, ext, io);
935 errno = EOVERFLOW;
936 return NULL;
937 }
938
939 ZZIP_DIR *
zzip_opendir_ext_io(zzip_char_t * name,int o_modes,zzip_strings_t * ext,zzip_plugin_io_t io)940 zzip_opendir_ext_io(zzip_char_t * name, int o_modes,
941 zzip_strings_t * ext, zzip_plugin_io_t io)
942 {
943 if (! io)
944 return zzip_opendir_ext_io64(name, o_modes, ext, io);
945 else
946 { errno = EOVERFLOW; return NULL; }
947 }
948
949 #endif /* ZZIP_LARGEFILE_RENAME && EOVERFLOW && PIC */
950
951 /* ------------------------------------------------------------------- */
952
953 /** rewind.
954 *
955 * This function will rewind a real/zipped file.
956 *
957 * It seeks to the beginning of this file's data in the zip,
958 * or the beginning of the file for a stat'fd.
959 */
960 int
zzip_rewind(ZZIP_FILE * fp)961 zzip_rewind(ZZIP_FILE * fp)
962 {
963 ZZIP_DIR *dir;
964 int err;
965
966 if (! fp)
967 return -1;
968
969 if (! fp->dir)
970 { /* stat fd */
971 fp->io->fd.seeks(fp->fd, 0, SEEK_SET);
972 return 0;
973 }
974
975 dir = fp->dir;
976 /*
977 * If this is other handle than previous, save current seek pointer
978 */
979 if (dir->currentfp != fp)
980 {
981 if (zzip_file_saveoffset(dir->currentfp) < 0)
982 { dir->errcode = ZZIP_DIR_SEEK; return -1; }
983 else
984 { dir->currentfp = fp; }
985 }
986
987 /* seek to beginning of this file */
988 if (fp->io->fd.seeks(dir->fd, fp->dataoffset, SEEK_SET) < 0)
989 return -1;
990
991 /* reset the inflate init stuff */
992 fp->restlen = fp->usize;
993 fp->offset = fp->dataoffset;
994
995 if (fp->method)
996 { /* method == 8, deflate */
997 err = inflateReset(&fp->d_stream);
998 if (err != Z_OK)
999 goto error;
1000
1001 /* start over at next inflate with a fresh read() */
1002 fp->d_stream.avail_in = 0;
1003 fp->crestlen = fp->csize;
1004 }
1005
1006 return 0;
1007
1008 error:
1009 if (fp)
1010 zzip_file_close(fp);
1011 return err;
1012 }
1013
1014 /** seek.
1015 *
1016 * This function will perform a => lseek(2) operation on a real/zipped file
1017 *
1018 * It will try to seek to the offset specified by offset, relative to whence,
1019 * which is one of SEEK_SET, SEEK_CUR or SEEK_END.
1020 *
1021 * If the file-handle is wrapping a stat'able file then it will actually just
1022 * perform a normal => lseek(2)-call. Otherwise the relative offset
1023 * is calculated, negative offsets are transformed into positive ones
1024 * by rewinding the file, and then data is read until the offset is
1025 * reached. This can make the function terribly slow, but this is
1026 * how gzio implements it, so I'm not sure there is a better way
1027 * without using the internals of the algorithm.
1028 */
1029 zzip_off_t
zzip_seek(ZZIP_FILE * fp,zzip_off_t offset,int whence)1030 zzip_seek(ZZIP_FILE * fp, zzip_off_t offset, int whence)
1031 {
1032 zzip_off_t cur_pos, rel_ofs, read_size, ofs;
1033 ZZIP_DIR *dir;
1034
1035 if (! fp)
1036 return -1;
1037
1038 if (! fp->dir)
1039 { /* stat fd */
1040 return fp->io->fd.seeks(fp->fd, offset, whence);
1041 }
1042
1043 cur_pos = zzip_tell(fp);
1044
1045 /* calculate relative offset */
1046 switch (whence)
1047 {
1048 case SEEK_SET: /* from beginning */
1049 rel_ofs = offset - cur_pos;
1050 break;
1051 case SEEK_CUR: /* from current */
1052 rel_ofs = offset;
1053 break;
1054 case SEEK_END: /* from end */
1055 rel_ofs = fp->usize + offset - cur_pos;
1056 break;
1057 default: /* something wrong */
1058 return -1;
1059 }
1060
1061 if (rel_ofs == 0)
1062 return cur_pos; /* don't have to move */
1063
1064 if (rel_ofs < 0)
1065 { /* convert backward into forward */
1066 if (zzip_rewind(fp) == -1)
1067 return -1;
1068
1069 read_size = cur_pos + rel_ofs;
1070 cur_pos = 0;
1071 } else
1072 { /* amount to read is positive relative offset */
1073 read_size = rel_ofs;
1074 }
1075
1076 if (read_size < 0) /* bad offset, before beginning of file */
1077 return -1;
1078
1079 if (read_size + cur_pos > (zzip_off_t) fp->usize) /* bad offset, past EOF */
1080 return -1;
1081
1082 if (read_size == 0) /* nothing to read */
1083 return cur_pos;
1084
1085 dir = fp->dir;
1086 /*
1087 * If this is other handle than previous, save current seek pointer
1088 * and read the file position of `this' handle.
1089 */
1090 if (dir->currentfp != fp)
1091 {
1092 if (zzip_file_saveoffset(dir->currentfp) < 0
1093 || fp->io->fd.seeks(dir->fd, fp->offset, SEEK_SET) < 0)
1094 { dir->errcode = ZZIP_DIR_SEEK; return -1; }
1095 else
1096 { dir->currentfp = fp; }
1097 }
1098
1099 if (fp->method == 0)
1100 { /* unstore, just lseek relatively */
1101 ofs = fp->io->fd.tells(dir->fd);
1102 ofs = fp->io->fd.seeks(dir->fd, read_size, SEEK_CUR);
1103 if (ofs > 0)
1104 { /* readjust from beginning of file */
1105 ofs -= fp->dataoffset;
1106 fp->restlen = fp->usize - ofs;
1107 }
1108 return ofs;
1109 } else
1110 { /* method == 8, inflate */
1111 char *buf;
1112
1113 /*FIXME: use a static buffer! */
1114 buf = (char *) malloc(ZZIP_32K);
1115 if (! buf)
1116 return -1;
1117
1118 while (read_size > 0)
1119 {
1120 zzip_off_t size = ZZIP_32K;
1121
1122 if (read_size < size /*32K */ )
1123 size = read_size;
1124
1125 size = zzip_file_read(fp, buf, (zzip_size_t) size);
1126 if (size <= 0)
1127 { free(buf); return -1; }
1128
1129 read_size -= size;
1130 }
1131
1132 free(buf);
1133 }
1134
1135 return zzip_tell(fp);
1136 }
1137
1138 /** tell.
1139 *
1140 * This function will => tell(2) the current position in a real/zipped file
1141 *
1142 * It will return the current offset within the real/zipped file,
1143 * measured in uncompressed bytes for the zipped-file case.
1144 *
1145 * If the file-handle is wrapping a stat'able file then it will actually just
1146 * perform a normal => tell(2)-call, otherwise the offset is
1147 * calculated from the amount of data left and the total uncompressed
1148 * size;
1149 */
1150 zzip_off_t
zzip_tell(ZZIP_FILE * fp)1151 zzip_tell(ZZIP_FILE * fp)
1152 {
1153 if (! fp)
1154 return -1;
1155
1156 if (! fp->dir) /* stat fd */
1157 return fp->io->fd.tells(fp->fd);
1158
1159 /* current uncompressed offset is uncompressed size - data left */
1160 return (fp->usize - fp->restlen);
1161 }
1162
1163 #ifndef EOVERFLOW
1164 #define EOVERFLOW EFBIG
1165 #endif
1166
1167 /** => zzip_tell
1168 * This function is provided for users who can not use any largefile-mode.
1169 */
1170 long
zzip_tell32(ZZIP_FILE * fp)1171 zzip_tell32(ZZIP_FILE * fp)
1172 {
1173 if (sizeof(zzip_off_t) == sizeof(long))
1174 {
1175 return zzip_tell(fp);
1176 } else
1177 {
1178 off_t off = zzip_tell(fp);
1179 if (off >= 0) {
1180 register long off32 = off;
1181 if (off32 == off) return off32;
1182 errno = EOVERFLOW;
1183 }
1184 return -1;
1185 }
1186 }
1187
1188 /** => zzip_seek
1189 * This function is provided for users who can not use any largefile-mode.
1190 */
1191 long
zzip_seek32(ZZIP_FILE * fp,long offset,int whence)1192 zzip_seek32(ZZIP_FILE * fp, long offset, int whence)
1193 {
1194 if (sizeof(zzip_off_t) == sizeof(long))
1195 {
1196 return zzip_seek(fp, offset, whence);
1197 } else
1198 {
1199 off_t off = zzip_seek(fp, offset, whence);
1200 if (off >= 0) {
1201 register long off32 = off;
1202 if (off32 == off) return off32;
1203 errno = EOVERFLOW;
1204 }
1205 return -1;
1206 }
1207 }
1208
1209 /*
1210 * Local variables:
1211 * c-file-style: "stroustrup"
1212 * End:
1213 */
1214