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>
27 #ifdef ZZIP_HAVE_SYS_STAT_H
31 #include <zzip/__mmap.h>
32 #include <zzip/__debug.h>
34 #define __sizeof(X) ((zzip_ssize_t)(sizeof(X)))
37 /* per default, we use a little hack to correct bad z_rootseek parts */
38 #define ZZIP_CORRECT_ROOTSEEK 1
41 #if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ >= 4)
43 # warning suppress a warning where the compiler should have optimized instead.
50 #define ZZIP_DISK64_TRAILER 1
52 #ifdef ZZIP_DISK64_TRAILER
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))
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
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
,
90 static int __zzip_parse_root_directory(int fd
,
91 struct _disk_trailer
*trailer
,
92 struct zzip_dir_hdr
**hdr_return
,
95 _zzip_inline
static char *__zzip_aligned4(char *p
);
97 /* ------------------------ harden routines ------------------------------ */
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;
134 #define __fixup_rootseek(A,B)
135 #define __correct_rootseek(A,B,C)
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
161 #define __debug_dir_hdr(X)
164 /* -------------------------- low-level interface -------------------------- */
167 #if BUFSIZ == 1024 || BUFSIZ == 512 || BUFSIZ == 256
168 #define ZZIP_BUFSIZ BUFSIZ
173 #define ZZIP_BUFSIZ 2048
175 /* #define ZZIP_BUFSIZ 64 / * for testing */
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.
184 __zzip_fetch_disk_trailer(int fd
, zzip_off_t filesize
,
185 struct _disk_trailer
*_zzip_restrict trailer
,
189 #define return(val) { e=val; HINT2("%s", zzip_strerror(e)); goto cleanup; }
191 #define return(val) { e=val; goto cleanup; }
196 auto char buffer
[2 * ZZIP_BUFSIZ
];
199 char *buf
= malloc(2 * ZZIP_BUFSIZ
);
201 zzip_off_t offset
= 0;
202 zzip_ssize_t maplen
= 0; /* mmap(),read(),getpagesize() use size_t !! */
210 { return(ZZIP_OUTOFMEM
); }
213 if (filesize
< __sizeof(struct zzip_disk_trailer
))
214 { return(ZZIP_DIR_TOO_SHORT
); }
217 { return(ZZIP_OUTOFMEM
); }
219 offset
= filesize
; /* a.k.a. old offset */
220 while (1) /* outer loop */
222 register unsigned char *mapped
;
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
)
241 if (mapoff
< pagesize
)
243 maplen
= (zzip_ssize_t
) mapoff
+ pagesize
;
248 maplen
= 2 * pagesize
;
249 if ((zzip_ssize_t
) mapoff
& (pagesize
- 1))
251 pagesize
-= (zzip_ssize_t
) mapoff
& (pagesize
- 1);
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
)
263 mapped
= (unsigned char *) fd_map
;
264 offset
= mapoff
; /* success */
265 HINT3("mapped *%p len=%li", fd_map
, (long) maplen
);
269 fd_map
= 0; /* have no mmap */
271 zzip_off_t pagesize
= ZZIP_BUFSIZ
;
272 if (offset
== filesize
&& filesize
> pagesize
)
274 if (offset
< pagesize
)
276 maplen
= (zzip_ssize_t
) offset
+ pagesize
;
281 maplen
= 2 * pagesize
;
282 if ((zzip_ssize_t
) offset
& (pagesize
- 1))
284 pagesize
-= (zzip_ssize_t
) offset
& (pagesize
- 1);
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
));
319 memcpy(trailer
, tail
, sizeof(*trailer
) - 2);
320 trailer
->z_comment
[0] = 0;
321 trailer
->z_comment
[1] = 0;
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
);
334 __fixup_rootseek(offset
+ tail
- mapped
, trailer
);
336 } else if ((*tail
== 'P') &&
338 __sizeof(struct zzip_disk64_trailer
) - 2
339 && zzip_disk64_trailer_check_magic(tail
))
341 # ifndef ZZIP_DISK64_TRAILER
342 return (ZZIP_DIR_LARGEFILE
);
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
);
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
);
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
);
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 :) */
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
403 __zzip_parse_root_directory(int fd
,
404 struct _disk_trailer
*trailer
,
405 struct zzip_dir_hdr
**hdr_return
,
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 */
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
);
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
));
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
));
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
);
464 { d
= (void*)(fd_map
+zz_fd_gap
+zz_offset
); } /* fd_map+fd_gap==u_rootseek */
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
;
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
);
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
);
490 # if 0 && defined DEBUG
491 zzip_debug_xbuf((unsigned char *) d
, sizeof(*d
) + 8);
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
)
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
));
524 { memcpy(hdr
->d_name
, fd_map
+zz_fd_gap
+ zz_offset
+sizeof(*d
), u_namlen
); }
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
));
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
;
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
);
566 *p_reclen
= 0; /* mark end of list */
570 } /* else zero (sane) entries */
571 # ifndef ZZIP_ALLOW_MODULO_ENTRIES
572 return (entries
!= zz_entries
? ZZIP_CORRUPTED
: 0);
574 return ((entries
& (unsigned)0xFFFF) != zz_entries
? ZZIP_CORRUPTED
: 0);
578 /* ------------------------- high-level interface ------------------------- */
584 static zzip_strings_t
*
585 zzip_get_default_ext(void)
587 static zzip_strings_t ext
[] = {
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 */
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
608 * (ext==null flags uses { ".zip" , ".ZIP" } )
609 * (io ==null flags use of posix io defaults)
612 zzip_dir_alloc_ext_io(zzip_strings_t
* ext
, const zzip_plugin_io_t io
)
615 if ((dir
= (ZZIP_DIR
*) calloc(1, sizeof(*dir
))) == NULL
)
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();
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.
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
)
650 return (dir
->refcount
); /* still open files attached */
653 dir
->io
->fd
.close(dir
->fd
);
658 if (dir
->cache
.buf32k
)
659 free(dir
->cache
.buf32k
);
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
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
700 zzip_dir_fdopen_ext_io(int fd
, zzip_error_t
* errcode_p
,
701 zzip_strings_t
* ext
, const zzip_plugin_io_t io
)
706 if ((dir
= zzip_dir_alloc_ext_io(ext
, io
)) == NULL
)
707 { rv
= ZZIP_OUTOFMEM
; goto error
; }
710 if ((rv
= __zzip_dir_parse(dir
)))
713 dir
->hdr
= dir
->hdr0
;
714 dir
->refcount
|= 0x10000000;
728 __zzip_dir_parse(ZZIP_DIR
* dir
)
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
,
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
,
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
];
774 zzip_size_t len
= strlen(filename
);
776 if (len
+ 4 >= PATH_MAX
)
777 { /* errno = ENAMETOOLONG; */ return -1; }
778 memcpy(file
, filename
, len
+ 1);
781 io
= zzip_get_default_io();
783 ext
= zzip_get_default_ext();
787 strcpy(file
+ len
, *ext
);
788 fd
= (io
->fd
.open
)(file
, filemode
);
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.
801 zzip_dir_open(zzip_char_t
* filename
, zzip_error_t
* e
)
803 return zzip_dir_open_ext_io(filename
, e
, 0, 0);
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.
813 zzip_dir_open_ext_io(zzip_char_t
* filename
, zzip_error_t
* e
,
814 zzip_strings_t
* ext
, zzip_plugin_io_t io
)
819 io
= zzip_get_default_io();
821 ext
= zzip_get_default_ext();
823 fd
= (io
->fd
.open
)(filename
, O_RDONLY
| O_BINARY
);
826 return zzip_dir_fdopen_ext_io(fd
, e
, ext
, io
);
829 fd
= __zzip_try_open(filename
, O_RDONLY
| O_BINARY
, ext
, io
);
832 return zzip_dir_fdopen_ext_io(fd
, e
, ext
, io
);
836 { *e
= 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
)
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
)
864 dir
->hdr
= (struct zzip_dir_hdr
*)
865 ((char *) dir
->hdr
+ dir
->hdr
->d_reclen
);
873 * c-file-style: "stroustrup"