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 */ }
/* * 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); } } }
/* * 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 */ }