Beispiel #1
0
/** => zzip_entry_findfile
 *
 * This function is the first call of all the zip access functions here.
 * It contains the code to find the first entry of the zip central directory.
 * Here we require the stdio handle to represent a real zip file where the
 * disk_trailer is _last_ in the file area, so that its position would be at
 * a fixed offset from the end of the file area if not for the comment field
 * allowed to be of variable length (which needs us to do a little search
 * for the disk_tailer). However, in this simple implementation we disregard
 * any disk_trailer info telling about multidisk archives, so we just return
 * a pointer to the first entry in the zip central directory of that file.
 *
 * For an actual means, we are going to search backwards from the end
 * of the mmaped block looking for the PK-magic signature of a
 * disk_trailer. If we see one then we check the rootseek value to
 * find the first disk_entry of the root central directory. If we find
 * the correct PK-magic signature of a disk_entry over there then we
 * assume we are done and we are going to return a pointer to that label.
 *
 * The return value is a pointer to the first zzip_disk_entry being checked
 * to be within the bounds of the file area specified by the arguments. If
 * no disk_trailer was found then null is returned, and likewise we only
 * accept a disk_trailer with a seekvalue that points to a disk_entry and
 * 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.
 */
zzip__new__ ZZIP_ENTRY *
zzip_entry_findfirst(FILE * disk)
{
    if (! disk)
        return 0;
    if (fseeko(disk, 0, SEEK_END) == -1)
        return 0;
    ___ zzip_off_t disksize = ftello(disk);
    if (disksize < (zzip_off_t) sizeof(struct zzip_disk_trailer))
        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;
    ___ unsigned char *buffer = malloc(pagesize);
    if (! buffer)
        goto nomem;

    assert(pagesize / 2 > (zzip_off_t) sizeof(struct zzip_disk_trailer));
    /* 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);
    ___ zzip_off_t mapsize = disksize - mapoffs;
    if (mapoffs && mapsize < pagesize / 2)
    {
        mapoffs -= pagesize / 2;
        mapsize += pagesize / 2;
    }
    while (1)
    {
        if (fseeko(disk, mapoffs, SEEK_SET) == -1)
            goto error;
        if (fread(buffer, 1, mapsize, disk) != mapsize)
            goto error;
        ___ unsigned char *p =
            buffer + mapsize - sizeof(struct zzip_disk_trailer);
        for (; p >= buffer; p--)
        {
            zzip_off_t root;    /* (struct zzip_disk_entry*) */
            if (zzip_disk_trailer_check_magic(p))
            {
                root = zzip_disk_trailer_rootseek((struct zzip_disk_trailer *)
                                                  p);
                if (root > disksize - (long) sizeof(struct zzip_disk_trailer))
                {
                    /* first disk_entry is after the disk_trailer? can't be! */
                    struct zzip_disk_trailer *trailer =
                        (struct zzip_disk_trailer *) p;
                    zzip_off_t rootsize = zzip_disk_trailer_rootsize(trailer);
                    if (rootsize > mapoffs)
                        continue;
                    /* a common brokeness that can be fixed: we just assume the
                     * central directory was written directly before : */
                    root = mapoffs - rootsize;
                }
            } else if (zzip_disk64_trailer_check_magic(p))
            {
                struct zzip_disk64_trailer *trailer =
                    (struct zzip_disk64_trailer *) p;
                if (sizeof(zzip_off_t) < 8)
                    return 0;
                root = zzip_disk64_trailer_rootseek(trailer);
            } else
                continue;

            assert(0 <= root && root < mapsize);
            if (fseeko(disk, root, SEEK_SET) == -1)
                goto error;
            if (fread(disk_(entry), 1, sizeof(*disk_(entry)), disk)
                    != sizeof(*disk_(entry))) goto error;
            if (zzip_disk_entry_check_magic(entry))
            {
                free(buffer);
                entry->headseek = root;
                entry->diskfile = disk;
                entry->disksize = disksize;
                if (prescan_entry(entry))
                    goto nomem;
                return entry;
            }
        }
        ____;
        if (! mapoffs)
            break;
        assert(mapsize >= pagesize / 2);
        mapoffs -= pagesize / 2;        /* mapsize += pagesize/2; */
        mapsize = pagesize;     /* if (mapsize > pagesize) ... */
        if (disksize - mapoffs > 64 * 1024)
            break;
    }
  error:
    free(buffer);
  nomem:
    free(entry);
    ____;
    ____;
    ____;
    ____;
    ____;
    ____;
    return 0;
}
Beispiel #2
0
/** => zzip_entry_findfile
 *
 * This function is the first call of all the zip access functions here.
 * It contains the code to find the first entry of the zip central directory. 
 * Here we require the stdio handle to represent a real zip file where the
 * disk_trailer is _last_ in the file area, so that its position would be at 
 * a fixed offset from the end of the file area if not for the comment field 
 * allowed to be of variable length (which needs us to do a little search
 * for the disk_tailer). However, in this simple implementation we disregard
 * any disk_trailer info telling about multidisk archives, so we just return
 * a pointer to the first entry in the zip central directory of that file.
 * 
 * For an actual means, we are going to search backwards from the end 
 * of the mmaped block looking for the PK-magic signature of a 
 * disk_trailer. If we see one then we check the rootseek value to
 * find the first disk_entry of the root central directory. If we find
 * the correct PK-magic signature of a disk_entry over there then we 
 * assume we are done and we are going to return a pointer to that label.
 *
 * The return value is a pointer to the first zzip_disk_entry being checked
 * to be within the bounds of the file area specified by the arguments. If
 * no disk_trailer was found then null is returned, and likewise we only 
 * accept a disk_trailer with a seekvalue that points to a disk_entry and 
 * 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.
 */
