PageRenderTime 24ms CodeModel.GetById 2ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

/src/zziplib/zzip/memdisk.c

https://bitbucket.org/cabalistic/ogredeps/
C | 466 lines | 372 code | 34 blank | 60 comment | 42 complexity | 518ada4d50b8e7fb625377f0f80cd521 MD5 | raw file
  1
  2/*
  3 * NOTE: this is part of libzzipmmapped (i.e. it is not libzzip).
  4 *                                            ==================
  5 *
  6 * The mem_disk cache will parse the central information of a zip archive
  7 * and store it internally. One the one hand it allows to find files
  8 * faster - no disk access is required and endian conversion is not
  9 * needed. If zzip is compiled with zip extensions then it is about
 10 * the only way to build maintainable code around the zip format.
 11 *
 12 * Note that 64bit support is almost entirely living in extension
 13 * blocks as well as different character encodings and file access
 14 * control bits that are mostly platform specific.
 15 *
 16 * Author:
 17 *    Guido Draheim <guidod@gmx.de>
 18 *
 19 * Copyright (c) 1999,2000,2001,2002,2003 Guido Draheim
 20 *          All rights reserved,
 21 *          use under the restrictions of the
 22 *          Lesser GNU General Public License
 23 *          or alternatively the restrictions
 24 *          of the Mozilla Public License 1.1
 25 */
 26#define _ZZIP_DISK_FILE_STRUCT 1
 27
 28#include <zzip/types.h>
 29
 30#include <stdlib.h>
 31#include <stdio.h>
 32#include <string.h>
 33#include <time.h>
 34
 35#include <zlib.h>
 36#include <zzip/format.h>
 37#include <zzip/fetch.h>
 38#include <zzip/mmapped.h>
 39#include <zzip/memdisk.h>
 40#include <zzip/__fnmatch.h>
 41
 42#define ___ {
 43#define ____ }
 44
 45static const char *error[] = {
 46    "Ok",
 47#   define _zzip_mem_disk_open_fail 1
 48    "zzip_mem_disk_open: zzip_disk_open did fail",
 49#   define _zzip_mem_disk_fdopen_fail 2
 50    "zzip_mem_disk_fdopen: zzip_disk_mmap did fail"
 51#   define _zzip_mem_disk_buffer_fail 3
 52    "zzip_mem_disk_buffer: zzip_disk_buffer did fail",
 53    0
 54};
 55
 56#define ZZIP_EXTRA_zip64 0x0001
 57typedef struct _zzip_extra_zip64
 58{                               /* ZIP64 extended information extra field */
 59    zzip_byte_t z_datatype[2];  /* Tag for this "extra" block type */
 60    zzip_byte_t z_datasize[2];  /* Size of this "extra" block */
 61    zzip_byte_t z_usize[8];     /* Original uncompressed file size */
 62    zzip_byte_t z_csize[8];     /* Size of compressed data */
 63    zzip_byte_t z_offset[8];    /* Offset of local header record */
 64    zzip_byte_t z_diskstart[4]; /* Number of the disk for file start */
 65} zzip_extra_zip64;
 66
 67/*forward*/
 68
 69static zzip__new__ ZZIP_MEM_ENTRY *
 70zzip_mem_entry_new(ZZIP_DISK * disk, ZZIP_DISK_ENTRY * entry);
 71static void
 72zzip_mem_entry_free(ZZIP_MEM_ENTRY * _zzip_restrict item);
 73
 74zzip__new__ ZZIP_MEM_DISK *
 75zzip_mem_disk_new(void)
 76{
 77    return calloc(1, sizeof(ZZIP_MEM_DISK));
 78}
 79
 80/** create new diskdir handle.
 81 *  wraps underlying zzip_disk_open. */
 82zzip__new__ ZZIP_MEM_DISK *
 83zzip_mem_disk_open(char *filename)
 84{
 85    ZZIP_DISK *disk = zzip_disk_open(filename);
 86    if (! disk)
 87        { perror(error[_zzip_mem_disk_open_fail]); return 0; }
 88    ___ ZZIP_MEM_DISK *dir = zzip_mem_disk_new();
 89    zzip_mem_disk_load(dir, disk);
 90    return dir;
 91    ____;
 92}
 93
 94/** create new diskdir handle.
 95 *  wraps underlying zzip_disk_open. */
 96zzip__new__ ZZIP_MEM_DISK *
 97zzip_mem_disk_fdopen(int fd)
 98{
 99    ZZIP_DISK *disk = zzip_disk_mmap(fd);
100    if (! disk)
101        { perror(error[_zzip_mem_disk_fdopen_fail]); return 0; }
102    ___ ZZIP_MEM_DISK *dir = zzip_mem_disk_new();
103    zzip_mem_disk_load(dir, disk);
104    return dir;
105    ____;
106}
107
108/** create new diskdir handle.
109 *  wraps underlying zzip_disk_buffer. */
110zzip__new__ ZZIP_MEM_DISK *
111zzip_mem_disk_buffer(char *buffer, size_t buflen)
112{
113    ZZIP_DISK *disk = zzip_disk_buffer(buffer, buflen);
114    if (! disk)
115        { perror(error[_zzip_mem_disk_buffer_fail]); return 0; }
116    ___ ZZIP_MEM_DISK *dir = zzip_mem_disk_new();
117    zzip_mem_disk_load(dir, disk);
118    return dir;
119    ____;
120}
121
122/** parse central dir.
123 *  creates an internal copy of each entry converted to the local platform.
124 *  returns: number of entries, or -1 on error (setting errno)
125 */
126long
127zzip_mem_disk_load(ZZIP_MEM_DISK * dir, ZZIP_DISK * disk)
128{
129    if (! dir || ! disk)
130        { errno=EINVAL; return -1; }
131    if (dir->list)
132        zzip_mem_disk_unload(dir);
133    ___ long count = 0;
134    ___ struct zzip_disk_entry *entry = zzip_disk_findfirst(disk);
135    for (; entry; entry = zzip_disk_findnext(disk, entry))
136    {
137        ZZIP_MEM_ENTRY *item = zzip_mem_entry_new(disk, entry);
138        if (! item)
139            goto error;
140        if (dir->last)
141        {
142            dir->last->zz_next = item;  /* chain last */
143        } else
144        {
145            dir->list = item;
146        }
147        dir->last = item;       /* to earlier */
148        count++;
149    }
150    ____;
151    dir->disk = disk;
152    return count;
153    ____;
154  error:
155    zzip_mem_disk_unload(dir);
156    return -1;
157}
158
159/** convert a zip disk entry to internal format.
160 * creates a new item parsing the information out of the various places
161 * in the zip archive. This is a good place to extend functionality if
162 * you have a project with extra requirements as you can push more bits
163 * right into the diskdir_entry for later usage in higher layers.
164 * returns: new item, or null on error (setting errno)
165 */
166zzip__new__ ZZIP_MEM_ENTRY *
167zzip_mem_entry_new(ZZIP_DISK * disk, ZZIP_DISK_ENTRY * entry)
168{
169    if (! disk || ! entry)
170        { errno=EINVAL; return 0; }
171    ___ ZZIP_MEM_ENTRY *item = calloc(1, sizeof(*item));
172    if (! item)
173        return 0;               /* errno=ENOMEM; */
174    ___ struct zzip_file_header *header =
175        zzip_disk_entry_to_file_header(disk, entry);
176    /*  there is a number of duplicated information in the file header
177     *  or the disk entry block. Theoretically some part may be missing
178     *  that exists in the other, ... but we will prefer the disk entry.
179     */
180    item->zz_comment = zzip_disk_entry_strdup_comment(disk, entry);
181    item->zz_name = zzip_disk_entry_strdup_name(disk, entry);
182    item->zz_data = zzip_file_header_to_data(header);
183    item->zz_flags = zzip_disk_entry_get_flags(entry);
184    item->zz_compr = zzip_disk_entry_get_compr(entry);
185    item->zz_mktime = zzip_disk_entry_get_mktime(entry);
186    item->zz_crc32 = zzip_disk_entry_get_crc32(entry);
187    item->zz_csize = zzip_disk_entry_get_csize(entry);
188    item->zz_usize = zzip_disk_entry_get_usize(entry);
189    item->zz_diskstart = zzip_disk_entry_get_diskstart(entry);
190    item->zz_filetype = zzip_disk_entry_get_filetype(entry);
191
192    {                           /* copy the extra blocks to memory as well */
193        int /*            */ ext1 = zzip_disk_entry_get_extras(entry);
194        char *_zzip_restrict ptr1 = zzip_disk_entry_to_extras(entry);
195        int /*            */ ext2 = zzip_file_header_get_extras(header);
196        char *_zzip_restrict ptr2 = zzip_file_header_to_extras(header);
197
198        if (ext1)
199        {
200            void *mem = malloc(ext1 + 2);
201            item->zz_ext[1] = mem;
202            memcpy(mem, ptr1, ext1);
203            ((char *) (mem))[ext1 + 0] = 0;
204            ((char *) (mem))[ext1 + 1] = 0;
205        }
206        if (ext2)
207        {
208            void *mem = malloc(ext2 + 2);
209            item->zz_ext[2] = mem;
210            memcpy(mem, ptr2, ext2);
211            ((char *) (mem))[ext2 + 0] = 0;
212            ((char *) (mem))[ext2 + 1] = 0;
213        }
214    }
215    {
216        /* override sizes/offsets with zip64 values for largefile support */
217        zzip_extra_zip64 *block = (zzip_extra_zip64 *)
218            zzip_mem_entry_extra_block(item, ZZIP_EXTRA_zip64);
219        if (block)
220        {
221            item->zz_usize = __zzip_get64(block->z_usize);
222            item->zz_csize = __zzip_get64(block->z_csize);
223            item->zz_offset = __zzip_get64(block->z_offset);
224            item->zz_diskstart = __zzip_get32(block->z_diskstart);
225        }
226    }
227    /* NOTE:
228     * All information from the central directory entry is now in memory.
229     * Effectivly that allows us to modify it and write it back to disk.
230     */
231    return item;
232    ____;
233    ____;
234}
235
236/* find an extra block for the given datatype code.
237 * We assume that the central directory has been preparsed to memory.
238 */
239ZZIP_EXTRA_BLOCK *
240zzip_mem_entry_extra_block(ZZIP_MEM_ENTRY * entry, short datatype)
241{
242    int i = 2;
243    while (1)
244    {
245        ZZIP_EXTRA_BLOCK *ext = entry->zz_ext[i];
246        if (ext)
247        {
248            while (*(short *) (ext->z_datatype))
249            {
250                if (datatype == zzip_extra_block_get_datatype(ext))
251                {
252                    return ext;
253                }
254                ___ char *e = (char *) ext;
255                e += zzip_extra_block_headerlength;
256                e += zzip_extra_block_get_datasize(ext);
257                ext = (void *) e;
258                ____;
259            }
260        }
261        if (! i)
262            return 0;
263        i--;
264    }
265}
266
267void
268zzip_mem_entry_free(ZZIP_MEM_ENTRY * _zzip_restrict item)
269{
270    if (item)
271    {
272	/* *INDENT-OFF* */
273	if (item->zz_ext[0]) free (item->zz_ext[0]);
274	if (item->zz_ext[1]) free (item->zz_ext[1]);
275	if (item->zz_ext[2]) free (item->zz_ext[2]);
276	if (item->zz_comment) free (item->zz_comment);
277	if (item->zz_name) free (item->zz_name);
278	free (item);
279	/* *INDENT-ON* */
280    }
281}
282
283void
284zzip_mem_disk_unload(ZZIP_MEM_DISK * dir)
285{
286    ZZIP_MEM_ENTRY *item = dir->list;
287    while (item)
288    {
289        ZZIP_MEM_ENTRY *next = item->zz_next;
290        zzip_mem_entry_free(item);
291        item = next;
292    }
293    dir->list = dir->last = 0;
294    zzip_disk_close(dir->disk);
295    dir->disk = 0;
296}
297
298void
299zzip_mem_disk_close(ZZIP_MEM_DISK * _zzip_restrict dir)
300{
301    if (dir)
302    {
303        zzip_mem_disk_unload(dir);
304        zzip_disk_close(dir->disk);
305        free(dir);
306    }
307}
308
309#if 0
310static void
311foo(short zz_datatype)
312{
313    switch (zz_datatype)
314    {
315    /* *INDENT-OFF* */
316    case 0x0001: /* ZIP64 extended information extra field */
317    case 0x0007: /* AV Info */
318    case 0x0008: /* Reserved for future Unicode file name data (PFS) */
319    case 0x0009: /* OS/2 */
320    case 0x000a: /* NTFS */
321    case 0x000c: /* OpenVMS */
322    case 0x000d: /* Unix */
323    case 0x000e: /* Reserved for file stream and fork descriptors */
324    case 0x000f: /* Patch Descriptor */
325    case 0x0014: /* PKCS#7 Store for X.509 Certificates */
326    case 0x0015: /* X.509 Certificate ID and Signature for file */
327    case 0x0016: /* X.509 Certificate ID for Central Directory */
328    case 0x0017: /* Strong Encryption Header */
329    case 0x0018: /* Record Management Controls */
330    case 0x0019: /* PKCS#7 Encryption Recipient Certificate List */
331    case 0x0065: /* IBM S/390, AS/400 attributes - uncompressed */
332    case 0x0066: /* Reserved for IBM S/390, AS/400 attr - compressed */
333    case 0x07c8: /* Macintosh */
334    case 0x2605: /* ZipIt Macintosh */
335    case 0x2705: /* ZipIt Macintosh 1.3.5+ */
336    case 0x2805: /* ZipIt Macintosh 1.3.5+ */
337    case 0x334d: /* Info-ZIP Macintosh */
338    case 0x4341: /* Acorn/SparkFS  */
339    case 0x4453: /* Windows NT security descriptor (binary ACL) */
340    case 0x4704: /* VM/CMS */
341    case 0x470f: /* MVS */
342    case 0x4b46: /* FWKCS MD5 (see below) */
343    case 0x4c41: /* OS/2 access control list (text ACL) */
344    case 0x4d49: /* Info-ZIP OpenVMS */
345    case 0x4f4c: /* Xceed original location extra field */
346    case 0x5356: /* AOS/VS (ACL) */
347    case 0x5455: /* extended timestamp */
348    case 0x554e: /* Xceed unicode extra field */
349    case 0x5855: /* Info-ZIP Unix (original, also OS/2, NT, etc) */
350    case 0x6542: /* BeOS/BeBox */
351    case 0x756e: /* ASi Unix */
352    case 0x7855: /* Info-ZIP Unix (new) */
353    case 0xfd4a: /* SMS/QDOS */
354    /* *INDENT-ON* */
355    }
356}
357#endif
358
359ZZIP_MEM_ENTRY *
360zzip_mem_disk_findfile(ZZIP_MEM_DISK * dir,
361                       char *filename, ZZIP_MEM_ENTRY * after,
362                       zzip_strcmp_fn_t compare)
363{
364    ZZIP_MEM_ENTRY *entry = (! after ? dir->list : after->zz_next);
365    if (! compare)
366        compare = (zzip_strcmp_fn_t) (strcmp);
367    for (; entry; entry = entry->zz_next)
368    {
369        if (! compare(filename, entry->zz_name))
370        {
371            return entry;
372        }
373    }
374    return 0;
375}
376
377ZZIP_MEM_ENTRY *
378zzip_mem_disk_findmatch(ZZIP_MEM_DISK * dir,
379                        char *filespec, ZZIP_MEM_ENTRY * after,
380                        zzip_fnmatch_fn_t compare, int flags)
381{
382    ZZIP_MEM_ENTRY *entry = (! after ? dir->list : after->zz_next);
383    if (! compare)
384        compare = (zzip_fnmatch_fn_t) _zzip_fnmatch;
385    for (; entry; entry = entry->zz_next)
386    {
387        if (! compare(filespec, entry->zz_name, flags))
388        {
389            return entry;
390        }
391    }
392    return 0;
393}
394
395zzip__new__ ZZIP_MEM_DISK_FILE *
396zzip_mem_entry_fopen(ZZIP_MEM_DISK * dir, ZZIP_MEM_ENTRY * entry)
397{
398    /* keep this in sync with zzip_disk_entry_fopen */
399    ZZIP_DISK_FILE *file = malloc(sizeof(ZZIP_MEM_DISK_FILE));
400    if (! file)
401        return file;
402    file->buffer = dir->disk->buffer;
403    file->endbuf = dir->disk->endbuf;
404    file->avail = zzip_mem_entry_usize(entry);
405
406    if (! file->avail || zzip_mem_entry_data_stored(entry))
407        { file->stored = zzip_mem_entry_to_data (entry); return file; }
408
409    file->stored = 0;
410    file->zlib.opaque = 0;
411    file->zlib.zalloc = Z_NULL;
412    file->zlib.zfree = Z_NULL;
413    file->zlib.avail_in = zzip_mem_entry_csize(entry);
414    file->zlib.next_in = zzip_mem_entry_to_data(entry);
415
416    if (! zzip_mem_entry_data_deflated(entry) ||
417        inflateInit2(&file->zlib, -MAX_WBITS) != Z_OK)
418        { free (file); return 0; }
419
420    return file;
421}
422
423zzip__new__ ZZIP_MEM_DISK_FILE *
424zzip_mem_disk_fopen(ZZIP_MEM_DISK * dir, char *filename)
425{
426    ZZIP_MEM_ENTRY *entry = zzip_mem_disk_findfile(dir, filename, 0, 0);
427    if (! entry)
428        return 0;
429    else
430        return zzip_mem_entry_fopen(dir, entry);
431}
432
433_zzip_size_t
434zzip_mem_disk_fread(void *ptr, _zzip_size_t size, _zzip_size_t nmemb,
435                    ZZIP_MEM_DISK_FILE * file)
436{
437    return zzip_disk_fread(ptr, size, nmemb, file);
438}
439
440int
441zzip_mem_disk_fclose(ZZIP_MEM_DISK_FILE * file)
442{
443    return zzip_disk_fclose(file);
444}
445
446int
447zzip_mem_disk_feof(ZZIP_MEM_DISK_FILE * file)
448{
449    return zzip_disk_feof(file);
450}
451
452/* convert dostime of entry to unix time_t */
453long
454zzip_disk_entry_get_mktime(ZZIP_DISK_ENTRY * entry)
455{
456    uint16_t dostime = ZZIP_GET16(entry->z_dostime.time);
457    uint16_t dosdate = ZZIP_GET16(entry->z_dostime.date);
458    struct tm date;
459    date.tm_sec = (dostime) & 0x1F;     /* bits 0..4 */
460    date.tm_min = (dostime >> 5) & 0x3F;        /* bits 5..10 */
461    date.tm_hour = (dostime >> 11);     /* bits 11..15 */
462    date.tm_mday = (dosdate) & 0x1F;    /* bits 16..20 */
463    date.tm_mon = (dosdate >> 5) & 0xF; /* bits 21..24 */
464    date.tm_year = (dosdate >> 9) + 80; /* bits 25..31 */
465    return mktime(&date);       /* well, unix has that function... */
466}