diff options
Diffstat (limited to 'Build/source/libs/zziplib/zziplib-src/zzip/fseeko.c')
-rw-r--r-- | Build/source/libs/zziplib/zziplib-src/zzip/fseeko.c | 323 |
1 files changed, 253 insertions, 70 deletions
diff --git a/Build/source/libs/zziplib/zziplib-src/zzip/fseeko.c b/Build/source/libs/zziplib/zziplib-src/zzip/fseeko.c index d99067a0b4f..ba19b436fb0 100644 --- a/Build/source/libs/zziplib/zziplib-src/zzip/fseeko.c +++ b/Build/source/libs/zziplib/zziplib-src/zzip/fseeko.c @@ -24,12 +24,7 @@ * Author: * Guido Draheim <guidod@gmx.de> * - * Copyright (c) 2003,2004 Guido Draheim - * All rights reserved, - * use under the restrictions of the - * Lesser GNU General Public License - * or alternatively the restrictions - * of the Mozilla Public License 1.1 + * Copyright (c) Guido Draheim, use under copyleft (LGPL,MPL) */ #define _LARGEFILE_SOURCE 1 @@ -41,7 +36,6 @@ #include <zzip/__mmap.h> #include <zzip/__fnmatch.h> -#include <assert.h> #include <stdlib.h> #include <sys/stat.h> @@ -83,6 +77,18 @@ * the sys/mmap interface we have to guess a good value here: */ #define PAGESIZE 8192 +#ifdef DEBUG +#define debug1(msg) do { fprintf(stderr, "%s : " msg "\n", __func__); } while(0) +#define debug2(msg, arg1) do { fprintf(stderr, "%s : " msg "\n", __func__, arg1); } while(0) +#define debug3(msg, arg1, arg2) do { fprintf(stderr, "%s : " msg "\n", __func__, arg1, arg2); } while(0) +#define debug4(msg, arg1, arg2, arg3) do { fprintf(stderr, "%s : " msg "\n", __func__, arg1, arg2, arg3); } while(0) +#else +#define debug1(msg) +#define debug2(msg, arg1) +#define debug3(msg, arg1, arg2) +#define debug4(msg, arg1, arg2, arg3) +#endif + /* ====================================================================== */ /* helper functions */ @@ -92,21 +98,42 @@ * the zip disk of the given "entry". The returned off_t points to the * end of the file_header where the current fseek pointer has stopped. * This is used to immediatly parse out any filename/extras block following - * the file_header. The return value is null on error. + * the file_header. + * + * Returns zero on error. (errno = EINVAL|EBADMSG|EBADF|EIO) */ static zzip_off_t zzip_entry_fread_file_header(ZZIP_ENTRY * entry, struct zzip_file_header *file_header) { if (! entry || ! file_header) + { + errno = EINVAL; return 0; + } ___ zzip_off_t offset = zzip_disk_entry_fileoffset(disk_(entry)); if (0 > offset || offset >= entry->disksize) + { + errno = EBADMSG; return 0; + } - if (fseeko(entry->diskfile, offset, SEEK_SET) == -1) return 0; - return (fread(file_header, sizeof(*file_header), 1, entry->diskfile) - ? offset + sizeof(*file_header) : 0); + if (fseeko(entry->diskfile, offset, SEEK_SET) == -1) + { + debug2("fseeko failed: %s", strerror(errno)); + return 0; /* EBADF */ + } + + ___ zzip_size_t n = fread(file_header, 1, sizeof(*file_header), entry->diskfile); + if (n < sizeof(*file_header)) + { + debug4("fread failed: at offset %llu got %i instead of %i", + (long long) offset, n, sizeof(*file_header)); + errno = ferror(entry->diskfile) ? EBADF : EIO; + return 0; + } + ____; + return offset + sizeof(*file_header); ____; } @@ -116,20 +143,29 @@ zzip_entry_fread_file_header(ZZIP_ENTRY * entry, * file referenced by the given zzip_entry. It requires an intermediate * check of the file_header structure (i.e. it reads it from disk). After * this call, the contained diskfile readposition is already set to the - * data_offset returned here. On error -1 is returned. + * data_offset returned here. + * + * Returns -1 on error. (errno = EINVAL|EBADMSG) */ zzip_off_t zzip_entry_data_offset(ZZIP_ENTRY * entry) { struct zzip_file_header file_header; if (! entry) + { + errno = EINVAL; return -1; + } ___ zzip_off_t offset = zzip_entry_fread_file_header(entry, &file_header); if (! offset) - return -1; + { + return -1; /* EBADMSG */ + } offset += zzip_file_header_sizeof_tails(&file_header); if (fseeko(entry->diskfile, offset, SEEK_SET) == -1) - return -1; + { + return -1; /* EBADF */ + } return offset; ____; } @@ -140,19 +176,26 @@ zzip_entry_data_offset(ZZIP_ENTRY * entry) * with libc we need it that way. Secondly, the filename SHOULD be present * in the zip central directory but if not then we fallback to the filename * given in the file_header of each compressed data portion. + * + * returns: new string buffer, null on error (errno = EINVAL|ENOMEM|EBADMSG) */ zzip__new__ char * zzip_entry_strdup_name(ZZIP_ENTRY * entry) { if (! entry) + { + errno = EINVAL; return 0; + } ___ zzip_size_t len; if ((len = zzip_disk_entry_namlen(disk_(entry)))) { char *name = malloc(len + 1); if (! name) - return 0; + { + return 0; /* ENOMEM */ + } memcpy(name, entry->tail, len); name[len] = '\0'; return name; @@ -163,17 +206,20 @@ zzip_entry_strdup_name(ZZIP_ENTRY * entry) { char *name = malloc(len + 1); if (! name) { + return 0; /* ENOMEM */ + } + ___ zzip_size_t n = fread(name, 1, len, entry->diskfile); + if (n < len) + { + errno = ferror(entry->diskfile) ? EBADF : EIO; + free (name); return 0; - } else { - zzip_size_t n = fread(name, 1, len, entry->diskfile); - if (n != len) { - free (name); - return 0; - } - name[n] = '\0'; - return name; } + name[n] = '\0'; + return name; + ____; } + errno = EBADMSG; return 0; ____; ____; @@ -182,7 +228,8 @@ zzip_entry_strdup_name(ZZIP_ENTRY * entry) static int prescan_entry(ZZIP_ENTRY * entry) { - assert(entry); + if (! entry) + return EINVAL; ___ zzip_off_t tailsize = zzip_disk_entry_sizeof_tails(disk_(entry)); if (tailsize + 1 > entry->tailalloc) { @@ -193,11 +240,16 @@ prescan_entry(ZZIP_ENTRY * entry) entry->tailalloc = tailsize + 1; } # ifdef SIZE_MAX /* from stdint.h */ - if (tailsize > (zzip_off_t)(SIZE_MAX)) { return EFBIG; } + if ((unsigned long long)(tailsize) > (unsigned long long)(SIZE_MAX)) + { + debug3("tailsize %llu bigger than sizemax %llu", (long long)(tailsize), (long long)(SIZE_MAX)); + return EFBIG; + } # endif ___ zzip_size_t readsize = fread(entry->tail, 1, tailsize, entry->diskfile); /* name + comment + extras */ if ((zzip_off_t)readsize != tailsize) { + debug1("read to data"); return errno; } else { return 0; @@ -207,7 +259,8 @@ prescan_entry(ZZIP_ENTRY * entry) static void prescan_clear(ZZIP_ENTRY * entry) { - assert(entry); + if (! entry) + return; if (entry->tail) free(entry->tail); entry->tail = 0; @@ -242,27 +295,42 @@ prescan_clear(ZZIP_ENTRY * entry) * both parts have valid PK-magic parts. Beyond some sanity check we try to * catch a common brokeness with zip archives that still allows us to find * the start of the zip central directory. + * + * Returns null on error (errno = EINVAL|ENOMEM|EBADMSG|EBADF|ENOENT) */ zzip__new__ ZZIP_ENTRY * zzip_entry_findfirst(FILE * disk) { if (! disk) + { + errno = EINVAL; return 0; + } if (fseeko(disk, 0, SEEK_END) == -1) - return 0; + { + printf("fseeko failed: %s", strerror(errno)); + return 0; /* EBADF */ + } ___ zzip_off_t disksize = ftello(disk); if (disksize < (zzip_off_t) sizeof(struct zzip_disk_trailer)) + { + errno = EBADMSG; return 0; + } /* we read out chunks of 8 KiB in the hope to match disk granularity */ ___ zzip_off_t pagesize = PAGESIZE; /* getpagesize() */ ___ ZZIP_ENTRY *entry = malloc(sizeof(*entry)); if (! entry) - return 0; + goto error0; /* ENOMEM */ ___ unsigned char *buffer = malloc(pagesize); if (! buffer) - goto nomem; + goto error1; /* ENOMEM */ - assert(pagesize / 2 > (zzip_off_t) sizeof(struct zzip_disk_trailer)); + if (pagesize / 2 <= (zzip_off_t) sizeof(struct zzip_disk_trailer)) + { + errno = EBADMSG; + goto error2; + } /* at each step, we will fread a pagesize block which overlaps with the * previous read by means of pagesize/2 step at the end of the while(1) */ ___ zzip_off_t mapoffs = disksize & ~(pagesize - 1); @@ -272,13 +340,21 @@ zzip_entry_findfirst(FILE * disk) mapoffs -= pagesize / 2; mapsize += pagesize / 2; } - assert(mapsize < 3*8192); + if (mapsize >= 3*8192) + { + errno = EBADMSG; + goto error2; + } while (1) { if (fseeko(disk, mapoffs, SEEK_SET) == -1) - goto error; - if (fread(buffer, 1, mapsize, disk) != (zzip_size_t)mapsize) - goto error; + goto error2; /* EBADF */ + if (fread(buffer, 1, mapsize, disk) < (zzip_size_t)mapsize) + { + errno = ferror(disk) ? EBADF : EIO; + debug1("in fread"); + goto error2; + } ___ unsigned char *p = buffer + mapsize - sizeof(struct zzip_disk_trailer); for (; p >= buffer; p--) @@ -305,39 +381,74 @@ zzip_entry_findfirst(FILE * disk) struct zzip_disk64_trailer *trailer = (struct zzip_disk64_trailer *) p; if (sizeof(zzip_off_t) < 8) - return 0; + { + debug1("disk64 trailer on non-large compile"); + errno = EFBIG; + goto error2; + } + if ((void*)(trailer + 1) > (buffer + mapsize)) + { + debug1("disk64 trailer is not complete"); + errno = EBADMSG; + goto error2; + } root = zzip_disk64_trailer_rootseek(trailer); } else continue; - assert(0 <= root && root < mapsize); + if (!(0 <= root && root < disksize)) + { + debug3("bogus rootseek value %lli (disksize %lli)", (long long)root, (long long)disksize); + errno = EBADMSG; + goto error2; + } if (fseeko(disk, root, SEEK_SET) == -1) - goto error; + { + debug2("next seeko %s", strerror(errno)); + goto error2; /* EBADF */ + } if (fread(disk_(entry), 1, sizeof(*disk_(entry)), disk) - != sizeof(*disk_(entry))) goto error; + != sizeof(*disk_(entry))) + { + debug2("next freed %s", strerror(errno)); + errno = ferror(disk) ? EBADF : EIO; + goto error2; + } if (zzip_disk_entry_check_magic(entry)) { free(buffer); entry->headseek = root; entry->diskfile = disk; entry->disksize = disksize; - if (prescan_entry(entry)) - goto nomem; + ___ int err = prescan_entry(entry); + if (err) + { + debug2("prescan %s", strerror(err)); + errno = err; + goto error2; + } return entry; + ____; } } ____; if (! mapoffs) break; - assert(mapsize >= pagesize / 2); + if (mapsize < pagesize / 2) + { + debug1("bad mapsize should not be possible"); + errno = EBADMSG; + goto error2; + } mapoffs -= pagesize / 2; /* mapsize += pagesize/2; */ mapsize = pagesize; /* if (mapsize > pagesize) ... */ if (disksize - mapoffs > 64 * 1024) break; } - error: + errno = ENOENT; /* not found */ + error2: free(buffer); - nomem: + error1: free(entry); ____; ____; @@ -345,6 +456,8 @@ zzip_entry_findfirst(FILE * disk) ____; ____; ____; + error0: + debug1("error.."); return 0; } @@ -361,25 +474,39 @@ zzip__new__ ZZIP_ENTRY * zzip_entry_findnext(ZZIP_ENTRY * _zzip_restrict entry) { if (! entry) + { + errno = EINVAL; return entry; + } if (! zzip_disk_entry_check_magic(entry)) - goto err; + goto error_EBADMSG; ___ zzip_off_t seek = entry->headseek + zzip_disk_entry_sizeto_end(disk_(entry)); if (seek + (zzip_off_t) sizeof(*disk_(entry)) > entry->disksize) - goto err; + goto error_EBADMSG; if (fseeko(entry->diskfile, seek, SEEK_SET) == -1) - goto err; + goto error; /* EBADF */ if (fread(disk_(entry), 1, sizeof(*disk_(entry)), entry->diskfile) - != sizeof(*disk_(entry))) goto err; + < sizeof(*disk_(entry))) + { + errno = ferror(entry->diskfile) ? EBADF : EIO; + goto error; + } entry->headseek = seek; if (! zzip_disk_entry_check_magic(entry)) - goto err; - if (prescan_entry(entry)) - goto err; + goto error_EBADMSG; + ___ int err = prescan_entry(entry); + if (err) + { + errno = err; + goto error; + } return entry; - err: + ____; + error_EBADMSG: + errno = EBADMSG; + error: zzip_entry_free(entry); return 0; ____; @@ -394,7 +521,10 @@ int zzip_entry_free(ZZIP_ENTRY * entry) { if (! entry) + { + errno = EINVAL; return 0; + } prescan_clear(entry); free(entry); return 1; @@ -416,7 +546,10 @@ zzip_entry_findfile(FILE * disk, char *filename, ZZIP_ENTRY * _zzip_restrict entry, zzip_strcmp_fn_t compare) { if (! filename || ! disk) + { + errno = EINVAL; return 0; + } if (! entry) entry = zzip_entry_findfirst(disk); else @@ -430,7 +563,9 @@ zzip_entry_findfile(FILE * disk, char *filename, /* filenames within zip files are often not null-terminated! */ char *realname = zzip_entry_strdup_name(entry); if (! realname) - continue; + { + return 0; /* ENOMEM|EBADMSG */ + } if (! compare(filename, realname)) { free(realname); @@ -441,6 +576,7 @@ zzip_entry_findfile(FILE * disk, char *filename, continue; } } + errno = ENOENT; return 0; } @@ -464,7 +600,10 @@ zzip_entry_findmatch(FILE * disk, char *filespec, zzip_fnmatch_fn_t compare, int flags) { if (! filespec || ! disk) + { + errno = EINVAL; return 0; + } if (! entry) entry = zzip_entry_findfirst(disk); else @@ -478,17 +617,22 @@ zzip_entry_findmatch(FILE * disk, char *filespec, /* filenames within zip files are often not null-terminated! */ char *realname = zzip_entry_strdup_name(entry); if (! realname) - continue; + { + return 0; /* ENOMEM|EBADMSG */ + } if (! compare(filespec, realname, flags)) { + debug3("compare '%s' equal with zip '%s'", filespec, realname); free(realname); return entry; } else { + debug3("compare '%s' not like zip '%s'", filespec, realname); free(realname); continue; } } + errno = ENOENT; return 0; } @@ -525,25 +669,36 @@ zzip__new__ ZZIP_ENTRY_FILE * zzip_entry_fopen(ZZIP_ENTRY * entry, int takeover) { if (! entry) + { + errno = EINVAL; return 0; + } if (! takeover) { ZZIP_ENTRY *found = malloc(sizeof(*entry)); if (! found) - return 0; + { + return 0; /* ENOMEM */ + } memcpy(found, entry, sizeof(*entry)); /* prescan_copy */ found->tail = malloc(found->tailalloc); - if (! found->tail) - { free (found); return 0; } + if (! found->tail) + { + free (found); + return 0; /* ENOMEM */ + } memcpy(found->tail, entry->tail, entry->tailalloc); entry = found; } ___ ZZIP_ENTRY_FILE *file = malloc(sizeof(*file)); if (! file) - goto fail1; + goto error1; /* ENOMEM */ file->entry = entry; if (! zzip_entry_fread_file_header(entry, &file->header)) - goto fail2; + { + debug2("file header: %s", strerror(errno)); + goto error2; /* EIO|EBADMSG */ + } file->avail = zzip_file_header_usize(&file->header); file->data = zzip_entry_data_offset(entry); file->dataoff = 0; @@ -556,26 +711,32 @@ zzip_entry_fopen(ZZIP_ENTRY * entry, int takeover) file->zlib.zalloc = Z_NULL; file->zlib.zfree = Z_NULL; - ___ zzip_off_t seek = file->data; - seek += sizeof(file->buffer); - seek -= seek & (sizeof(file->buffer) - 1); - assert(file->data < seek); /* pre-read to next PAGESIZE boundary... */ + ___ zzip_off_t size = file->avail; + if (size > sizeof(file->buffer)) + size = sizeof(file->buffer); if (fseeko(file->entry->diskfile, file->data + file->dataoff, SEEK_SET) == -1) - goto fail2; + { + debug2("file seek failed: %s", strerror(errno)); + goto error2; /* EBADF */ + } file->zlib.next_in = file->buffer; - file->zlib.avail_in = fread(file->buffer, 1, seek - file->data, + file->zlib.avail_in = fread(file->buffer, 1, size, file->entry->diskfile); file->dataoff += file->zlib.avail_in; ____; if (! zzip_file_header_data_deflated(&file->header) || inflateInit2(&file->zlib, -MAX_WBITS) != Z_OK) - goto fail2; + { + debug1("decompress failed"); + errno = EBADMSG; + goto error2; + } return file; - fail2: + error2: free(file); - fail1: + error1: zzip_entry_free(entry); return 0; ____; @@ -592,7 +753,9 @@ zzip_entry_ffile(FILE * disk, char *filename) { ZZIP_ENTRY *entry = zzip_entry_findfile(disk, filename, 0, 0); if (! entry) - return 0; + { + return 0; /* EBADMSG */ + } return zzip_entry_fopen(entry, 1); } @@ -609,13 +772,21 @@ zzip_entry_fread(void *ptr, zzip_size_t sized, zzip_size_t nmemb, ZZIP_ENTRY_FILE * file) { if (! file) + { + errno = EINVAL; return 0; + } ___ zzip_size_t size = sized * nmemb; if (! file->compressed) { if (size > file->avail) size = file->avail; - if (fread(ptr, 1, size, file->entry->diskfile) != size) return 0; + if (fread(ptr, 1, size, file->entry->diskfile) != size) + { + errno = ferror(file->entry->diskfile) ? EBADF : EIO; + debug2("uncompressed fread incomplete: %s", strerror(errno)); + return 0; + } file->dataoff += size; file->avail -= size; return size; @@ -629,6 +800,7 @@ zzip_entry_fread(void *ptr, zzip_size_t sized, zzip_size_t nmemb, if (! file->zlib.avail_in) { size = file->compressed - file->dataoff; + debug2("remaining compressed bytes: %lli", (long long)size); if (size > sizeof(file->buffer)) size = sizeof(file->buffer); /* fseek (file->data + file->dataoff, file->entry->diskfile); */ @@ -636,9 +808,13 @@ zzip_entry_fread(void *ptr, zzip_size_t sized, zzip_size_t nmemb, file->entry->diskfile); file->zlib.next_in = file->buffer; file->dataoff += file->zlib.avail_in; + debug2("remaing compressed fread %lli", (long long) file->zlib.avail_in); } if (! file->zlib.avail_in) + { + errno = EIO; return 0; + } ___ int err = inflate(&file->zlib, Z_NO_FLUSH); if (err == Z_STREAM_END) @@ -646,7 +822,11 @@ zzip_entry_fread(void *ptr, zzip_size_t sized, zzip_size_t nmemb, else if (err == Z_OK) file->avail -= file->zlib.total_out - total_old; else + { + debug1("zlib decode incomplete"); + errno = EBADMSG; return 0; + } ____; if (file->zlib.avail_out && ! file->zlib.avail_in) continue; @@ -664,7 +844,10 @@ int zzip_entry_fclose(ZZIP_ENTRY_FILE * file) { if (! file) - return 0; + { + errno = EINVAL; + return EOF; + } if (file->compressed) inflateEnd(&file->zlib); zzip_entry_free(file->entry); |