ZZIP_ENTRY* _zzip_restrict
zzip_entry_findfirst(FILE* disk)
{
    if (! disk) return 0;
    fseeko (disk, 0, SEEK_END);
    ___ zzip_off_t disksize = ftello (disk);
    if (disksize < (zzip_off_t) sizeof(struct zzip_disk_trailer)) 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;
    ___ char* buffer = malloc (pagesize);             if (! buffer) goto nomem;

    assert (pagesize/2 > (zzip_off_t) sizeof (struct zzip_disk_trailer));
    /* 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);
    ___ zzip_off_t mapsize = disksize - mapoffs;
    if (mapoffs && mapsize < pagesize/2) { 
	mapoffs -= pagesize/2; mapsize += pagesize/2; }
    while(1) 
    {
	fseeko (disk, mapoffs, SEEK_SET);
	fread (buffer, 1, mapsize, disk);
	___ char* p = buffer + mapsize - sizeof(struct zzip_disk_trailer);
	for (; p >= buffer ; p--)
	{
	    if (! zzip_disk_trailer_check_magic(p)) continue;
	    ___ zzip_off_t root = 
		zzip_disk_trailer_rootseek ((struct zzip_disk_trailer*)p);
	    if ((char*) root > p) 
	    {   /* the first disk_entry is after the disk_trailer? can't be! */
		zzip_off_t rootsize =
		    zzip_disk_trailer_rootsize ((struct zzip_disk_trailer*)p);
		if (rootsize > mapoffs) continue;
		/* a common brokeness that can be fixed: we just assume that 
		 * the central directory was written directly before : */
		root = mapoffs - rootsize;
	    }
	    assert (0 <= root && root < mapsize);
	    fseeko (disk, root, SEEK_SET);
	    fread (disk_(entry), 1, sizeof(*disk_(entry)), disk);
	    if (zzip_disk_entry_check_magic(entry)) 
	    {
		free (buffer);
		entry->headseek = root;
		entry->diskfile = disk;
		entry->disksize = disksize;
		___ zzip_size_t tailsize = 
		    zzip_disk_entry_sizeof_tails (disk_(entry));
		if (!( entry->tail = malloc (tailsize+1) )) goto nomem;
		fread (entry->tail, 1, tailsize, disk);
		entry->tailalloc = tailsize+1;
		return entry; ____;
	    }
	    ____;
	} ____;
	if (! mapoffs) break;             assert (mapsize >= pagesize/2);
	mapoffs -= pagesize/2;            /* mapsize += pagesize/2; */
	mapsize = pagesize;               /* if (mapsize > pagesize) ... */
	if (disksize - mapoffs > 64*1024) break;
    }
    free (buffer);
 nomem:
    free (entry);                         ____;____;____;____;____;____;
    return 0;
}