4 * Guido Draheim <guidod@gmx.de>
5 * Tomi Ollila <too@iki.fi>
7 * Copyright (c) 1999,2000,2001,2002,2003 Guido Draheim
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>
25 #ifdef ZZIP_HAVE_SYS_STAT_H
29 #include <zzip/__mmap.h>
30 #include <zzip/__debug.h>
32 #define __sizeof(X) ((zzip_ssize_t)(sizeof(X)))
35 /* per default, we use a little hack to correct bad z_rootseek parts */
36 #define ZZIP_CORRECT_ROOTSEEK 1
39 #if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ >= 4)
41 # warning suppress a warning where the compiler should have optimized instead.
48 #define ZZIP_DISK64_TRAILER 1
50 #ifdef ZZIP_DISK64_TRAILER
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))
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
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
,
88 int __zzip_parse_root_directory(int fd
,
89 struct _disk_trailer
*trailer
,
90 struct zzip_dir_hdr
**hdr_return
,
93 _zzip_inline
static char *__zzip_aligned4(char *p
);
95 /* ------------------------ harden routines ------------------------------ */
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;
132 #define __fixup_rootseek(A,B)
133 #define __correct_rootseek(A,B,C)
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
159 #define __debug_dir_hdr(X)
162 /* -------------------------- low-level interface -------------------------- */
165 #if BUFSIZ == 1024 || BUFSIZ == 512 || BUFSIZ == 256
166 #define ZZIP_BUFSIZ BUFSIZ
171 #define ZZIP_BUFSIZ 512
173 /* #define ZZIP_BUFSIZ 64 / * for testing */
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
,
187 #define return(val) { e=val; HINT2("%s", zzip_strerror(e)); goto cleanup; }
189 #define return(val) { e=val; goto cleanup; }
194 auto char buffer
[2 * ZZIP_BUFSIZ
];
197 char *buf
= malloc(2 * ZZIP_BUFSIZ
);
199 zzip_off_t offset
= 0;
200 zzip_ssize_t maplen
= 0; /* mmap(),read(),getpagesize() use size_t !! */
206 if (filesize
< __sizeof(struct zzip_disk_trailer
))
207 { return(ZZIP_DIR_TOO_SHORT
); }
210 { return(ZZIP_OUTOFMEM
); }
212 offset
= filesize
; /* a.k.a. old offset */
213 while (1) /* outer loop */
215 register unsigned char *mapped
;
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
)
234 if (mapoff
< pagesize
)
236 maplen
= (zzip_ssize_t
) mapoff
+ pagesize
;
241 maplen
= 2 * pagesize
;
242 if ((zzip_ssize_t
) mapoff
& (pagesize
- 1))
244 pagesize
-= (zzip_ssize_t
) mapoff
& (pagesize
- 1);
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
)
256 mapped
= (unsigned char *) fd_map
;
257 offset
= mapoff
; /* success */
258 HINT3("mapped *%p len=%li", fd_map
, (long) maplen
);
262 fd_map
= 0; /* have no mmap */
264 zzip_off_t pagesize
= ZZIP_BUFSIZ
;
265 if (offset
== filesize
&& filesize
> pagesize
)
267 if (offset
< pagesize
)
269 maplen
= (zzip_ssize_t
) offset
+ pagesize
;
274 maplen
= 2 * pagesize
;
275 if ((zzip_ssize_t
) offset
& (pagesize
- 1))
277 pagesize
-= (zzip_ssize_t
) offset
& (pagesize
- 1);
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
));
312 memcpy(trailer
, tail
, sizeof(*trailer
) - 2);
313 trailer
->z_comment
[0] = 0;
314 trailer
->z_comment
[1] = 0;
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
);
327 __fixup_rootseek(offset
+ tail
- mapped
, trailer
);
329 } else if ((*tail
== 'P') &&
331 __sizeof(struct zzip_disk64_trailer
) - 2
332 && zzip_disk64_trailer_check_magic(tail
))
334 # ifndef ZZIP_DISK64_TRAILER
335 return (ZZIP_DIR_LARGEFILE
);
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
);
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
);
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
);
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
384 p
+= ((__int64
) p
) & 1;
385 p
+= ((__int64
) p
) & 2;
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
400 __zzip_parse_root_directory(int fd
,
401 struct _disk_trailer
*trailer
,
402 struct zzip_dir_hdr
**hdr_return
,
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 */
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
);
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
));
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
));
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
);
461 { d
= (void*)(fd_map
+zz_fd_gap
+zz_offset
); } /* fd_map+fd_gap==u_rootseek */
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
;
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
);
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
);
487 # if 0 && defined DEBUG
488 zzip_debug_xbuf((unsigned char *) d
, sizeof(*d
) + 8);
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
)
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
));
521 { memcpy(hdr
->d_name
, fd_map
+zz_fd_gap
+ zz_offset
+sizeof(*d
), u_namlen
); }
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
));
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
;
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
);
563 *p_reclen
= 0; /* mark end of list */
567 } /* else zero (sane) entries */
568 # ifndef ZZIP_ALLOW_MODULO_ENTRIES
569 return (entries
!= zz_entries
? ZZIP_CORRUPTED
: 0);
571 return ((entries
& (unsigned)0xFFFF) != zz_entries
? ZZIP_CORRUPTED
: 0);
575 /* ------------------------- high-level interface ------------------------- */
581 static zzip_strings_t
*
582 zzip_get_default_ext(void)
584 static zzip_strings_t ext
[] = {
586 ".zip", ".ZIP", /* common extension */
587 # ifdef ZZIP_USE_ZIPLIKES
588 ".pk3", ".PK3", /* ID Software's Quake3 zipfiles */
589 ".jar", ".JAR", /* Java zipfiles */
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
603 * (ext==null flags uses { ".zip" , ".ZIP" } )
604 * (io ==null flags use of posix io defaults)
607 zzip_dir_alloc_ext_io(zzip_strings_t
* ext
, const zzip_plugin_io_t io
)
610 if ((dir
= (ZZIP_DIR
*) calloc(1, sizeof(*dir
))) == NULL
)
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();
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.
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
)
645 return (dir
->refcount
); /* still open files attached */
648 dir
->io
->fd
.close(dir
->fd
);
653 if (dir
->cache
.buf32k
)
654 free(dir
->cache
.buf32k
);
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
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
695 zzip_dir_fdopen_ext_io(int fd
, zzip_error_t
* errcode_p
,
696 zzip_strings_t
* ext
, const zzip_plugin_io_t io
)
701 if ((dir
= zzip_dir_alloc_ext_io(ext
, io
)) == NULL
)
702 { rv
= ZZIP_OUTOFMEM
; goto error
; }
705 if ((rv
= __zzip_dir_parse(dir
)))
708 dir
->hdr
= dir
->hdr0
;
709 dir
->refcount
|= 0x10000000;
723 __zzip_dir_parse(ZZIP_DIR
* dir
)
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
,
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
,
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
];
769 zzip_size_t len
= strlen(filename
);
771 if (len
+ 4 >= PATH_MAX
)
772 { errno
= ENAMETOOLONG
; return -1; }
773 memcpy(file
, filename
, len
+ 1);
776 io
= zzip_get_default_io();
778 ext
= zzip_get_default_ext();
782 strcpy(file
+ len
, *ext
);
783 fd
= (io
->fd
.open
)(file
, filemode
);
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.
796 zzip_dir_open(zzip_char_t
* filename
, zzip_error_t
* e
)
798 return zzip_dir_open_ext_io(filename
, e
, 0, 0);
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.
808 zzip_dir_open_ext_io(zzip_char_t
* filename
, zzip_error_t
* e
,
809 zzip_strings_t
* ext
, zzip_plugin_io_t io
)
814 io
= zzip_get_default_io();
816 ext
= zzip_get_default_ext();
818 fd
= (io
->fd
.open
)(filename
, O_RDONLY
| O_BINARY
);
821 return zzip_dir_fdopen_ext_io(fd
, e
, ext
, io
);
824 fd
= __zzip_try_open(filename
, O_RDONLY
| O_BINARY
, ext
, io
);
827 return zzip_dir_fdopen_ext_io(fd
, e
, ext
, io
);
831 { *e
= 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
)
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
)
859 dir
->hdr
= (struct zzip_dir_hdr
*)
860 ((char *) dir
->hdr
+ dir
->hdr
->d_reclen
);
868 * c-file-style: "stroustrup"