dlgTextEntry_Keyboard: rename to TouchTextEntry
[xcsoar.git] / src / zzip / zip.c
blobafbaf7fb5fcf787557f273f84708b54d9f9ec110
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 #ifdef ZZIP_DISABLED
22 #include <errno.h>
23 #endif
24 #include <stdlib.h>
25 #include <string.h>
26 #include <fcntl.h>
27 #ifdef ZZIP_HAVE_SYS_STAT_H
28 #include <sys/stat.h>
29 #endif
31 #include <zzip/__mmap.h>
32 #include <zzip/__debug.h>
34 #define __sizeof(X) ((zzip_ssize_t)(sizeof(X)))
36 #ifndef ZZIP_EASY
37 /* per default, we use a little hack to correct bad z_rootseek parts */
38 #define ZZIP_CORRECT_ROOTSEEK 1
39 #endif
41 #if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ >= 4)
42 # ifdef DEBUG
43 # warning suppress a warning where the compiler should have optimized instead.
44 # endif
45 #define _255 254
46 #else
47 #define _255 255
48 #endif
50 #define ZZIP_DISK64_TRAILER 1
52 #ifdef ZZIP_DISK64_TRAILER
53 struct _disk_trailer
55 void *zz_tail;
56 void *zz_for_correct_rootseek; // ZZIP_CORRECT_ROOTSEEK
57 zzip_off64_t zz_entries;
58 zzip_off64_t zz_finalentries;
59 zzip_off64_t zz_rootseek;
60 zzip_off64_t zz_rootsize;
62 #define _disk_trailer_entries(__p) ((__p)->zz_entries)
63 #define _disk_trailer_localentries(__p) ((__p)->zz_entries)
64 #define _disk_trailer_finalentries(__p) ((__p)->zz_entries)
65 #define _disk_trailer_rootseek(__p) ((__p)->zz_rootseek)
66 #define _disk_trailer_rootsize(__p) ((__p)->zz_rootsize)
67 #define _disk_trailer_set_rootseek(__p,__v) ((__p)->rootseek = (__v))
69 #else
70 #define _disk_trailer zzip_disk_trailer
71 #define _disk_trailer_entries zzip_disk_trailer_entries
72 #define _disk_trailer_localentries zzip_disk_trailer_localentries
73 #define _disk_trailer_finalentries zzip_disk_trailer_finalentries
74 #define _disk_trailer_rootseek zzip_disk_trailer_rootseek
75 #define _disk_trailer_rootsize zzip_disk_trailer_rootsize
76 #define _disk_trailer_set_rootseek zzip_disk_trailer_set_rootseek
77 #define __zzip_fetch_disk_trailer __zzip_find_disk_trailer
78 #endif
80 /* --------------------------- internals -------------------------------- */
82 /* internal functions of zziplib, avoid at all cost, changes w/o warning.
83 * we do export them for debugging purpose and special external tools
84 * which know what they do and which can adapt from version to version
87 static int __zzip_fetch_disk_trailer(int fd, zzip_off_t filesize,
88 struct _disk_trailer *_zzip_restrict trailer,
89 zzip_plugin_io_t io);
90 static int __zzip_parse_root_directory(int fd,
91 struct _disk_trailer *trailer,
92 struct zzip_dir_hdr **hdr_return,
93 zzip_plugin_io_t io);
95 _zzip_inline static char *__zzip_aligned4(char *p);
97 /* ------------------------ harden routines ------------------------------ */
99 #ifdef ZZIP_HARDEN
102 * check for inconsistent values in trailer and prefer lower seek value
103 * - we fix values assuming the root directory was written at the end
104 * and it is just before the zip trailer. Therefore, ...
106 _zzip_inline static void
107 __fixup_rootseek(zzip_off_t offset_of_trailer, struct _disk_trailer *trailer)
109 if (_disk_trailer_rootseek(trailer) >
110 offset_of_trailer - _disk_trailer_rootsize(trailer) &&
111 offset_of_trailer > _disk_trailer_rootsize(trailer))
113 register zzip_off_t offset;
114 offset = offset_of_trailer - _disk_trailer_rootsize(trailer);
115 _disk_trailer_set_rootseek(trailer, offset);
116 HINT2("new rootseek=%li", (long) _disk_trailer_rootseek(trailer));
120 #define __correct_rootseek(A,B,C)
122 #elif defined ZZIP_CORRECT_ROOTSEEK
124 /* store the seekvalue of the trailer into the "z_magic" field and with
125 * a 64bit off_t we overwrite z_disk/z_finaldisk as well. If you change
126 * anything in zziplib or dump the trailer structure then watch out that
127 * these are still unused, so that this code may still (ab)use those. */
128 #define __fixup_rootseek(_offset_of_trailer, _trailer) \
129 *(zzip_off_t*)_trailer = _offset_of_trailer;
130 #define __correct_rootseek( _u_rootseek, _u_rootsize, _trailer) \
131 if (_u_rootseek > *(zzip_off_t*)_trailer - _u_rootsize) \
132 _u_rootseek = *(zzip_off_t*)_trailer - _u_rootsize;
133 #else
134 #define __fixup_rootseek(A,B)
135 #define __correct_rootseek(A,B,C)
136 #endif
139 #ifdef DEBUG
140 _zzip_inline static void
141 __debug_dir_hdr(struct zzip_dir_hdr *hdr)
143 if (sizeof(struct zzip_dir_hdr) > sizeof(struct zzip_disk_entry))
144 { WARN1("internal sizeof-mismatch may break wreakage"); }
145 /* the internal directory structure is never bigger than the
146 * external zip central directory space had been beforehand
147 * (as long as the following assertion holds...)
150 if (((zzip_off_t) hdr) & 3)
152 NOTE1("this machine's malloc(3) returns sth. not u32-aligned");
154 /* we assume that if this machine's malloc has returned a non-aligned
155 * memory block, then it is actually safe to access misaligned data, and
156 * since it does only affect the first hdr it should not even bring about
157 * too much of that cpu's speed penalty
160 #else
161 #define __debug_dir_hdr(X)
162 #endif
164 /* -------------------------- low-level interface -------------------------- */
166 #if defined BUFSIZ
167 #if BUFSIZ == 1024 || BUFSIZ == 512 || BUFSIZ == 256
168 #define ZZIP_BUFSIZ BUFSIZ
169 #endif
170 #endif
172 #ifndef ZZIP_BUFSIZ
173 #define ZZIP_BUFSIZ 2048
175 /* #define ZZIP_BUFSIZ 64 / * for testing */
176 #endif
179 * This function is used by => zzip_file_open. It tries to find
180 * the zip's central directory info that is usually a few
181 * bytes off the end of the file.
183 static int
184 __zzip_fetch_disk_trailer(int fd, zzip_off_t filesize,
185 struct _disk_trailer *_zzip_restrict trailer,
186 zzip_plugin_io_t io)
188 #ifdef DEBUG
189 #define return(val) { e=val; HINT2("%s", zzip_strerror(e)); goto cleanup; }
190 #else
191 #define return(val) { e=val; goto cleanup; }
192 #endif
193 register int e;
195 #ifndef _LOWSTK
196 auto char buffer[2 * ZZIP_BUFSIZ];
197 char *buf = buffer;
198 #else
199 char *buf = malloc(2 * ZZIP_BUFSIZ);
200 #endif
201 zzip_off_t offset = 0;
202 zzip_ssize_t maplen = 0; /* mmap(),read(),getpagesize() use size_t !! */
203 char *fd_map = 0;
205 #ifdef ZZIP_DISABLED
206 if (! trailer)
207 { return(EINVAL); }
208 #else
209 if (! trailer)
210 { return(ZZIP_OUTOFMEM); }
211 #endif
213 if (filesize < __sizeof(struct zzip_disk_trailer))
214 { return(ZZIP_DIR_TOO_SHORT); }
216 if (! buf)
217 { return(ZZIP_OUTOFMEM); }
219 offset = filesize; /* a.k.a. old offset */
220 while (1) /* outer loop */
222 register unsigned char *mapped;
224 if (offset <= 0)
225 { return(ZZIP_DIR_EDH_MISSING); }
227 /* trailer cannot be farther away than 64K from fileend */
228 if (filesize - offset > 64 * 1024)
229 { return(ZZIP_DIR_EDH_MISSING); }
231 /* the new offset shall overlap with the area after the old offset! */
232 if (USE_MMAP && io->fd.sys)
234 zzip_off_t mapoff = offset;
236 zzip_ssize_t pagesize = _zzip_getpagesize(io->fd.sys);
237 if (pagesize < ZZIP_BUFSIZ)
238 goto non_mmap; /* an error? */
239 if (mapoff == filesize && filesize > pagesize)
240 mapoff -= pagesize;
241 if (mapoff < pagesize)
243 maplen = (zzip_ssize_t) mapoff + pagesize;
244 mapoff = 0;
245 } else
247 mapoff -= pagesize;
248 maplen = 2 * pagesize;
249 if ((zzip_ssize_t) mapoff & (pagesize - 1))
250 { /*only 1. run */
251 pagesize -= (zzip_ssize_t) mapoff & (pagesize - 1);
252 mapoff += pagesize;
253 maplen -= pagesize;
256 if (mapoff + maplen > filesize)
257 maplen = filesize - mapoff;
260 fd_map = _zzip_mmap(io->fd.sys, fd, mapoff, (zzip_size_t) maplen);
261 if (fd_map == MAP_FAILED)
262 goto non_mmap;
263 mapped = (unsigned char *) fd_map;
264 offset = mapoff; /* success */
265 HINT3("mapped *%p len=%li", fd_map, (long) maplen);
266 } else
268 non_mmap:
269 fd_map = 0; /* have no mmap */
271 zzip_off_t pagesize = ZZIP_BUFSIZ;
272 if (offset == filesize && filesize > pagesize)
273 offset -= pagesize;
274 if (offset < pagesize)
276 maplen = (zzip_ssize_t) offset + pagesize;
277 offset = 0;
278 } else
280 offset -= pagesize;
281 maplen = 2 * pagesize;
282 if ((zzip_ssize_t) offset & (pagesize - 1))
283 { /*on 1st run */
284 pagesize -= (zzip_ssize_t) offset & (pagesize - 1);
285 offset += pagesize;
286 maplen -= pagesize;
289 if (offset + maplen > filesize)
290 maplen = filesize - offset;
293 if (io->fd.seeks(fd, offset, SEEK_SET) < 0)
294 { return(ZZIP_DIR_SEEK); }
295 if (io->fd.read(fd, buf, (zzip_size_t) maplen) < maplen)
296 { return(ZZIP_DIR_READ); }
297 mapped = (unsigned char *) buf; /* success */
298 HINT5("offs=$%lx len=%li filesize=%li pagesize=%i",
299 (long) offset, (long) maplen, (long) filesize, ZZIP_BUFSIZ);
302 { /* now, check for the trailer-magic, hopefully near the end of file */
303 register unsigned char *end = mapped + maplen;
304 register unsigned char *tail;
305 for (tail = end - 1; (tail >= mapped); tail--)
307 if ((*tail == 'P') && /* quick pre-check for trailer magic */
308 end - tail >= __sizeof(struct zzip_disk_trailer) - 2 &&
309 zzip_disk_trailer_check_magic(tail))
311 # ifndef ZZIP_DISK64_TRAILER
312 /* if the file-comment is not present, it happens
313 that the z_comment field often isn't either */
314 if (end - tail >= __sizeof(*trailer))
316 memcpy(trailer, tail, sizeof(*trailer));
317 } else
319 memcpy(trailer, tail, sizeof(*trailer) - 2);
320 trailer->z_comment[0] = 0;
321 trailer->z_comment[1] = 0;
323 # else
324 struct zzip_disk_trailer *orig =
325 (struct zzip_disk_trailer *) tail;
326 trailer->zz_tail = tail;
327 trailer->zz_entries = zzip_disk_trailer_localentries(orig);
328 trailer->zz_finalentries =
329 zzip_disk_trailer_finalentries(orig);
330 trailer->zz_rootseek = zzip_disk_trailer_rootseek(orig);
331 trailer->zz_rootsize = zzip_disk_trailer_rootsize(orig);
332 # endif
334 __fixup_rootseek(offset + tail - mapped, trailer);
335 { return(0); }
336 } else if ((*tail == 'P') &&
337 end - tail >=
338 __sizeof(struct zzip_disk64_trailer) - 2
339 && zzip_disk64_trailer_check_magic(tail))
341 # ifndef ZZIP_DISK64_TRAILER
342 return (ZZIP_DIR_LARGEFILE);
343 # else
344 struct zzip_disk64_trailer *orig =
345 (struct zzip_disk64_trailer *) tail;
346 trailer->zz_tail = tail;
347 trailer->zz_entries =
348 zzip_disk64_trailer_localentries(orig);
349 trailer->zz_finalentries =
350 zzip_disk64_trailer_finalentries(orig);
351 trailer->zz_rootseek = zzip_disk64_trailer_rootseek(orig);
352 trailer->zz_rootsize = zzip_disk64_trailer_rootsize(orig);
353 { return(0); }
354 # endif
359 if (USE_MMAP && fd_map)
361 HINT3("unmap *%p len=%li", fd_map, (long) maplen);
362 _zzip_munmap(io->fd.sys, fd_map, (zzip_size_t) maplen);
363 fd_map = 0;
365 } /*outer loop */
367 cleanup:
368 if (USE_MMAP && fd_map)
370 HINT3("unmap *%p len=%li", fd_map, (long) maplen);
371 _zzip_munmap(io->fd.sys, fd_map, (zzip_size_t) maplen);
373 # ifdef _LOWSTK
374 free(buf);
375 # endif
376 # undef return
377 return e;
381 * making pointer alignments to values that can be handled as structures
382 * is tricky. We assume here that an align(4) is sufficient even for
383 * 64 bit machines. Note that binary operations are not usually allowed
384 * to pointer types but we do need only the lower bits in this implementation,
385 * so we can just cast the value to a long value.
387 _zzip_inline static char *
388 __zzip_aligned4(char *p)
390 #define aligned4 __zzip_aligned4
391 p += ((size_t) p) & 1; /* warnings about truncation of a "pointer" */
392 p += ((size_t) p) & 2; /* to a "long int" may be safely ignored :) */
393 return p;
397 * This function is used by => zzip_file_open, it is usually called after
398 * => __zzip_find_disk_trailer. It will parse the zip's central directory
399 * information and create a zziplib private directory table in
400 * memory.
402 static int
403 __zzip_parse_root_directory(int fd,
404 struct _disk_trailer *trailer,
405 struct zzip_dir_hdr **hdr_return,
406 zzip_plugin_io_t io)
408 auto struct zzip_disk_entry dirent;
409 struct zzip_dir_hdr *hdr;
410 struct zzip_dir_hdr *hdr0;
411 uint16_t *p_reclen = 0;
412 zzip_off64_t entries;
413 zzip_off64_t zz_offset; /* offset from start of root directory */
414 char *fd_map = 0;
415 zzip_off64_t zz_fd_gap = 0;
416 zzip_off64_t zz_entries = _disk_trailer_localentries(trailer);
417 zzip_off64_t zz_rootsize = _disk_trailer_rootsize(trailer);
418 zzip_off64_t zz_rootseek = _disk_trailer_rootseek(trailer);
419 __correct_rootseek(zz_rootseek, zz_rootsize, trailer);
421 hdr0 = (struct zzip_dir_hdr *) malloc((unsigned int)zz_rootsize);
422 if (! hdr0)
423 return ZZIP_DIRSIZE;
424 hdr = hdr0;
425 __debug_dir_hdr(hdr);
427 if (USE_MMAP && io->fd.sys)
429 zz_fd_gap = zz_rootseek & (_zzip_getpagesize(io->fd.sys) - 1);
430 HINT4(" fd_gap=%ld, mapseek=0x%lx, maplen=%ld", (long) (zz_fd_gap),
431 (long) (zz_rootseek - zz_fd_gap),
432 (long) (zz_rootsize + zz_fd_gap));
433 fd_map =
434 _zzip_mmap(io->fd.sys, fd, zz_rootseek - zz_fd_gap,
435 zz_rootsize + zz_fd_gap);
436 /* if mmap failed we will fallback to seek/read mode */
437 if (fd_map == MAP_FAILED)
439 NOTE2("map failed: %s", strerror(errno));
440 fd_map = 0;
441 } else
443 HINT3("mapped *%p len=%li", fd_map,
444 (long) (zz_rootsize + zz_fd_gap));
448 for (entries=0, zz_offset=0; ; entries++)
450 register struct zzip_disk_entry *d;
451 uint16_t u_extras, u_comment, u_namlen;
453 # ifndef ZZIP_ALLOW_MODULO_ENTRIES
454 if (entries >= zz_entries) {
455 if (zz_offset + 256 < zz_rootsize) {
456 FAIL4("%li's entry is long before the end of directory - enable modulo_entries? (O:%li R:%li)",
457 (long) entries, (long) (zz_offset), (long) zz_rootsize);
459 break;
461 # endif
463 if (fd_map)
464 { d = (void*)(fd_map+zz_fd_gap+zz_offset); } /* fd_map+fd_gap==u_rootseek */
465 else
467 if (io->fd.seeks(fd, (long)(zz_rootseek+zz_offset), SEEK_SET) < 0)
468 return ZZIP_DIR_SEEK;
469 if (io->fd.read(fd, &dirent, sizeof(dirent)) < __sizeof(dirent))
470 return ZZIP_DIR_READ;
471 d = &dirent;
474 if ((zzip_off64_t) (zz_offset + sizeof(*d)) > zz_rootsize ||
475 (zzip_off64_t) (zz_offset + sizeof(*d)) < 0)
477 FAIL4("%li's entry stretches beyond root directory (O:%li R:%li)",
478 (long) entries, (long) (zz_offset), (long) zz_rootsize);
479 break;
482 if (! zzip_disk_entry_check_magic(d)) {
483 # ifndef ZZIP_ALLOW_MODULO_ENTRIES
484 FAIL4("%li's entry has no disk_entry magic indicator (O:%li R:%li)",
485 (long) entries, (long) (zz_offset), (long) zz_rootsize);
486 # endif
487 break;
490 # if 0 && defined DEBUG
491 zzip_debug_xbuf((unsigned char *) d, sizeof(*d) + 8);
492 # endif
494 u_extras = zzip_disk_entry_get_extras(d);
495 u_comment = zzip_disk_entry_get_comment(d);
496 u_namlen = zzip_disk_entry_get_namlen(d);
497 HINT5("offset=0x%lx, size %ld, dirent *%p, hdr %p\n",
498 (long) (zz_offset + zz_rootseek), (long) zz_rootsize, d, hdr);
500 /* writes over the read buffer, Since the structure where data is
501 copied is smaller than the data in buffer this can be done.
502 It is important that the order of setting the fields is considered
503 when filling the structure, so that some data is not trashed in
504 first structure read.
505 at the end the whole copied list of structures is copied into
506 newly allocated buffer */
507 hdr->d_crc32 = zzip_disk_entry_get_crc32(d);
508 hdr->d_csize = zzip_disk_entry_get_csize(d);
509 hdr->d_usize = zzip_disk_entry_get_usize(d);
510 hdr->d_off = zzip_disk_entry_get_offset(d);
511 hdr->d_compr = zzip_disk_entry_get_compr(d);
512 if (hdr->d_compr > _255)
513 hdr->d_compr = 255;
515 if ((zzip_off64_t) (zz_offset + sizeof(*d) + u_namlen) > zz_rootsize ||
516 (zzip_off64_t) (zz_offset + sizeof(*d) + u_namlen) < 0)
518 FAIL4("%li's name stretches beyond root directory (O:%li N:%li)",
519 (long) entries, (long) (zz_offset), (long) (u_namlen));
520 break;
523 if (fd_map)
524 { memcpy(hdr->d_name, fd_map+zz_fd_gap + zz_offset+sizeof(*d), u_namlen); }
525 else
526 { io->fd.read(fd, hdr->d_name, u_namlen); }
527 hdr->d_name[u_namlen] = '\0';
528 hdr->d_namlen = u_namlen;
530 /* update offset by the total length of this entry -> next entry */
531 zz_offset += sizeof(*d) + u_namlen + u_extras + u_comment;
533 if (zz_offset > zz_rootsize)
535 FAIL3("%li's entry stretches beyond root directory (O:%li)",
536 (long) entries, (long) (zz_offset));
537 entries ++;
538 break;
541 HINT5("file %ld { compr=%d crc32=$%x offset=%d",
542 (long) entries, hdr->d_compr, hdr->d_crc32, hdr->d_off);
543 HINT5("csize=%d usize=%d namlen=%d extras=%d",
544 hdr->d_csize, hdr->d_usize, u_namlen, u_extras);
545 HINT5("comment=%d name='%s' %s <sizeof %d> } ",
546 u_comment, hdr->d_name, "", (int) sizeof(*d));
548 p_reclen = &hdr->d_reclen;
551 register char *p = (char *) hdr;
552 register char *q = aligned4(p + sizeof(*hdr) + u_namlen + 1);
553 *p_reclen = (uint16_t) (q - p);
554 hdr = (struct zzip_dir_hdr *) q;
556 } /*for */
558 if (USE_MMAP && fd_map)
560 HINT3("unmap *%p len=%li", fd_map, (long) (zz_rootsize + zz_fd_gap));
561 _zzip_munmap(io->fd.sys, fd_map, zz_rootsize + zz_fd_gap);
564 if (p_reclen)
566 *p_reclen = 0; /* mark end of list */
568 if (hdr_return)
569 *hdr_return = hdr0;
570 } /* else zero (sane) entries */
571 # ifndef ZZIP_ALLOW_MODULO_ENTRIES
572 return (entries != zz_entries ? ZZIP_CORRUPTED : 0);
573 # else
574 return ((entries & (unsigned)0xFFFF) != zz_entries ? ZZIP_CORRUPTED : 0);
575 # endif
578 /* ------------------------- high-level interface ------------------------- */
580 #ifndef O_BINARY
581 #define O_BINARY 0
582 #endif
584 static zzip_strings_t *
585 zzip_get_default_ext(void)
587 static zzip_strings_t ext[] = {
588 /* *INDENT-OFF* */
589 ".zip", ".ZIP", /* common extension */
590 ".xcm", ".XCM", // XCSoar map files
591 "", // JMW, allow paths like fred.zip/FOO
592 # ifdef ZZIP_USE_ZIPLIKES
593 ".pk3", ".PK3", /* ID Software's Quake3 zipfiles */
594 ".jar", ".JAR", /* Java zipfiles */
595 # endif
596 /* *INDENT-ON* */
600 return ext;
604 * allocate a new ZZIP_DIR handle and do basic
605 * initializations before usage by => zzip_dir_fdopen
606 * => zzip_dir_open => zzip_file_open or through
607 * => zzip_open
608 * (ext==null flags uses { ".zip" , ".ZIP" } )
609 * (io ==null flags use of posix io defaults)
611 ZZIP_DIR *
612 zzip_dir_alloc_ext_io(zzip_strings_t * ext, const zzip_plugin_io_t io)
614 ZZIP_DIR *dir;
615 if ((dir = (ZZIP_DIR *) calloc(1, sizeof(*dir))) == NULL)
616 return 0;
618 /* dir->fileext is currently unused - so what, still initialize it */
619 dir->fileext = ext ? ext : zzip_get_default_ext();
620 dir->io = io ? io : zzip_get_default_io();
621 return dir;
624 /** => zzip_dir_alloc_ext_io
625 * this function is obsolete - it was generally used for implementation
626 * and exported to let other code build on it. It is now advised to
627 * use => zzip_dir_alloc_ext_io now on explicitly, just set that second
628 * argument to zero to achieve the same functionality as the old style.
630 ZZIP_DIR *
631 zzip_dir_alloc(zzip_strings_t * fileext)
633 return zzip_dir_alloc_ext_io(fileext, 0);
637 * will free the zzip_dir handle unless there are still
638 * zzip_files attached (that may use its cache buffer).
639 * This is the inverse of => zzip_dir_alloc , and both
640 * are helper functions used implicitly in other zzipcalls
641 * e.g. => zzip_dir_close = zzip_close
643 * returns zero on sucess
644 * returns the refcount when files are attached.
647 zzip_dir_free(ZZIP_DIR * dir)
649 if (dir->refcount)
650 return (dir->refcount); /* still open files attached */
652 if (dir->fd >= 0)
653 dir->io->fd.close(dir->fd);
654 if (dir->hdr0)
655 free(dir->hdr0);
656 if (dir->cache.fp)
657 free(dir->cache.fp);
658 if (dir->cache.buf32k)
659 free(dir->cache.buf32k);
660 if (dir->realname)
661 free(dir->realname);
662 free(dir);
663 return 0;
666 /** => zzip_dir_free
667 * It will also => free(2) the => ZZIP_DIR-handle given.
668 * the counterpart for => zzip_dir_open
669 * see also => zzip_dir_free
672 zzip_dir_close(ZZIP_DIR * dir)
674 dir->refcount &= ~0x10000000; /* explicit dir close */
675 return zzip_dir_free(dir);
679 * used by the => zzip_dir_open and zzip_opendir(2) call. Opens the
680 * zip-archive as specified with the fd which points to an
681 * already openend file. This function then search and parse
682 * the zip's central directory.
684 * NOTE: refcount is zero, so an _open/_close pair will also delete
685 * this _dirhandle
687 ZZIP_DIR *
688 zzip_dir_fdopen(int fd, zzip_error_t * errcode_p)
690 return zzip_dir_fdopen_ext_io(fd, errcode_p, 0, 0);
693 static zzip_error_t __zzip_dir_parse(ZZIP_DIR * dir); /* forward */
695 /** => zzip_dir_fdopen
696 * this function uses explicit ext and io instead of the internal
697 * defaults, setting these to zero is equivalent to => zzip_dir_fdopen
699 ZZIP_DIR *
700 zzip_dir_fdopen_ext_io(int fd, zzip_error_t * errcode_p,
701 zzip_strings_t * ext, const zzip_plugin_io_t io)
703 zzip_error_t rv;
704 ZZIP_DIR *dir;
706 if ((dir = zzip_dir_alloc_ext_io(ext, io)) == NULL)
707 { rv = ZZIP_OUTOFMEM; goto error; }
709 dir->fd = fd;
710 if ((rv = __zzip_dir_parse(dir)))
711 goto error;
713 dir->hdr = dir->hdr0;
714 dir->refcount |= 0x10000000;
716 if (errcode_p)
717 *errcode_p = rv;
718 return dir;
719 error:
720 if (dir)
721 zzip_dir_free(dir);
722 if (errcode_p)
723 *errcode_p = rv;
724 return NULL;
727 static zzip_error_t
728 __zzip_dir_parse(ZZIP_DIR * dir)
730 zzip_error_t rv;
731 zzip_off_t filesize;
732 struct _disk_trailer trailer;
733 /* if (! dir || dir->fd < 0)
734 * { rv = EINVAL; goto error; }
737 HINT2("------------------ fd=%i", (int) dir->fd);
738 if ((filesize = dir->io->fd.filesize(dir->fd)) < 0)
739 { rv = ZZIP_DIR_STAT; goto error; }
741 HINT2("------------------ filesize=%ld", (long) filesize);
742 if ((rv = __zzip_fetch_disk_trailer(dir->fd, filesize, &trailer,
743 dir->io)) != 0)
744 { goto error; }
746 HINT5("directory = { entries= %ld/%ld, size= %ld, seek= %ld } ",
747 (long) _disk_trailer_localentries(&trailer),
748 (long) _disk_trailer_finalentries(&trailer),
749 (long) _disk_trailer_rootsize(&trailer),
750 (long) _disk_trailer_rootseek(&trailer));
752 if ((rv = __zzip_parse_root_directory(dir->fd, &trailer, &dir->hdr0,
753 dir->io)) != 0)
754 { goto error; }
755 error:
756 return rv;
760 * This function will attach any of the .zip extensions then
761 * trying to open it the with => open(2). This is a helper
762 * function for => zzip_dir_open, => zzip_opendir and => zzip_open.
764 * This function returns a new system file handle or -1 on error.
765 * On error this function leaves the errno(3) of the underlying
766 * open(2) call on the last file.
769 __zzip_try_open(zzip_char_t * filename, int filemode,
770 zzip_strings_t * ext, zzip_plugin_io_t io)
772 auto char file[PATH_MAX];
773 int fd;
774 zzip_size_t len = strlen(filename);
776 if (len + 4 >= PATH_MAX)
777 { /* errno = ENAMETOOLONG; */ return -1; }
778 memcpy(file, filename, len + 1);
780 if (! io)
781 io = zzip_get_default_io();
782 if (! ext)
783 ext = zzip_get_default_ext();
785 for (; *ext; ++ext)
787 strcpy(file + len, *ext);
788 fd = (io->fd.open)(file, filemode);
789 if (fd != -1)
790 return fd;
792 return -1;
796 * Opens the zip-archive (if available).
797 * the two ext_io arguments will default to use posix io and
798 * a set of default fileext that can atleast add .zip ext itself.
800 ZZIP_DIR *
801 zzip_dir_open(zzip_char_t * filename, zzip_error_t * e)
803 return zzip_dir_open_ext_io(filename, e, 0, 0);
806 /** => zzip_dir_open
807 * this function uses explicit ext and io instead of the internal
808 * defaults. Setting these to zero is equivalent to => zzip_dir_open
809 * Note that the referenced ext_io plugin handlers structure must be
810 * static as it is not copied to the returned ZZIP_DIR structure.
812 ZZIP_DIR *
813 zzip_dir_open_ext_io(zzip_char_t * filename, zzip_error_t * e,
814 zzip_strings_t * ext, zzip_plugin_io_t io)
816 int fd;
818 if (! io)
819 io = zzip_get_default_io();
820 if (! ext)
821 ext = zzip_get_default_ext();
823 fd = (io->fd.open)(filename, O_RDONLY | O_BINARY);
824 if (fd != -1)
826 return zzip_dir_fdopen_ext_io(fd, e, ext, io);
827 } else
829 fd = __zzip_try_open(filename, O_RDONLY | O_BINARY, ext, io);
830 if (fd != -1)
832 return zzip_dir_fdopen_ext_io(fd, e, ext, io);
833 } else
835 if (e)
836 { *e = ZZIP_DIR_OPEN; }
837 return 0;
842 /** => zzip_dir_open
843 * fills the dirent-argument with the values and
844 * increments the read-pointer of the dir-argument.
846 * returns 0 if there no entry (anymore).
849 zzip_dir_read(ZZIP_DIR * dir, ZZIP_DIRENT * d)
851 if (! dir || ! dir->hdr || ! d)
852 return 0;
854 d->d_compr = dir->hdr->d_compr;
855 d->d_csize = dir->hdr->d_csize;
856 d->st_size = dir->hdr->d_usize;
857 d->d_name = dir->hdr->d_name;
859 if (! dir->hdr->d_reclen)
861 dir->hdr = 0;
862 } else
864 dir->hdr = (struct zzip_dir_hdr *)
865 ((char *) dir->hdr + dir->hdr->d_reclen);
868 return 1;
872 * Local variables:
873 * c-file-style: "stroustrup"
874 * End: