コード例 #1
0
static int
find_file(int fd, zentry *entry, const char *file_name)
{
    int	    bytes;
    int	    res;
    int	    entry_size;
    int	    read_size;
    int	    base_offset;
    Byte    *p;
    Byte    *bp;
    Byte    *buffer;
    Byte    locbuf[LOCHDR];

    if ((buffer = (Byte*)malloc(BUFSIZE)) == NULL) {
	return(-1);
    }

    p = buffer;
    bp = buffer;

    /*
     * Read the END Header, which is the starting point for ZIP files.
     * (Clearly designed to make writing a zip file easier than reading
     * one. Now isn't that precious...)
     */
    if ((base_offset = find_end(fd, bp)) == -1) {
        free(buffer);
	return (-1);
    }

    /*
     * There is a historical, but undocumented, ability to allow for
     * additional "stuff" to be prepended to the zip/jar file. It seems
     * that this has been used to prepend an actual java launcher
     * executable to the jar on Windows.  Although this is just another
     * form of statically linking a small piece of the JVM to the
     * application, we choose to continue to support it.  Note that no
     * guarantees have been made (or should be made) to the customer that
     * this will continue to work.
     *
     * Therefore, calculate the base offset of the zip file (within the
     * expanded file) by assuming that the central directory is followed
     * immediately by the end record.
     */
    base_offset = base_offset - ENDSIZ(p) - ENDOFF(p);

    /*
     * The END Header indicates the start of the Central Directory
     * Headers. Remember that the desired Central Directory Header (CEN)
     * will almost always be the second one and the first one is a small
     * directory entry ("META-INF/"). Keep the code optimized for
     * that case.
     *
     * Begin by seeking to the beginning of the Central Directory and
     * reading in the first buffer full of bits.
     */
    if (lseek(fd, base_offset + ENDOFF(p), SEEK_SET) < (off_t)0) {
        free(buffer);
	return (-1);
    }
    if ((bytes = read(fd, bp, MINREAD)) < 0) {
        free(buffer);
	return (-1);
    }

    /*
     * Loop through the Central Directory Headers. Note that a valid zip/jar
     * must have an ENDHDR (with ENDSIG) after the Central Directory.
     */
    while (GETSIG(p) == CENSIG) {

	/*
	 * If a complete header isn't in the buffer, shift the contents
	 * of the buffer down and refill the buffer.  Note that the check
	 * for "bytes < CENHDR" must be made before the test for the entire
	 * size of the header, because if bytes is less than CENHDR, the
	 * actual size of the header can't be determined. The addition of
	 * SIGSIZ guarantees that the next signature is also in the buffer
	 * for proper loop termination.
	 */
	if (bytes < CENHDR) {
	    p = memmove(bp, p, bytes);
	    if ((res = read(fd, bp + bytes, MINREAD)) <= 0) {
	      	free(buffer);
		return (-1);
	    }
	    bytes += res;
	}
	entry_size = CENHDR + CENNAM(p) + CENEXT(p) + CENCOM(p);
	if (bytes < entry_size + SIGSIZ) {
	    if (p != bp)
		p = memmove(bp, p, bytes);
	    read_size = entry_size - bytes + SIGSIZ;
	    read_size = (read_size < MINREAD) ? MINREAD : read_size;
	    if ((res = read(fd, bp + bytes,  read_size)) <= 0) {
	      	free(buffer);
		return (-1);
 	    }
	    bytes += res;
	}

	/*
	 * Check if the name is the droid we are looking for; the jar file
	 * manifest.  If so, build the entry record from the data found in
	 * the header located and return success.
	 */
        if (CENNAM(p) == strlen(file_name) &&
          memcmp((p + CENHDR), file_name, strlen(file_name)) == 0) {
	    if (lseek(fd, base_offset + CENOFF(p), SEEK_SET) < (off_t)0) {
    		free(buffer);
		return (-1);
	    }
	    if (read(fd, locbuf, LOCHDR) < 0) {
    		free(buffer);
		return (-1);
	    }
	    if (GETSIG(locbuf) != LOCSIG) {
    		free(buffer);
		return (-1);
	    }
	    entry->isize = CENLEN(p);
	    entry->csize = CENSIZ(p);
	    entry->offset = base_offset + CENOFF(p) + LOCHDR +
		LOCNAM(locbuf) + LOCEXT(locbuf);
	    entry->how = CENHOW(p);
	    free(buffer);
	    return (0);
	}

	/*
	 * Point to the next entry and decrement the count of valid remaining
	 * bytes.
	 */
	bytes -= entry_size;
	p += entry_size;
    }
    free(buffer);
    return (-1);	/* Fell off the end the loop without a Manifest */
}
コード例 #2
0
/*
 * Return a new initialized jzentry corresponding to a given hash cell.
 * In case of error, returns NULL.
 * We already sanity-checked all the CEN headers for ZIP format errors
 * in readCEN(), so we don't check them again here.
 * The ZIP lock should be held here.
 */
static jzentry *
newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint)
{
    jlong locoff;
    jint nlen, elen, clen;
    jzentry *ze;
    char *cen;

    if ((ze = (jzentry *) malloc(sizeof(jzentry))) == NULL) return NULL;
    ze->name    = NULL;
    ze->extra   = NULL;
    ze->comment = NULL;

#ifdef USE_MMAP
    if (zip->usemmap) {
        cen = (char*) zip->maddr + zc->cenpos - zip->offset;
    } else
#endif
    {
        if (accessHint == ACCESS_RANDOM)
            cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE);
        else
            cen = sequentialAccessReadCENHeader(zip, zc->cenpos);
        if (cen == NULL) goto Catch;
    }

    nlen      = CENNAM(cen);
    elen      = CENEXT(cen);
    clen      = CENCOM(cen);
    ze->time  = CENTIM(cen);
    ze->size  = CENLEN(cen);
    ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen);
    ze->crc   = CENCRC(cen);
    locoff    = CENOFF(cen);
    ze->pos   = -(zip->locpos + locoff);
    ze->flag  = CENFLG(cen);

    if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch;
    memcpy(ze->name, cen + CENHDR, nlen);
    ze->name[nlen] = '\0';
    if (elen > 0) {
        char *extra = cen + CENHDR + nlen;

        /* This entry has "extra" data */
        if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch;
        ze->extra[0] = (unsigned char) elen;
        ze->extra[1] = (unsigned char) (elen >> 8);
        memcpy(ze->extra+2, extra, elen);
        if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL ||
            locoff == ZIP64_MAGICVAL) {
            jint off = 0;
            while ((off + 4) < elen) {    // spec: HeaderID+DataSize+Data
                jint sz = SH(extra, off + 2);
                if (SH(extra, off) == ZIP64_EXTID) {
                    off += 4;
                    if (ze->size == ZIP64_MAGICVAL) {
                        // if invalid zip64 extra fields, just skip
                        if (sz < 8 || (off + 8) > elen)
                            break;
                        ze->size = LL(extra, off);
                        sz -= 8;
                        off += 8;
                    }
                    if (ze->csize == ZIP64_MAGICVAL) {
                        if (sz < 8 || (off + 8) > elen)
                            break;
                        ze->csize = LL(extra, off);
                        sz -= 8;
                        off += 8;
                    }
                    if (locoff == ZIP64_MAGICVAL) {
                        if (sz < 8 || (off + 8) > elen)
                            break;
                        ze->pos = -(zip->locpos +  LL(extra, off));
                        sz -= 8;
                        off += 8;
                    }
                    break;
                }
                off += (sz + 4);
            }
        }
    }
