beta-0.89.2
[luatex.git] / source / libs / zziplib / zziplib-0.13.62 / zzip / zip.c
bloba4b06b471893c1e4a207cc5df100bb7aa18bb73f
2 /*
3 * Author:
4 * Guido Draheim <guidod@gmx.de>
5 * Tomi Ollila <too@iki.fi>
7 * Copyright (c) 1999,2000,2001,2002,2003 Guido Draheim
8 * All rights reserved,
9 * use under the restrictions of the
10 * Lesser GNU General Public License
11 * or alternatively the restrictions
12 * of the Mozilla Public License 1.1
15 #include <zzip/lib.h> /* archive handling */
16 #include <zzip/file.h>
17 #include <zzip/format.h>
18 #include <zzip/fetch.h>
20 #include <ctype.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <fcntl.h>
25 #ifdef ZZIP_HAVE_SYS_STAT_H
26 #include <sys/stat.h>
27 #endif
29 #include <zzip/__mmap.h>
30 #include <zzip/__debug.h>
32 #define __sizeof(X) ((zzip_ssize_t)(sizeof(X)))
34 #ifndef ZZIP_EASY
35 /* per default, we use a little hack to correct bad z_rootseek parts */
36 #define ZZIP_CORRECT_ROOTSEEK 1
37 #endif
39 #if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ >= 4)
40 # ifdef DEBUG
41 # warning suppress a warning where the compiler should have optimized instead.
42 # endif
43 #define _255 254
44 #else
45 #define _255 255
46 #endif
48 #define ZZIP_DISK64_TRAILER 1
50 #ifdef ZZIP_DISK64_TRAILER
51 struct _disk_trailer
53 void *zz_tail;
54 void *zz_for_correct_rootseek; // ZZIP_CORRECT_ROOTSEEK
55 zzip_off64_t zz_entries;
56 zzip_off64_t zz_finalentries;
57 zzip_off64_t zz_rootseek;
58 zzip_off64_t zz_rootsize;
60 #define _disk_trailer_entries(__p) ((__p)->zz_entries)
61 #define _disk_trailer_localentries(__p) ((__p)->zz_entries)
62 #define _disk_trailer_finalentries(__p) ((__p)->zz_entries)
63 #define _disk_trailer_rootseek(__p) ((__p)->zz_rootseek)
64 #define _disk_trailer_rootsize(__p) ((__p)->zz_rootsize)
65 #define _disk_trailer_set_rootseek(__p,__v) ((__p)->rootseek = (__v))
67 #else
68 #define _disk_trailer zzip_disk_trailer
69 #define _disk_trailer_entries zzip_disk_trailer_entries
70 #define _disk_trailer_localentries zzip_disk_trailer_localentries
71 #define _disk_trailer_finalentries zzip_disk_trailer_finalentries
72 #define _disk_trailer_rootseek zzip_disk_trailer_rootseek
73 #define _disk_trailer_rootsize zzip_disk_trailer_rootsize
74 #define _disk_trailer_set_rootseek zzip_disk_trailer_set_rootseek
75 #define __zzip_fetch_disk_trailer __zzip_find_disk_trailer
76 #endif
78 /* --------------------------- internals -------------------------------- */
80 /* internal functions of zziplib, avoid at all cost, changes w/o warning.
81 * we do export them for debugging purpose and special external tools
82 * which know what they do and which can adapt from version to version
85 int __zzip_fetch_disk_trailer(int fd, zzip_off_t filesize,
86 struct _disk_trailer *_zzip_restrict trailer,
87 zzip_plugin_io_t io);
88 int __zzip_parse_root_directory(int fd,
89 struct _disk_trailer *trailer,
90 struct zzip_dir_hdr **hdr_return,
91 zzip_plugin_io_t io);
93 _zzip_inline static char *__zzip_aligned4(char *p);
95 /* ------------------------ harden routines ------------------------------ */
97 #ifdef ZZIP_HARDEN
100 * check for inconsistent values in trailer and prefer lower seek value
101 * - we fix values assuming the root directory was written at the end
102 * and it is just before the zip trailer. Therefore, ...
104 _zzip_inline static void
105 __fixup_rootseek(zzip_off_t offset_of_trailer, struct _disk_trailer *trailer)
107 if (_disk_trailer_rootseek(trailer) >
108 offset_of_trailer - _disk_trailer_rootsize(trailer) &&
109 offset_of_trailer > _disk_trailer_rootsize(trailer))
111 register zzip_off_t offset;
112 offset = offset_of_trailer - _disk_trailer_rootsize(trailer);
113 _disk_trailer_set_rootseek(trailer, offset);
114 HINT2("new rootseek=%li", (long) _disk_trailer_rootseek(trailer));
118 #define __correct_rootseek(A,B,C)
120 #elif defined ZZIP_CORRECT_ROOTSEEK
122 /* store the seekvalue of the trailer into the "z_magic" field and with
123 * a 64bit off_t we overwrite z_disk/z_finaldisk as well. If you change
124 * anything in zziplib or dump the trailer structure then watch out that
125 * these are still unused, so that this code may still (ab)use those. */
126 #define __fixup_rootseek(_offset_of_trailer, _trailer) \
127 *(zzip_off_t*)_trailer = _offset_of_trailer;
128 #define __correct_rootseek( _u_rootseek, _u_rootsize, _trailer) \
129 if (_u_rootseek > *(zzip_off_t*)_trailer - _u_rootsize) \
130 _u_rootseek = *(zzip_off_t*)_trailer - _u_rootsize;
131 #else
132 #define __fixup_rootseek(A,B)
133 #define __correct_rootseek(A,B,C)
134 #endif
137 #ifdef DEBUG
138 _zzip_inline static void
139 __debug_dir_hdr(struct zzip_dir_hdr *hdr)
141 if (sizeof(struct zzip_dir_hdr) > sizeof(struct zzip_disk_entry))
142 { WARN1("internal sizeof-mismatch may break wreakage"); }
143 /* the internal directory structure is never bigger than the
144 * external zip central directory space had been beforehand
145 * (as long as the following assertion holds...)
148 if (((zzip_off_t) hdr) & 3)
150 NOTE1("this machine's malloc(3) returns sth. not u32-aligned");
152 /* we assume that if this machine's malloc has returned a non-aligned
153 * memory block, then it is actually safe to access misaligned data, and
154 * since it does only affect the first hdr it should not even bring about
155 * too much of that cpu's speed penalty
158 #else
159 #define __debug_dir_hdr(X)
160 #endif
162 /* -------------------------- low-level interface -------------------------- */
164 #if defined BUFSIZ
165 #if BUFSIZ == 1024 || BUFSIZ == 512 || BUFSIZ == 256
166 #define ZZIP_BUFSIZ BUFSIZ
167 #endif
168 #endif
170 #ifndef ZZIP_BUFSIZ
171 #define ZZIP_BUFSIZ 512
173 /* #define ZZIP_BUFSIZ 64 / * for testing */
174 #endif
177 * This function is used by => zzip_file_open. It tries to find
178 * the zip's central directory info that is usually a few
179 * bytes off the end of the file.
182 __zzip_fetch_disk_trailer(int fd, zzip_off_t filesize,
183 struct _disk_trailer *_zzip_restrict trailer,
184 zzip_plugin_io_t io)
186 #ifdef DEBUG
187 #define return(val) { e=val; HINT2("%s", zzip_strerror(e)); goto cleanup; }
188 #else
189 #define return(val) { e=val; goto cleanup; }
190 #endif
191 register int e;
193 #ifndef _LOWSTK
194 auto char buffer[2 * ZZIP_BUFSIZ];
195 char *buf = buffer;
196 #else
197 char *buf = malloc(2 * ZZIP_BUFSIZ);
198 #endif
199 zzip_off_t offset = 0;
200 zzip_ssize_t maplen = 0; /* mmap(),read(),getpagesize() use size_t !! */
201 char *fd_map = 0;
203 if (! trailer)
204 { return(EINVAL); }
206 if (filesize < __sizeof(struct zzip_disk_trailer))
207 { return(ZZIP_DIR_TOO_SHORT); }
209 if (! buf)
210 { return(ZZIP_OUTOFMEM); }
212 offset = filesize; /* a.k.a. old offset */
213 while (1) /* outer loop */
215 register unsigned char *mapped;
217 if (offset <= 0)
218 { return(ZZIP_DIR_EDH_MISSING); }
220 /* trailer cannot be farther away than 64K from fileend */
221 if (filesize - offset > 64 * 1024)
222 { return(ZZIP_DIR_EDH_MISSING); }
224 /* the new offset shall overlap with the area after the old offset! */
225 if (USE_MMAP && io->fd.sys)
227 zzip_off_t mapoff = offset;
229 zzip_ssize_t pagesize = _zzip_getpagesize(io->fd.sys);
230 if (pagesize < ZZIP_BUFSIZ)
231 goto non_mmap; /* an error? */
232 if (mapoff == filesize && filesize > pagesize)
233 mapoff -= pagesize;
234 if (mapoff < pagesize)
236 maplen = (zzip_ssize_t) mapoff + pagesize;
237 mapoff = 0;
238 } else
240 mapoff -= pagesize;
241 maplen = 2 * pagesize;
242 if ((zzip_ssize_t) mapoff & (pagesize - 1))
243 { /*only 1. run */
244 pagesize -= (zzip_ssize_t) mapoff & (pagesize - 1);
245 mapoff += pagesize;
246 maplen -= pagesize;
249 if (mapoff + maplen > filesize)
250 maplen = filesize - mapoff;
253 fd_map = _zzip_mmap(io->fd.sys, fd, mapoff, (zzip_size_t) maplen);
254 if (fd_map == MAP_FAILED)
255 goto non_mmap;
256 mapped = (unsigned char *) fd_map;
257 offset = mapoff; /* success */
258 HINT3("mapped *%p len=%li", fd_map, (long) maplen);
259 } else
261 non_mmap:
262 fd_map = 0; /* have no mmap */
264 zzip_off_t pagesize = ZZIP_BUFSIZ;
265 if (offset == filesize && filesize > pagesize)
266 offset -= pagesize;
267 if (offset < pagesize)
269 maplen = (zzip_ssize_t) offset + pagesize;
270 offset = 0;
271 } else
273 offset -= pagesize;
274 maplen = 2 * pagesize;
275 if ((zzip_ssize_t) offset & (pagesize - 1))
276 { /*on 1st run */
277 pagesize -= (zzip_ssize_t) offset & (pagesize - 1);
278 offset += pagesize;
279 maplen -= pagesize;
282 if (offset + maplen > filesize)
283 maplen = filesize - offset;
286 if (io->fd.seeks(fd, offset, SEEK_SET) < 0)
287 { return(ZZIP_DIR_SEEK); }
288 if (io->fd.read(fd, buf, (zzip_size_t) maplen) < maplen)
289 { return(ZZIP_DIR_READ); }
290 mapped = (unsigned char *) buf; /* success */
291 HINT5("offs=$%lx len=%li filesize=%li pagesize=%i",
292 (long) offset, (long) maplen, (long) filesize, ZZIP_BUFSIZ);
295 { /* now, check for the trailer-magic, hopefully near the end of file */
296 register unsigned char *end = mapped + maplen;
297 register unsigned char *tail;
298 for (tail = end - 1; (tail >= mapped); tail--)
300 if ((*tail == 'P') && /* quick pre-check for trailer magic */
301 end - tail >= __sizeof(struct zzip_disk_trailer) - 2 &&
302 zzip_disk_trailer_check_magic(tail))
304 # ifndef ZZIP_DISK64_TRAILER
305 /* if the file-comment is not present, it happens
306 that the z_comment field often isn't either */
307 if (end - tail >= __sizeof(*trailer))
309 memcpy(trailer, tail, sizeof(*trailer));
310 } else
312 memcpy(trailer, tail, sizeof(*trailer) - 2);
313 trailer->z_comment[0] = 0;
314 trailer->z_comment[1] = 0;
316 # else
317 struct zzip_disk_trailer *orig =
318 (struct zzip_disk_trailer *) tail;
319 trailer->zz_tail = tail;
320 trailer->zz_entries = zzip_disk_trailer_localentries(orig);
321 trailer->zz_finalentries =
322 zzip_disk_trailer_finalentries(orig);
323 trailer->zz_rootseek = zzip_disk_trailer_rootseek(orig);
324 trailer->zz_rootsize = zzip_disk_trailer_rootsize(orig);
325 # endif
327 __fixup_rootseek(offset + tail - mapped, trailer);
328 { return(0); }
329 } else if ((*tail == 'P') &&
330 end - tail >=
331 __sizeof(struct zzip_disk64_trailer) - 2
332 && zzip_disk64_trailer_check_magic(tail))
334 # ifndef ZZIP_DISK64_TRAILER
335 return (ZZIP_DIR_LARGEFILE);
336 # else
337 struct zzip_disk64_trailer *orig =
338 (struct zzip_disk64_trailer *) tail;
339 trailer->zz_tail = tail;
340 trailer->zz_entries =
341 zzip_disk64_trailer_localentries(orig);
342 trailer->zz_finalentries =
343 zzip_disk64_trailer_finalentries(orig);
344 trailer->zz_rootseek = zzip_disk64_trailer_rootseek(orig);
345 trailer->zz_rootsize = zzip_disk64_trailer_rootsize(orig);
346 { return(0); }
347 # endif
352 if (USE_MMAP && fd_map)
354 HINT3("unmap *%p len=%li", fd_map, (long) maplen);
355 _zzip_munmap(io->fd.sys, fd_map, (zzip_size_t) maplen);
356 fd_map = 0;
358 } /*outer loop */
360 cleanup:
361 if (USE_MMAP && fd_map)
363 HINT3("unmap *%p len=%li", fd_map, (long) maplen);
364 _zzip_munmap(io->fd.sys, fd_map, (zzip_size_t) maplen);
366 # ifdef _LOWSTK
367 free(buf);
368 # endif
369 # undef return
370 return e;
374 * making pointer alignments to values that can be handled as structures
375 * is tricky. We assume here that an align(4) is sufficient even for
376 * 64 bit machines. Note that binary operations are not usually allowed
377 * to pointer types but we can cast the value to a suitably sized integer.
379 _zzip_inline static char *
380 __zzip_aligned4(char *p)
382 #define aligned4 __zzip_aligned4
383 #ifdef _WIN64
384 p += ((__int64) p) & 1;
385 p += ((__int64) p) & 2;
386 #else
387 p += ((long) p) & 1;
388 p += ((long) p) & 2;
389 #endif
390 return p;
394 * This function is used by => zzip_file_open, it is usually called after
395 * => __zzip_find_disk_trailer. It will parse the zip's central directory
396 * information and create a zziplib private directory table in
397 * memory.
400 __zzip_parse_root_directory(int fd,
401 struct _disk_trailer *trailer,
402 struct zzip_dir_hdr **hdr_return,
403 zzip_plugin_io_t io)
405 auto struct zzip_disk_entry dirent;
406 struct zzip_dir_hdr *hdr;
407 struct zzip_dir_hdr *hdr0;
408 uint16_t *p_reclen = 0;
409 zzip_off64_t entries;
410 zzip_off64_t zz_offset; /* offset from start of root directory */
411 char *fd_map = 0;
412 zzip_off64_t zz_fd_gap = 0;
413 zzip_off64_t zz_entries = _disk_trailer_localentries(trailer);
414 zzip_off64_t zz_rootsize = _disk_trailer_rootsize(trailer);
415 zzip_off64_t zz_rootseek = _disk_trailer_rootseek(trailer);
416 __correct_rootseek(zz_rootseek, zz_rootsize, trailer);
418 hdr0 = (struct zzip_dir_hdr *) malloc(zz_rootsize);
419 if (! hdr0)
420 return ZZIP_DIRSIZE;
421 hdr = hdr0;
422 __debug_dir_hdr(hdr);
424 if (USE_MMAP && io->fd.sys)
426 zz_fd_gap = zz_rootseek & (_zzip_getpagesize(io->fd.sys) - 1);
427 HINT4(" fd_gap=%ld, mapseek=0x%lx, maplen=%ld", (long) (zz_fd_gap),
428 (long) (zz_rootseek - zz_fd_gap),
429 (long) (zz_rootsize + zz_fd_gap));
430 fd_map =
431 _zzip_mmap(io->fd.sys, fd, zz_rootseek - zz_fd_gap,
432 zz_rootsize + zz_fd_gap);
433 /* if mmap failed we will fallback to seek/read mode */
434 if (fd_map == MAP_FAILED)
436 NOTE2("map failed: %s", strerror(errno));
437 fd_map = 0;
438 } else
440 HINT3("mapped *%p len=%li", fd_map,
441 (long) (zz_rootsize + zz_fd_gap));
445 for (entries=0, zz_offset=0; ; entries++)
447 register struct zzip_disk_entry *d;
448 uint16_t u_extras, u_comment, u_namlen;
450 # ifndef ZZIP_ALLOW_MODULO_ENTRIES
451 if (entries >= zz_entries) {
452 if (zz_offset + 256 < zz_rootsize) {
453 FAIL4("%li's entry is long before the end of directory - enable modulo_entries? (O:%li R:%li)",
454 (long) entries, (long) (zz_offset), (long) zz_rootsize);
456 break;
458 # endif
460 if (fd_map)
461 { d = (void*)(fd_map+zz_fd_gap+zz_offset); } /* fd_map+fd_gap==u_rootseek */
462 else
464 if (io->fd.seeks(fd, zz_rootseek + zz_offset, SEEK_SET) < 0)
465 return ZZIP_DIR_SEEK;
466 if (io->fd.read(fd, &dirent, sizeof(dirent)) < __sizeof(dirent))
467 return ZZIP_DIR_READ;
468 d = &dirent;
471 if ((zzip_off64_t) (zz_offset + sizeof(*d)) > zz_rootsize ||
472 (zzip_off64_t) (zz_offset + sizeof(*d)) < 0)
474 FAIL4("%li's entry stretches beyond root directory (O:%li R:%li)",
475 (long) entries, (long) (zz_offset), (long) zz_rootsize);
476 break;
479 if (! zzip_disk_entry_check_magic(d)) {
480 # ifndef ZZIP_ALLOW_MODULO_ENTRIES
481 FAIL4("%li's entry has no disk_entry magic indicator (O:%li R:%li)",
482 (long) entries, (long) (zz_offset), (long) zz_rootsize);
483 # endif
484 break;
487 # if 0 && defined DEBUG
488 zzip_debug_xbuf((unsigned char *) d, sizeof(*d) + 8);
489 # endif
491 u_extras = zzip_disk_entry_get_extras(d);
492 u_comment = zzip_disk_entry_get_comment(d);
493 u_namlen = zzip_disk_entry_get_namlen(d);
494 HINT5("offset=0x%lx, size %ld, dirent *%p, hdr %p\n",
495 (long) (zz_offset + zz_rootseek), (long) zz_rootsize, d, hdr);
497 /* writes over the read buffer, Since the structure where data is
498 copied is smaller than the data in buffer this can be done.
499 It is important that the order of setting the fields is considered
500 when filling the structure, so that some data is not trashed in
501 first structure read.
502 at the end the whole copied list of structures is copied into
503 newly allocated buffer */
504 hdr->d_crc32 = zzip_disk_entry_get_crc32(d);
505 hdr->d_csize = zzip_disk_entry_get_csize(d);
506 hdr->d_usize = zzip_disk_entry_get_usize(d);
507 hdr->d_off = zzip_disk_entry_get_offset(d);
508 hdr->d_compr = zzip_disk_entry_get_compr(d);
509 if (hdr->d_compr > _255)
510 hdr->d_compr = 255;
512 if ((zzip_off64_t) (zz_offset + sizeof(*d) + u_namlen) > zz_rootsize ||
513 (zzip_off64_t) (zz_offset + sizeof(*d) + u_namlen) < 0)
515 FAIL4("%li's name stretches beyond root directory (O:%li N:%li)",
516 (long) entries, (long) (zz_offset), (long) (u_namlen));
517 break;
520 if (fd_map)
521 { memcpy(hdr->d_name, fd_map+zz_fd_gap + zz_offset+sizeof(*d), u_namlen); }
522 else
523 { io->fd.read(fd, hdr->d_name, u_namlen); }
524 hdr->d_name[u_namlen] = '\0';
525 hdr->d_namlen = u_namlen;
527 /* update offset by the total length of this entry -> next entry */
528 zz_offset += sizeof(*d) + u_namlen + u_extras + u_comment;
530 if (zz_offset > zz_rootsize)
532 FAIL3("%li's entry stretches beyond root directory (O:%li)",
533 (long) entries, (long) (zz_offset));
534 entries ++;
535 break;
538 HINT5("file %ld { compr=%d crc32=$%x offset=%d",
539 (long) entries, hdr->d_compr, hdr->d_crc32, hdr->d_off);
540 HINT5("csize=%d usize=%d namlen=%d extras=%d",
541 hdr->d_csize, hdr->d_usize, u_namlen, u_extras);
542 HINT5("comment=%d name='%s' %s <sizeof %d> } ",
543 u_comment, hdr->d_name, "", (int) sizeof(*d));
545 p_reclen = &hdr->d_reclen;
548 register char *p = (char *) hdr;
549 register char *q = aligned4(p + sizeof(*hdr) + u_namlen + 1);
550 *p_reclen = (uint16_t) (q - p);
551 hdr = (struct zzip_dir_hdr *) q;
553 } /*for */
555 if (USE_MMAP && fd_map)
557 HINT3("unmap *%p len=%li", fd_map, (long) (zz_rootsize + zz_fd_gap));
558 _zzip_munmap(io->fd.sys, fd_map, zz_rootsize + zz_fd_gap);
561 if (p_reclen)
563 *p_reclen = 0; /* mark end of list */
565 if (hdr_return)
566 *hdr_return = hdr0;
567 } /* else zero (sane) entries */
568 # ifndef ZZIP_ALLOW_MODULO_ENTRIES
569 return (entries != zz_entries ? ZZIP_CORRUPTED : 0);
570 # else
571 return ((entries & (unsigned)0xFFFF) != zz_entries ? ZZIP_CORRUPTED : 0);
572 # endif
575 /* ------------------------- high-level interface ------------------------- */
577 #ifndef O_BINARY
578 #define O_BINARY 0
579 #endif
581 static zzip_strings_t *
582 zzip_get_default_ext(void)
584 static zzip_strings_t ext[] = {
585 /* *INDENT-OFF* */
586 ".zip", ".ZIP", /* common extension */
587 # ifdef ZZIP_USE_ZIPLIKES
588 ".pk3", ".PK3", /* ID Software's Quake3 zipfiles */
589 ".jar", ".JAR", /* Java zipfiles */
590 # endif
591 /* *INDENT-ON* */
595 return ext;
599 * allocate a new ZZIP_DIR handle and do basic
600 * initializations before usage by => zzip_dir_fdopen
601 * => zzip_dir_open => zzip_file_open or through
602 * => zzip_open
603 * (ext==null flags uses { ".zip" , ".ZIP" } )
604 * (io ==null flags use of posix io defaults)
606 ZZIP_DIR *
607 zzip_dir_alloc_ext_io(zzip_strings_t * ext, const zzip_plugin_io_t io)
609 ZZIP_DIR *dir;
610 if ((dir = (ZZIP_DIR *) calloc(1, sizeof(*dir))) == NULL)
611 return 0;
613 /* dir->fileext is currently unused - so what, still initialize it */
614 dir->fileext = ext ? ext : zzip_get_default_ext();
615 dir->io = io ? io : zzip_get_default_io();
616 return dir;
619 /** => zzip_dir_alloc_ext_io
620 * this function is obsolete - it was generally used for implementation
621 * and exported to let other code build on it. It is now advised to
622 * use => zzip_dir_alloc_ext_io now on explicitly, just set that second
623 * argument to zero to achieve the same functionality as the old style.
625 ZZIP_DIR *
626 zzip_dir_alloc(zzip_strings_t * fileext)
628 return zzip_dir_alloc_ext_io(fileext, 0);
632 * will free the zzip_dir handle unless there are still
633 * zzip_files attached (that may use its cache buffer).
634 * This is the inverse of => zzip_dir_alloc , and both
635 * are helper functions used implicitly in other zzipcalls
636 * e.g. => zzip_dir_close = zzip_close
638 * returns zero on sucess
639 * returns the refcount when files are attached.
642 zzip_dir_free(ZZIP_DIR * dir)
644 if (dir->refcount)
645 return (dir->refcount); /* still open files attached */
647 if (dir->fd >= 0)
648 dir->io->fd.close(dir->fd);
649 if (dir->hdr0)
650 free(dir->hdr0);
651 if (dir->cache.fp)
652 free(dir->cache.fp);
653 if (dir->cache.buf32k)
654 free(dir->cache.buf32k);
655 if (dir->realname)
656 free(dir->realname);
657 free(dir);
658 return 0;
661 /** => zzip_dir_free
662 * It will also => free(2) the => ZZIP_DIR-handle given.
663 * the counterpart for => zzip_dir_open
664 * see also => zzip_dir_free
667 zzip_dir_close(ZZIP_DIR * dir)
669 dir->refcount &= ~0x10000000; /* explicit dir close */
670 return zzip_dir_free(dir);
674 * used by the => zzip_dir_open and zzip_opendir(2) call. Opens the
675 * zip-archive as specified with the fd which points to an
676 * already openend file. This function then search and parse
677 * the zip's central directory.
679 * NOTE: refcount is zero, so an _open/_close pair will also delete
680 * this _dirhandle
682 ZZIP_DIR *
683 zzip_dir_fdopen(int fd, zzip_error_t * errcode_p)
685 return zzip_dir_fdopen_ext_io(fd, errcode_p, 0, 0);
688 static zzip_error_t __zzip_dir_parse(ZZIP_DIR * dir); /* forward */
690 /** => zzip_dir_fdopen
691 * this function uses explicit ext and io instead of the internal
692 * defaults, setting these to zero is equivalent to => zzip_dir_fdopen
694 ZZIP_DIR *
695 zzip_dir_fdopen_ext_io(int fd, zzip_error_t * errcode_p,
696 zzip_strings_t * ext, const zzip_plugin_io_t io)
698 zzip_error_t rv;
699 ZZIP_DIR *dir;
701 if ((dir = zzip_dir_alloc_ext_io(ext, io)) == NULL)
702 { rv = ZZIP_OUTOFMEM; goto error; }
704 dir->fd = fd;
705 if ((rv = __zzip_dir_parse(dir)))
706 goto error;
708 dir->hdr = dir->hdr0;
709 dir->refcount |= 0x10000000;
711 if (errcode_p)
712 *errcode_p = rv;
713 return dir;
714 error:
715 if (dir)
716 zzip_dir_free(dir);
717 if (errcode_p)
718 *errcode_p = rv;
719 return NULL;
722 static zzip_error_t
723 __zzip_dir_parse(ZZIP_DIR * dir)
725 zzip_error_t rv;
726 zzip_off_t filesize;
727 struct _disk_trailer trailer;
728 /* if (! dir || dir->fd < 0)
729 * { rv = EINVAL; goto error; }
732 HINT2("------------------ fd=%i", (int) dir->fd);
733 if ((filesize = dir->io->fd.filesize(dir->fd)) < 0)
734 { rv = ZZIP_DIR_STAT; goto error; }
736 HINT2("------------------ filesize=%ld", (long) filesize);
737 if ((rv = __zzip_fetch_disk_trailer(dir->fd, filesize, &trailer,
738 dir->io)) != 0)
739 { goto error; }
741 HINT5("directory = { entries= %ld/%ld, size= %ld, seek= %ld } ",
742 (long) _disk_trailer_localentries(&trailer),
743 (long) _disk_trailer_finalentries(&trailer),
744 (long) _disk_trailer_rootsize(&trailer),
745 (long) _disk_trailer_rootseek(&trailer));
747 if ((rv = __zzip_parse_root_directory(dir->fd, &trailer, &dir->hdr0,
748 dir->io)) != 0)
749 { goto error; }
750 error:
751 return rv;
755 * This function will attach any of the .zip extensions then
756 * trying to open it the with => open(2). This is a helper
757 * function for => zzip_dir_open, => zzip_opendir and => zzip_open.
759 * This function returns a new system file handle or -1 on error.
760 * On error this function leaves the errno(3) of the underlying
761 * open(2) call on the last file.
764 __zzip_try_open(zzip_char_t * filename, int filemode,
765 zzip_strings_t * ext, zzip_plugin_io_t io)
767 auto char file[PATH_MAX];
768 int fd;
769 zzip_size_t len = strlen(filename);
771 if (len + 4 >= PATH_MAX)
772 { errno = ENAMETOOLONG; return -1; }
773 memcpy(file, filename, len + 1);
775 if (! io)
776 io = zzip_get_default_io();
777 if (! ext)
778 ext = zzip_get_default_ext();
780 for (; *ext; ++ext)
782 strcpy(file + len, *ext);
783 fd = (io->fd.open)(file, filemode);
784 if (fd != -1)
785 return fd;
787 return -1;
791 * Opens the zip-archive (if available).
792 * the two ext_io arguments will default to use posix io and
793 * a set of default fileext that can atleast add .zip ext itself.
795 ZZIP_DIR *
796 zzip_dir_open(zzip_char_t * filename, zzip_error_t * e)
798 return zzip_dir_open_ext_io(filename, e, 0, 0);
801 /** => zzip_dir_open
802 * this function uses explicit ext and io instead of the internal
803 * defaults. Setting these to zero is equivalent to => zzip_dir_open
804 * Note that the referenced ext_io plugin handlers structure must be
805 * static as it is not copied to the returned ZZIP_DIR structure.
807 ZZIP_DIR *
808 zzip_dir_open_ext_io(zzip_char_t * filename, zzip_error_t * e,
809 zzip_strings_t * ext, zzip_plugin_io_t io)
811 int fd;
813 if (! io)
814 io = zzip_get_default_io();
815 if (! ext)
816 ext = zzip_get_default_ext();
818 fd = (io->fd.open)(filename, O_RDONLY | O_BINARY);
819 if (fd != -1)
821 return zzip_dir_fdopen_ext_io(fd, e, ext, io);
822 } else
824 fd = __zzip_try_open(filename, O_RDONLY | O_BINARY, ext, io);
825 if (fd != -1)
827 return zzip_dir_fdopen_ext_io(fd, e, ext, io);
828 } else
830 if (e)
831 { *e = ZZIP_DIR_OPEN; }
832 return 0;
837 /** => zzip_dir_open
838 * fills the dirent-argument with the values and
839 * increments the read-pointer of the dir-argument.
841 * returns 0 if there no entry (anymore).
844 zzip_dir_read(ZZIP_DIR * dir, ZZIP_DIRENT * d)
846 if (! dir || ! dir->hdr || ! d)
847 return 0;
849 d->d_compr = dir->hdr->d_compr;
850 d->d_csize = dir->hdr->d_csize;
851 d->st_size = dir->hdr->d_usize;
852 d->d_name = dir->hdr->d_name;
854 if (! dir->hdr->d_reclen)
856 dir->hdr = 0;
857 } else
859 dir->hdr = (struct zzip_dir_hdr *)
860 ((char *) dir->hdr + dir->hdr->d_reclen);
863 return 1;
867 * Local variables:
868 * c-file-style: "stroustrup"
869 * End: