4
* Guido Draheim <guidod@gmx.de>
5
* Tomi Ollila <Tomi.Ollila@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> /* exported... */
16
#include <zzip/file.h>
24
#include <zzip/format.h>
25
#include <zzip/fetch.h>
26
#include <zzip/__debug.h>
29
# if defined ZZIP_HAVE_IO_H
30
# include <io.h> /* tell */
32
# define tell(fd) lseek(fd,0,SEEK_CUR)
35
#define tells(fd) seeks(fd,0,SEEK_CUR)
39
* the direct function of => zzip_close(fp). it will cleanup the
40
* inflate-portion of => zlib and free the structure given.
42
* it is called quite from the error-cleanup parts
43
* of the various => _open functions.
45
* the .refcount is decreased and if zero the fp->dir is closed just as well.
48
zzip_file_close(ZZIP_FILE * fp)
51
ZZIP_DIR *dir = fp->dir;
54
inflateEnd(&fp->d_stream); /* inflateEnd() can be called many times */
56
if (dir->cache.locked == NULL)
57
dir->cache.locked = &self;
61
if (dir->cache.locked == &self && dir->cache.buf32k == NULL)
62
dir->cache.buf32k = fp->buf32k;
67
if (dir->currentfp == fp)
68
dir->currentfp = NULL;
71
/* ease to notice possible dangling reference errors */
72
memset(fp, 0, sizeof(*fp));
74
if (dir->cache.locked == &self && dir->cache.fp == NULL)
79
if (dir->cache.locked == &self)
80
dir->cache.locked = NULL;
83
return zzip_dir_close(dir);
90
zzip_file_saveoffset(ZZIP_FILE * fp)
95
zzip_off_t off = fp->io->fd.seeks(fd, 0, SEEK_CUR);
105
# ifndef ZZIP_CHECK_BACKSLASH_DIRSEPARATOR /* NOTE: also default */
106
# define ZZIP_CHECK_BACKSLASH_DIRSEPARATOR 0 /* to "NO" on win32 ! */
109
# if ! defined strcasecmp && ! defined ZZIP_HAVE_STRCASECMP
110
# define ZZIP_CHECK_BACKSLASH_DIRSEPARATOR 1
113
#if ! ZZIP_CHECK_BACKSLASH_DIRSEPARATOR+0
114
#define dirsep_strrchr(N,C) strrchr(N,C)
115
#define dirsep_casecmp strcasecmp
117
#define dirsep_strrchr(N,C) _dirsep_strrchr(N)
118
#define dirsep_casecmp _dirsep_casecmp
120
_dirsep_strrchr(zzip_char_t * name)
122
char *n = strrchr(name, '/');
123
char *m = strrchr(name, '\\');
130
_dirsep_casecmp(zzip_char_t * s1, zzip_char_t * s2)
132
/* ASCII tolower - including mapping of backslash in normal slash */
133
static const char mapping[] = "@abcdefghijklmnopqrstuvwxyz[/]^_";
138
c1 = (int) (unsigned char) *s1;
139
c2 = (int) (unsigned char) *s2;
140
if ((c1 & 0xE0) == 0x40)
141
c1 = mapping[c1 & 0x1f];
142
if ((c2 & 0xE0) == 0x40)
143
c2 = mapping[c2 & 0x1f];
150
return (((int) (unsigned char) *s1) - ((int) (unsigned char) *s2));
154
static int zzip_inflate_init(ZZIP_FILE *, struct zzip_dir_hdr *);
157
* open an => ZZIP_FILE from an already open => ZZIP_DIR handle. Since
158
* we have a chance to reuse a cached => buf32k and => ZZIP_FILE memchunk
159
* this is the best choice to unpack multiple files.
161
* Note: the zlib supports 2..15 bit windowsize, hence we provide a 32k
162
* memchunk here... just to be safe.
164
* On error it returns null and sets errcode in the ZZIP_DIR.
167
zzip_file_open(ZZIP_DIR * dir, zzip_char_t * name, int o_mode)
170
zzip_error_t err = 0;
171
struct zzip_file *fp = 0;
172
struct zzip_dir_hdr *hdr = dir->hdr0;
173
int (*cmp) (zzip_char_t *, zzip_char_t *);
175
cmp = (o_mode & ZZIP_CASELESS) ? dirsep_casecmp : strcmp;
179
if (! dir->fd || dir->fd == -1)
180
{ dir->errcode = EBADF; return NULL; }
182
{ dir->errcode = ENOENT; return NULL; }
184
if (o_mode & ZZIP_NOPATHS)
186
register zzip_char_t *n = dirsep_strrchr(name, '/');
194
register zzip_char_t *hdr_name = hdr->d_name;
196
if (o_mode & ZZIP_NOPATHS)
198
register zzip_char_t *n = dirsep_strrchr(hdr_name, '/');
204
HINT4("name='%s', compr=%d, size=%d\n",
205
hdr->d_name, hdr->d_compr, hdr->d_usize);
207
if (! cmp(hdr_name, name))
209
switch (hdr->d_compr)
212
case 8: /* inflate */
215
{ err = ZZIP_UNSUPP_COMPR; goto error; }
218
if (dir->cache.locked == NULL)
219
dir->cache.locked = &self;
221
if (dir->cache.locked == &self && dir->cache.fp)
224
dir->cache.fp = NULL;
225
/* memset(zfp, 0, sizeof *fp); cleared in zzip_file_close() */
228
if (! (fp = (ZZIP_FILE *) calloc(1, sizeof(*fp))))
229
{ err = ZZIP_OUTOFMEM; goto error; }
236
if (dir->cache.locked == &self && dir->cache.buf32k)
238
fp->buf32k = dir->cache.buf32k;
239
dir->cache.buf32k = NULL;
242
if (! (fp->buf32k = (char *) malloc(ZZIP_32K)))
243
{ err = ZZIP_OUTOFMEM; goto error; }
246
if (dir->cache.locked == &self)
247
dir->cache.locked = NULL;
249
* In order to support simultaneous open files in one zip archive
250
* we'll fix the fd offset when opening new file/changing which
254
if (zzip_file_saveoffset(dir->currentfp) < 0)
255
{ err = ZZIP_DIR_SEEK; goto error; }
257
fp->offset = hdr->d_off;
260
if (dir->io->fd.seeks(dir->fd, hdr->d_off, SEEK_SET) < 0)
261
{ err = ZZIP_DIR_SEEK; goto error; }
264
/* skip local header - should test tons of other info,
265
* but trust that those are correct */
266
zzip_ssize_t dataoff;
267
struct zzip_file_header *p = (void *) fp->buf32k;
269
dataoff = dir->io->fd.read(dir->fd, (void *) p, sizeof(*p));
270
if (dataoff < (zzip_ssize_t) sizeof(*p))
271
{ err = ZZIP_DIR_READ; goto error; }
272
if (! zzip_file_header_check_magic(p)) /* PK\3\4 */
273
{ err = ZZIP_CORRUPTED; goto error; }
275
dataoff = zzip_file_header_sizeof_tail(p);
277
if (dir->io->fd.seeks(dir->fd, dataoff, SEEK_CUR) < 0)
278
{ err = ZZIP_DIR_SEEK; goto error; }
280
fp->dataoffset = dir->io->fd.tells(dir->fd);
281
fp->usize = hdr->d_usize;
282
fp->csize = hdr->d_csize;
285
err = zzip_inflate_init(fp, hdr);
292
if (hdr->d_reclen == 0)
294
hdr = (struct zzip_dir_hdr *) ((char *) hdr + hdr->d_reclen);
297
dir->errcode = ZZIP_ENOENT;
307
* call => inflateInit and setup fp's iterator variables,
308
* used by lowlevel => _open functions.
311
zzip_inflate_init(ZZIP_FILE * fp, struct zzip_dir_hdr *hdr)
315
fp->method = hdr->d_compr;
316
fp->restlen = hdr->d_usize;
320
memset(&fp->d_stream, 0, sizeof(fp->d_stream));
322
err = inflateInit2(&fp->d_stream, -MAX_WBITS);
326
fp->crestlen = hdr->d_csize;
336
* This function closes the given ZZIP_FILE handle.
338
* If the ZZIP_FILE wraps a normal stat'fd then it is just that int'fd
339
* that is being closed and the otherwise empty ZZIP_FILE gets freed.
342
zzip_fclose(ZZIP_FILE * fp)
346
if (! fp->dir) /* stat fd */
347
{ int r = fp->io->fd.close(fp->fd); free(fp); return r; }
349
return zzip_file_close(fp);
355
zzip_close(ZZIP_FILE * fp)
357
return zzip_fclose(fp);
361
* This functions read data from zip-contained file.
363
* It works like => read(2) and will fill the given buffer with bytes from
364
* the opened file. It will return the number of bytes read, so if the => EOF
365
* is encountered you will be prompted with the number of bytes actually read.
367
* This is the routines that needs the => buf32k buffer, and it would have
368
* need for much more polishing but it does already work quite well.
370
* Note: the 32K buffer is rather big. The original inflate-algorithm
371
* required just that but the latest zlib would work just fine with
375
zzip_file_read(ZZIP_FILE * fp, void *buf, zzip_size_t len)
381
if (! fp || ! fp->dir)
385
l = fp->restlen > len ? len : fp->restlen;
386
if (fp->restlen == 0)
390
* If this is other handle than previous, save current seek pointer
391
* and read the file position of `this' handle.
393
if (dir->currentfp != fp)
395
if (zzip_file_saveoffset(dir->currentfp) < 0
396
|| fp->io->fd.seeks(dir->fd, fp->offset, SEEK_SET) < 0)
397
{ dir->errcode = ZZIP_DIR_SEEK; return -1; }
399
{ dir->currentfp = fp; }
402
/* if more methods is to be supported, change this to `switch ()' */
403
if (fp->method) /* method != 0 == 8, inflate */
405
fp->d_stream.avail_out = l;
406
fp->d_stream.next_out = (unsigned char *) buf;
411
zzip_size_t startlen;
413
if (fp->crestlen > 0 && fp->d_stream.avail_in == 0)
415
zzip_size_t cl = (fp->crestlen < ZZIP_32K ?
416
fp->crestlen : ZZIP_32K);
418
* fp->crestlen > 128 ? 128 : fp->crestlen;
420
zzip_ssize_t i = fp->io->fd.read(dir->fd, fp->buf32k, cl);
424
dir->errcode = ZZIP_DIR_READ;
425
/* or ZZIP_DIR_READ_EOF ? */
429
fp->d_stream.avail_in = i;
430
fp->d_stream.next_in = (unsigned char *) fp->buf32k;
433
startlen = fp->d_stream.total_out;
434
err = inflate(&fp->d_stream, Z_NO_FLUSH);
436
if (err == Z_STREAM_END)
438
else if (err == Z_OK)
439
{ fp->restlen -= (fp->d_stream.total_out - startlen); }
441
{ dir->errcode = err; return -1; }
443
while (fp->restlen && fp->d_stream.avail_out);
445
return l - fp->d_stream.avail_out;
447
{ /* method == 0 -- unstore */
448
rv = fp->io->fd.read(dir->fd, buf, l);
450
{ fp->restlen-= rv; }
452
{ dir->errcode = ZZIP_DIR_READ; }
458
* This function will read(2) data from a real/zipped file.
460
* the replacement for => read(2) will fill the given buffer with bytes from
461
* the opened file. It will return the number of bytes read, so if the EOF
462
* is encountered you will be prompted with the number of bytes actually read.
464
* If the file-handle is wrapping a stat'able file then it will actually just
465
* perform a normal => read(2)-call, otherwise => zzip_file_read is called
466
* to decompress the data stream and any error is mapped to => errno(3).
469
zzip_read(ZZIP_FILE * fp, void *buf, zzip_size_t len)
474
{ return fp->io->fd.read(fp->fd, buf, len); } /* stat fd */
477
register zzip_ssize_t v;
479
v = zzip_file_read(fp, buf, len);
481
{ errno = zzip_errno(fp->dir->errcode); }
489
zzip_fread(void *ptr, zzip_size_t size, zzip_size_t nmemb, ZZIP_FILE * file)
493
return zzip_read(file, ptr, size * nmemb) / size;
497
#define ZZIP_WRONLY O_WRONLY
498
#define ZZIP_EXCL O_EXCL
501
#define ZZIP_SYNC O_SYNC
506
#if defined O_NONBLOCK
507
#define ZZIP_NONBLOCK O_NONBLOCK
508
#elif defined O_NDELAY
509
#define ZZIP_NOCTTY O_NDELAY
511
#define ZZIP_NOCTTY 0
514
/* ------------------------------------------------------------------- */
517
* This function will => fopen(3) a real/zipped file.
519
* It has some magic functionality builtin - it will first try to open
520
* the given <em>filename</em> as a normal file. If it does not
521
* exist, the given path to the filename (if any) is split into
522
* its directory-part and the file-part. A ".zip" extension is
523
* then added to the directory-part to create the name of a
524
* zip-archive. That zip-archive (if it exists) is being searched
525
* for the file-part, and if found a zzip-handle is returned.
527
* Note that if the file is found in the normal fs-directory the
528
* returned structure is mostly empty and the => zzip_read call will
529
* use the libc => read to obtain data. Otherwise a => zzip_file_open
530
* is performed and any error mapped to => errno(3).
532
* unlike the posix-wrapper => zzip_open the mode-argument is
533
* a string which allows for more freedom to support the extra
534
* zzip modes called ZZIP_CASEINSENSITIVE and ZZIP_IGNOREPATH.
535
* Currently, this => zzip_fopen call will convert the following
536
* characters in the mode-string into their corrsponding mode-bits:
537
* * <code> "r" : O_RDONLY : </code> read-only
538
* * <code> "b" : O_BINARY : </code> binary (win32 specific)
539
* * <code> "f" : O_NOCTTY : </code> no char device (unix)
540
* * <code> "i" : ZZIP_CASELESS : </code> inside zip file
541
* * <code> "*" : ZZIP_NOPATHS : </code> inside zip file only
542
* all other modes will be ignored for zip-contained entries
543
* but they are transferred for compatibility and portability,
544
* including these extra sugar bits:
545
* * <code> "x" : O_EXCL :</code> fail if file did exist
546
* * <code> "s" : O_SYNC :</code> synchronized access
547
* * <code> "n" : O_NONBLOCK :</code> nonblocking access
548
* * <code> "z#" : compression level :</code> for zlib
549
* * <code> "g#" : group access :</code> unix access bits
550
* * <code> "u#" : owner access :</code> unix access bits
551
* * <code> "o#" : world access :</code> unix access bits
552
* ... the access bits are in traditional unix bit format
553
* with 7 = read/write/execute, 6 = read/write, 4 = read-only.
555
* The default access mode is 0664, and the compression level
556
* is ignored since the lib can not yet write zip files, otherwise
557
* it would be the initialisation value for the zlib deflateInit
558
* where 0 = no-compression, 1 = best-speed, 9 = best-compression.
560
* This function returns a new zzip-handle (use => zzip_close to return
561
* it). On error this function will return null setting => errno(3).
564
zzip_fopen(zzip_char_t * filename, zzip_char_t * mode)
566
return zzip_freopen(filename, mode, 0);
571
* This function receives an additional argument pointing to
572
* a ZZIP_FILE* being already in use. If this extra argument is
573
* null then this function is identical with calling => zzip_fopen
575
* Per default, the old file stream is closed and only the internal
576
* structures associated with it are kept. These internal structures
577
* may be reused for the return value, and this is a lot quicker when
578
* the filename matches a zipped file that is incidently in the very
579
* same zip arch as the old filename wrapped in the stream struct.
581
* That's simply because the zip arch's central directory does not
582
* need to be read again. As an extension for this function, if the
583
* mode-string contains a "q" then the old stream is not closed but
584
* left untouched, instead it is only given as a hint that a new
585
* file handle may share/copy the zip arch structures of the old file
586
* handle if that is possible, i.e when they are in the same zip arch.
588
* This function returns a new zzip-handle (use => zzip_close to return
589
* it). On error this function will return null setting => errno(3).
592
zzip_freopen(zzip_char_t * filename, zzip_char_t * mode, ZZIP_FILE * stream)
610
# define O_NONBLOCK 0
613
for (; *mode; mode++)
618
case '0': case '1': case '2': case '3': case '4':
619
case '5': case '6': case '7': case '8': case '9':
620
continue; /* ignore if not attached to other info */
621
case 'r': o_flags |= mode[1] == '+' ? O_RDWR : O_RDONLY; break;
622
case 'w': o_flags |= mode[1] == '+' ? O_RDWR : O_WRONLY;
623
o_flags |= O_TRUNC; break;
624
case 'b': o_flags |= O_BINARY; break;
625
case 'f': o_flags |= O_NOCTTY; break;
626
case 'i': o_modes |= ZZIP_CASELESS; break;
627
case '*': o_modes |= ZZIP_NOPATHS; break;
628
case 'x': o_flags |= O_EXCL; break;
629
case 's': o_flags |= O_SYNC; break;
630
case 'n': o_flags |= O_NONBLOCK; break;
631
case 'o': o_modes &=~ 07;
632
o_modes |= ((mode[1] - '0')) & 07; continue;
633
case 'g': o_modes &=~ 070;
634
o_modes |= ((mode[1] - '0') << 3) & 070; continue;
635
case 'u': o_modes &=~ 0700;
636
o_modes |= ((mode[1] - '0') << 6) & 0700; continue;
637
case 'q': o_modes |= ZZIP_FACTORY; break;
638
case 'z': /* compression level */
639
continue; /* currently ignored, just for write mode */
646
zzip_open_shared_io(stream, filename, o_flags, o_modes, 0, 0);
648
if (! (o_modes & ZZIP_FACTORY) && stream)
649
zzip_file_close(stream);
656
* This function will => open(2) a real/zipped file
658
* It has some magic functionality builtin - it will first try to open
659
* the given <em>filename</em> as a normal file. If it does not
660
* exist, the given path to the filename (if any) is split into
661
* its directory-part and the file-part. A ".zip" extension is
662
* then added to the directory-part to create the name of a
663
* zip-archive. That zip-archive (if it exists) is being searched
664
* for the file-part, and if found a zzip-handle is returned.
666
* Note that if the file is found in the normal fs-directory the
667
* returned structure is mostly empty and the => zzip_read call will
668
* use the libc => read to obtain data. Otherwise a => zzip_file_open
669
* is performed and any error mapped to => errno(3).
671
* There was a possibility to transfer zziplib-specific openmodes
672
* through o_flags but you should please not use them anymore and
673
* look into => zzip_open_ext_io to submit them down. This function
674
* is shallow in that it just extracts the zzipflags and calls
675
* * <code>zzip_open_ext_io(filename, o_flags, zzipflags|0664, 0, 0) </code>
676
* you must stop using this extra functionality (not well known anyway)
677
* since zzip_open might be later usable to open files for writing
678
* in which case the _EXTRAFLAGS will get in conflict.
680
* compare with => open(2) and => zzip_fopen
683
zzip_open(zzip_char_t * filename, int o_flags)
685
/* backward compatibility */
688
if (o_flags & ZZIP_CASEINSENSITIVE)
689
{ o_flags ^= ZZIP_CASEINSENSITIVE; o_modes |= ZZIP_CASELESS; }
690
if (o_flags & ZZIP_IGNOREPATH)
691
{ o_flags ^= ZZIP_IGNOREPATH; o_modes |= ZZIP_NOPATHS; }
692
return zzip_open_ext_io(filename, o_flags, o_modes, 0, 0);
695
/* ZZIP_ONLYZIP won't work on platforms with sizeof(int) == 16bit */
696
#if ZZIP_SIZEOF_INT+0 == 2
702
* This function uses explicit ext and io instead of the internal
703
* defaults, setting them to zero is equivalent to => zzip_open
705
* note that the two flag types have been split into an o_flags
706
* (for fcntl-like openflags) and o_modes where the latter shall
707
* carry the zzip_flags and possibly accessmodes for unix filesystems.
708
* Since this version of zziplib can not write zipfiles, it is not
709
* yet used for anything else than zzip-specific modeflags.
711
* This function returns a new zzip-handle (use => zzip_close to return
712
* it). On error this function will return null setting => errno(3).
715
zzip_open_ext_io(zzip_char_t * filename, int o_flags, int o_modes,
716
zzip_strings_t * ext, zzip_plugin_io_t io)
718
return zzip_open_shared_io(0, filename, o_flags, o_modes, ext, io);
723
* This function takes an extra stream argument - if a handle has been
724
* then ext/io can be left null and the new stream handle will pick up
725
* the ext/io. This should be used only in specific environment however
726
* since => zzip_file_real does not store any ext-sequence.
728
* The benefit for this function comes in when the old file handle
729
* was openened from a file within a zip archive. When the new file
730
* is in the same zip archive then the internal zzip_dir structures
731
* will be shared. It is even quicker, as no check needs to be done
732
* anymore trying to guess the zip archive place in the filesystem,
733
* here we just check whether the zip archive's filepath is a prefix
734
* part of the filename to be opened.
736
* Note that this function is also used by => zzip_freopen that
737
* will unshare the old handle, thereby possibly closing the handle.
739
* This function returns a new zzip-handle (use => zzip_close to return
740
* it). On error this function will return null setting => errno(3).
743
zzip_open_shared_io(ZZIP_FILE * stream,
744
zzip_char_t * filename, int o_flags, int o_modes,
745
zzip_strings_t * ext, zzip_plugin_io_t io)
747
if (stream && stream->dir)
750
ext = stream->dir->fileext;
752
io = stream->dir->io;
755
io = zzip_get_default_io();
757
if (o_modes & (ZZIP_PREFERZIP | ZZIP_ONLYZIP))
760
/* prefer an existing real file */
762
zzip_plugin_io_t os = (o_modes & ZZIP_ALLOWREAL)
763
? zzip_get_default_io() : io;
764
int fd = os->fd.open(filename, o_flags); /* io->fd.open */
768
ZZIP_FILE *fp = calloc(1, sizeof(ZZIP_FILE));
771
{ os->fd.close(fd); return 0; } /* io->fd.close */
777
if (o_modes & ZZIP_PREFERZIP)
782
/* if the user had it in place of a normal xopen, then
783
* we better defend this lib against illegal usage */
784
if (o_flags & (O_CREAT | O_WRONLY))
785
{ errno = EINVAL; return 0; }
786
if (o_flags & (O_RDWR))
787
{ o_flags ^= O_RDWR; o_flags |= O_RDONLY; }
789
/* this is just for backward compatibility -and strictly needed to
790
* prepare ourselves for more options and more options later on... */
791
/*# if (o_modes & ZZIP_CASELESS) { o_flags |= ZZIP_CASEINSENSITIVE; } */
792
/*# if (o_modes & ZZIP_NOPATHS) { o_flags |= ZZIP_IGNOREPATH; } */
794
/* see if we can open a file that is a zip file */
796
char basename[PATH_MAX];
798
int filename_len = strlen(filename);
800
if (filename_len >= PATH_MAX)
801
{ errno = ENAMETOOLONG; return 0; }
802
memcpy(basename, filename, filename_len + 1);
804
/* see if we can share the same zip directory */
805
if (stream && stream->dir && stream->dir->realname)
807
zzip_size_t len = strlen(stream->dir->realname);
809
if (! memcmp(filename, stream->dir->realname, len) &&
810
filename[len] == '/' && filename[len + 1])
813
zzip_file_open(stream->dir, filename + len + 1, o_modes);
815
{ errno = zzip_errno (stream->dir->errcode); }
820
/* per each slash in filename, check if it there is a zzip around */
821
while ((p = strrchr(basename, '/')))
829
/* i.e. cut at path separator == possible zipfile basename */
830
fd = __zzip_try_open(basename, o_flags | O_RDONLY | O_BINARY,
835
/* found zip-file .... now try to parse it */
836
dir = zzip_dir_fdopen_ext_io(fd, &e, ext, io);
838
{ errno = zzip_errno(e); io->fd.close(fd); return 0; }
840
/* (p - basename) is the lenghtof zzip_dir part of the filename */
841
fp = zzip_file_open(dir, filename + (p - basename) + 1, o_modes);
843
{ errno = zzip_errno(dir->errcode); }
845
{ if (! dir->realname) dir->realname = strdup (basename); }
848
/* note: since (fp) is attached that (dir) will survive */
849
/* but (dir) is implicitly closed on next zzip_close(fp) */
854
if (o_modes & ZZIP_PREFERZIP)
857
{ errno = ENOENT; return 0; }
861
#if defined ZZIP_LARGEFILE_RENAME && defined EOVERFLOW && defined PIC
862
#undef zzip_open_shared_io /* zzip_open_shared_io64 */
863
#undef zzip_open_ext_io /* zzip_open_ext_io64 */
864
#undef zzip_opendir_ext_io /* zzip_opendir_ext_io64 */
866
ZZIP_FILE *zzip_open_shared_io(ZZIP_FILE * stream,
867
zzip_char_t * name, int o_flags,
868
int o_modes, zzip_strings_t * ext,
869
zzip_plugin_io_t io);
870
ZZIP_FILE *zzip_open_ext_io(zzip_char_t * name, int o_flags,
871
int o_modes, zzip_strings_t * ext,
872
zzip_plugin_io_t io);
873
ZZIP_DIR *zzip_opendir_ext_io(zzip_char_t * name, int o_modes,
874
zzip_strings_t * ext, zzip_plugin_io_t io);
876
/* DLL compatibility layer - so that 32bit code can link with this lib too */
879
zzip_open_shared_io(ZZIP_FILE * stream,
880
zzip_char_t * name, int o_flags,
881
int o_modes, zzip_strings_t * ext, zzip_plugin_io_t io)
884
return zzip_open_shared_io64(stream, name, o_flags, o_modes, ext, io);
890
zzip_open_ext_io(zzip_char_t * name, int o_flags, int o_modes,
891
zzip_strings_t * ext, zzip_plugin_io_t io)
894
return zzip_open_ext_io64(name, o_flags, o_modes, ext, io);
900
zzip_opendir_ext_io(zzip_char_t * name, int o_modes,
901
zzip_strings_t * ext, zzip_plugin_io_t io)
904
return zzip_opendir_ext_io64(name, o_modes, ext, io);
906
{ errno = EOVERFLOW; return NULL; }
909
#endif /* ZZIP_LARGEFILE_RENAME && EOVERFLOW && PIC */
911
/* ------------------------------------------------------------------- */
914
* This function will rewind a real/zipped file.
916
* It seeks to the beginning of this file's data in the zip,
917
* or the beginning of the file for a stat'fd.
920
zzip_rewind(ZZIP_FILE * fp)
930
fp->io->fd.seeks(fp->fd, 0, SEEK_SET);
936
* If this is other handle than previous, save current seek pointer
938
if (dir->currentfp != fp)
940
if (zzip_file_saveoffset(dir->currentfp) < 0)
941
{ dir->errcode = ZZIP_DIR_SEEK; return -1; }
943
{ dir->currentfp = fp; }
946
/* seek to beginning of this file */
947
if (fp->io->fd.seeks(dir->fd, fp->dataoffset, SEEK_SET) < 0)
950
/* reset the inflate init stuff */
951
fp->restlen = fp->usize;
952
fp->offset = fp->dataoffset;
955
{ /* method == 8, deflate */
956
err = inflateReset(&fp->d_stream);
960
/* start over at next inflate with a fresh read() */
961
fp->d_stream.avail_in = 0;
962
fp->crestlen = fp->csize;
974
* This function will perform a => lseek(2) operation on a real/zipped file
976
* It will try to seek to the offset specified by offset, relative to whence,
977
* which is one of SEEK_SET, SEEK_CUR or SEEK_END.
979
* If the file-handle is wrapping a stat'able file then it will actually just
980
* perform a normal => lseek(2)-call. Otherwise the relative offset
981
* is calculated, negative offsets are transformed into positive ones
982
* by rewinding the file, and then data is read until the offset is
983
* reached. This can make the function terribly slow, but this is
984
* how gzio implements it, so I'm not sure there is a better way
985
* without using the internals of the algorithm.
988
zzip_seek(ZZIP_FILE * fp, zzip_off_t offset, int whence)
990
zzip_off_t cur_pos, rel_ofs, read_size, ofs;
998
return fp->io->fd.seeks(fp->fd, offset, whence);
1001
cur_pos = zzip_tell(fp);
1003
/* calculate relative offset */
1006
case SEEK_SET: /* from beginning */
1007
rel_ofs = offset - cur_pos;
1009
case SEEK_CUR: /* from current */
1012
case SEEK_END: /* from end */
1013
rel_ofs = fp->usize + offset - cur_pos;
1015
default: /* something wrong */
1020
return cur_pos; /* don't have to move */
1023
{ /* convert backward into forward */
1024
if (zzip_rewind(fp) == -1)
1027
read_size = cur_pos + rel_ofs;
1030
{ /* amount to read is positive relative offset */
1031
read_size = rel_ofs;
1034
if (read_size < 0) /* bad offset, before beginning of file */
1037
if (read_size + cur_pos > (zzip_off_t) fp->usize) /* bad offset, past EOF */
1040
if (read_size == 0) /* nothing to read */
1045
* If this is other handle than previous, save current seek pointer
1046
* and read the file position of `this' handle.
1048
if (dir->currentfp != fp)
1050
if (zzip_file_saveoffset(dir->currentfp) < 0
1051
|| dir->currentfp->io->fd.seeks(dir->fd, fp->offset, SEEK_SET) < 0)
1052
{ dir->errcode = ZZIP_DIR_SEEK; return -1; }
1054
{ dir->currentfp = fp; }
1057
if (fp->method == 0)
1058
{ /* unstore, just lseek relatively */
1059
ofs = fp->io->fd.tells(dir->fd);
1060
ofs = fp->io->fd.seeks(dir->fd, read_size, SEEK_CUR);
1062
{ /* readjust from beginning of file */
1063
ofs -= fp->dataoffset;
1064
fp->restlen = fp->usize - ofs;
1068
{ /* method == 8, inflate */
1071
/*FIXME: use a static buffer! */
1072
buf = (char *) malloc(ZZIP_32K);
1076
while (read_size > 0)
1078
zzip_off_t size = ZZIP_32K;
1080
if (read_size < size /*32K */ )
1083
size = zzip_file_read(fp, buf, (zzip_size_t) size);
1085
{ free(buf); return -1; }
1093
return zzip_tell(fp);
1097
* This function will => tell(2) the current position in a real/zipped file
1099
* It will return the current offset within the real/zipped file,
1100
* measured in uncompressed bytes for the zipped-file case.
1102
* If the file-handle is wrapping a stat'able file then it will actually just
1103
* perform a normal => tell(2)-call, otherwise the offset is
1104
* calculated from the amount of data left and the total uncompressed
1108
zzip_tell(ZZIP_FILE * fp)
1113
if (! fp->dir) /* stat fd */
1114
return fp->io->fd.tells(fp->fd);
1116
/* current uncompressed offset is uncompressed size - data left */
1117
return (fp->usize - fp->restlen);
1122
* c-file-style: "stroustrup"