コード例 #3
0
/*
 * Locate the manifest file with the zip/jar file.
 *
 *      fd:     File descriptor of the jar file.
 *      entry:  To be populated with the information necessary to perform
 *              the inflation (the compressed and uncompressed sizes and
 *              the offset in the file where the compressed data is located).
 *
 * Returns zero upon success. Returns a negative value upon failure.
 *
 * The buffer for reading the Central Directory if the zip/jar file needs
 * to be large enough to accommodate the largest possible single record
 * and the signature of the next record which is:
 *
 *      3*2**16 + CENHDR + SIGSIZ
 *
 * Each of the three variable sized fields (name, comment and extension)
 * has a maximum possible size of 64k.
 *
 * Typically, only a small bit of this buffer is used with bytes shuffled
 * down to the beginning of the buffer.  It is one thing to allocate such
 * a large buffer and another thing to actually start faulting it in.
 *
 * In most cases, all that needs to be read are the first two entries in
 * a typical jar file (META-INF and META-INF/MANIFEST.MF). Keep this factoid
 * in mind when optimizing this code.
 */
static int
find_file(int fd, zentry *entry, const char *file_name)
{
    int     bytes;
    int     res;
    int     entry_size;
    int     read_size;
    jlong   base_offset;
    Byte    *p;
    Byte    *bp;
    Byte    *buffer;
    Byte    locbuf[LOCHDR];

    if ((buffer = (Byte*)malloc(BUFSIZE)) == NULL) {
        return(-1);
    }

    bp = buffer;
    base_offset = compute_cen(fd, bp);
    if (base_offset == -1) {
        free(buffer);
        return -1;
    }

    if ((bytes = read(fd, bp, MINREAD)) < 0) {
        free(buffer);
        return (-1);
    }
    p = bp;
    /*
     * Loop through the Central Directory Headers. Note that a valid zip/jar
     * must have an ENDHDR (with ENDSIG) after the Central Directory.
     */
    while (GETSIG(p) == CENSIG) {

        /*
         * If a complete header isn't in the buffer, shift the contents
         * of the buffer down and refill the buffer.  Note that the check
         * for "bytes < CENHDR" must be made before the test for the entire
         * size of the header, because if bytes is less than CENHDR, the
         * actual size of the header can't be determined. The addition of
         * SIGSIZ guarantees that the next signature is also in the buffer
         * for proper loop termination.
         */
        if (bytes < CENHDR) {
            p = memmove(bp, p, bytes);
            if ((res = read(fd, bp + bytes, MINREAD)) <= 0) {
                free(buffer);
                return (-1);
            }
            bytes += res;
        }
        entry_size = CENHDR + CENNAM(p) + CENEXT(p) + CENCOM(p);
        if (bytes < entry_size + SIGSIZ) {
            if (p != bp)
                p = memmove(bp, p, bytes);
            read_size = entry_size - bytes + SIGSIZ;
            read_size = (read_size < MINREAD) ? MINREAD : read_size;
            if ((res = read(fd, bp + bytes,  read_size)) <= 0) {
                free(buffer);
                return (-1);
            }
            bytes += res;
        }

        /*
         * Check if the name is the droid we are looking for; the jar file
         * manifest.  If so, build the entry record from the data found in
         * the header located and return success.
         */
        if ((size_t)CENNAM(p) == JLI_StrLen(file_name) &&
          memcmp((p + CENHDR), file_name, JLI_StrLen(file_name)) == 0) {
            if (JLI_Lseek(fd, base_offset + CENOFF(p), SEEK_SET) < (jlong)0) {
                free(buffer);
                return (-1);
            }
            if (read(fd, locbuf, LOCHDR) < 0) {
                free(buffer);
                return (-1);
            }
            if (GETSIG(locbuf) != LOCSIG) {
                free(buffer);
                return (-1);
            }
            entry->isize = CENLEN(p);
            entry->csize = CENSIZ(p);
            entry->offset = base_offset + CENOFF(p) + LOCHDR +
                LOCNAM(locbuf) + LOCEXT(locbuf);
            entry->how = CENHOW(p);
            free(buffer);
            return (0);
        }

        /*
         * Point to the next entry and decrement the count of valid remaining
         * bytes.
         */
        bytes -= entry_size;
        p += entry_size;
    }
    free(buffer);
    return (-1);        /* Fell off the end the loop without a Manifest */
}