/* * 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); } } }
/* * Reads zip file central directory. Returns the file position of first * CEN header, otherwise returns -1 if an error occured. If zip->msg != NULL * then the error was a zip format error and zip->msg has the error text. * Always pass in -1 for knownTotal; it's used for a recursive call. */ static jlong readCEN(jzfile *zip, jint knownTotal) { /* Following are unsigned 32-bit */ jlong endpos, end64pos, cenpos, cenlen, cenoff; /* Following are unsigned 16-bit */ jint total, tablelen, i, j; unsigned char *cenbuf = NULL; unsigned char *cenend; unsigned char *cp; #ifdef USE_MMAP static jlong pagesize; jlong offset; #endif unsigned char endbuf[ENDHDR]; jint endhdrlen = ENDHDR; jzcell *entries; jint *table; /* Clear previous zip error */ zip->msg = NULL; /* Get position of END header */ if ((endpos = findEND(zip, endbuf)) == -1) return -1; /* no END header or system error */ if (endpos == 0) return 0; /* only END header present */ freeCEN(zip); /* Get position and length of central directory */ cenlen = ENDSIZ(endbuf); cenoff = ENDOFF(endbuf); total = ENDTOT(endbuf); if (cenlen == ZIP64_MAGICVAL || cenoff == ZIP64_MAGICVAL || total == ZIP64_MAGICCOUNT) { unsigned char end64buf[ZIP64_ENDHDR]; if ((end64pos = findEND64(zip, end64buf, endpos)) != -1) { cenlen = ZIP64_ENDSIZ(end64buf); cenoff = ZIP64_ENDOFF(end64buf); total = (jint)ZIP64_ENDTOT(end64buf); endpos = end64pos; endhdrlen = ZIP64_ENDHDR; } } if (cenlen > endpos) ZIP_FORMAT_ERROR("invalid END header (bad central directory size)"); cenpos = endpos - cenlen; /* Get position of first local file (LOC) header, taking into * account that there may be a stub prefixed to the zip file. */ zip->locpos = cenpos - cenoff; if (zip->locpos < 0) ZIP_FORMAT_ERROR("invalid END header (bad central directory offset)"); #ifdef USE_MMAP if (zip->usemmap) { /* On Solaris & Linux prior to JDK 6, we used to mmap the whole jar file to * read the jar file contents. However, this greatly increased the perceived * footprint numbers because the mmap'ed pages were adding into the totals shown * by 'ps' and 'top'. We switched to mmaping only the central directory of jar * file while calling 'read' to read the rest of jar file. Here are a list of * reasons apart from above of why we are doing so: * 1. Greatly reduces mmap overhead after startup complete; * 2. Avoids dual path code maintainance; * 3. Greatly reduces risk of address space (not virtual memory) exhaustion. */ if (pagesize == 0) { pagesize = (jlong)sysconf(_SC_PAGESIZE); if (pagesize == 0) goto Catch; } if (cenpos > pagesize) { offset = cenpos & ~(pagesize - 1); } else { offset = 0; } /* When we are not calling recursively, knownTotal is -1. */ if (knownTotal == -1) { void* mappedAddr; /* Mmap the CEN and END part only. We have to figure out the page size in order to make offset to be multiples of page size. */ zip->mlen = cenpos - offset + cenlen + endhdrlen; zip->offset = offset; mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset); zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL : (unsigned char*)mappedAddr; if (zip->maddr == NULL) { jio_fprintf(stderr, "mmap failed for CEN and END part of zip file\n"); goto Catch; } } cenbuf = zip->maddr + cenpos - offset; } else #endif { if ((cenbuf = malloc((size_t) cenlen)) == NULL || (readFullyAt(zip->zfd, cenbuf, cenlen, cenpos) == -1)) goto Catch; } cenend = cenbuf + cenlen; /* Initialize zip file data structures based on the total number * of central directory entries as stored in ENDTOT. Since this * is a 2-byte field, but we (and other zip implementations) * support approx. 2**31 entries, we do not trust ENDTOT, but * treat it only as a strong hint. When we call ourselves * recursively, knownTotal will have the "true" value. * * Keep this path alive even with the Zip64 END support added, just * for zip files that have more than 0xffff entries but don't have * the Zip64 enabled. */ total = (knownTotal != -1) ? knownTotal : total; entries = zip->entries = calloc(total, sizeof(entries[0])); tablelen = zip->tablelen = ((total/2) | 1); // Odd -> fewer collisions table = zip->table = malloc(tablelen * sizeof(table[0])); if (entries == NULL || table == NULL) goto Catch; for (j = 0; j < tablelen; j++) table[j] = ZIP_ENDCHAIN; /* Iterate through the entries in the central directory */ for (i = 0, cp = cenbuf; cp <= cenend - CENHDR; i++, cp += CENSIZE(cp)) { /* Following are unsigned 16-bit */ jint method, nlen; unsigned int hsh; if (i >= total) { /* This will only happen if the zip file has an incorrect * ENDTOT field, which usually means it contains more than * 65535 entries. */ cenpos = readCEN(zip, countCENHeaders(cenbuf, cenend)); goto Finally; } method = CENHOW(cp); nlen = CENNAM(cp); if (GETSIG(cp) != CENSIG) ZIP_FORMAT_ERROR("invalid CEN header (bad signature)"); if (CENFLG(cp) & 1) ZIP_FORMAT_ERROR("invalid CEN header (encrypted entry)"); if (method != STORED && method != DEFLATED) ZIP_FORMAT_ERROR("invalid CEN header (bad compression method)"); if (cp + CENHDR + nlen > cenend) ZIP_FORMAT_ERROR("invalid CEN header (bad header size)"); /* if the entry is metadata add it to our metadata names */ if (isMetaName((char *)cp+CENHDR, nlen)) if (addMetaName(zip, (char *)cp+CENHDR, nlen) != 0) goto Catch; /* Record the CEN offset and the name hash in our hash cell. */ entries[i].cenpos = cenpos + (cp - cenbuf); entries[i].hash = hashN((char *)cp+CENHDR, nlen); /* Add the entry to the hash table */ hsh = entries[i].hash % tablelen; entries[i].next = table[hsh]; table[hsh] = i; } if (cp != cenend) ZIP_FORMAT_ERROR("invalid CEN header (bad header size)"); zip->total = i; goto Finally; Catch: freeCEN(zip); cenpos = -1; Finally: #ifdef USE_MMAP if (!zip->usemmap) #endif free(cenbuf); return cenpos; }
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 */ }
/** * Writes all entries except ".class" to the data_file_handle, * writes corresponding central directory records and the end of central * directory record to the directory_file_handle. * Treats .ZIP file format as documented in * ftp://ftp.uu.net/pub/archiving/zip/doc/appnote-970311-iz.zip. * Assumes that the .ZIP file doesn't span across multiple disks. * Assumes that raw_current_entry()->nextCenOffset contains the offset * of the first entry of the central directory (as set in the constructor). * Returns true if completes successfully, false otherwise. */ bool JarFileParser::copy_non_class_entries_to(OsFile_Handle data_file_handle, OsFile_Handle directory_file_handle JVM_TRAPS) { UsingFastOops fast_oops; BufferedFile::Fast jar_buffer = buffered_file(); const char class_suffix[] = {'.','c','l','a','s','s','\0'}; juint locOffset = raw_current_entry()->locOffset; const juint buffer_size = MAX_ENTRY_NAME; DECLARE_STATIC_BUFFER(unsigned char, buffer, buffer_size); unsigned int name_length = 0; juint loc_header_offset = 0; juint cen_header_offset = 0; size_t bytes_to_copy = 0; unsigned int written_entry_count = 0; unsigned int read_entry_count = 0; unsigned int total_entry_count = raw_current_entry()->totalEntryCount; // No OsFile_ routine to get the current position, // so keep this information by ourselves. juint data_file_position = 0; juint directory_file_position = 0; GUARANTEE(buffer_size >= LOCHDRSIZ && buffer_size >= EXTHDRSIZ && buffer_size >= ENDHDRSIZ && buffer_size >= MAX_ENTRY_NAME, "Buffer is too small"); if ((OsFile_seek(data_file_handle, 0L, SEEK_SET) < 0) || (OsFile_seek(directory_file_handle, 0L, SEEK_SET) < 0)) { return false; } for (read_entry_count = 0; read_entry_count < total_entry_count; read_entry_count++) { // Find the next entry in the JAR. bool found = find_entry(NULL JVM_MUST_SUCCEED); if (!found) { return false; } cen_header_offset = raw_current_entry()->nextCenOffset; // If find_entry succeeded, centralHeader contains the central directory // header for the found entry. unsigned char *cenp = (unsigned char *)raw_current_entry()->centralHeader; name_length = CENNAM(cenp); if (name_length >= MAX_ENTRY_NAME) { Throw::error(jarfile_error JVM_THROW_0); } else { jar_buffer().get_bytes(buffer, name_length); if (!JarFileParser::match(class_suffix, (char*)buffer, name_length)) { loc_header_offset = locOffset + CENOFF(cenp); // Update the relative offset of local header // in the central directory entry. // Use little-endian order according to the .ZIP format. Bytes::put_Java_u4(cenp + CENOFF_OFFSET, Bytes::swap_u4(data_file_position)); // Write the central directory entry to the directory file. if (OsFile_write(directory_file_handle, cenp, 1, CENHDRSIZ) != CENHDRSIZ) { return false; } directory_file_position += CENHDRSIZ; // Write the file name to the direcory file. if (OsFile_write(directory_file_handle, buffer, 1, name_length) != name_length) { return false; } directory_file_position += name_length; // Copy the extra field and file comment to the directory file. bytes_to_copy = CENEXT(cenp) + CENCOM(cenp); if (block_copy(&jar_buffer, directory_file_handle, bytes_to_copy) != bytes_to_copy) { return false; } directory_file_position += bytes_to_copy; // Copy the local file header to the data file. if ((jar_buffer().seek(loc_header_offset, SEEK_SET) < 0) || (jar_buffer().get_bytes(buffer, LOCHDRSIZ) != LOCHDRSIZ) || (OsFile_write(data_file_handle, buffer, 1, LOCHDRSIZ) != LOCHDRSIZ)) { return false; } data_file_position += LOCHDRSIZ; { unsigned char *locp = (unsigned char *)buffer; // Copy the file name, extra field and the compressed file data // to the data file. bytes_to_copy = LOCNAM(locp) + LOCEXT(locp) + CENSIZ(cenp); if (block_copy(&jar_buffer, data_file_handle, bytes_to_copy) != bytes_to_copy) { return false; } data_file_position += bytes_to_copy; // Check if the data descriptor exists. if ((LOCFLG(locp) & 8) == 8) { // Copy the data descriptor to the data file. if (jar_buffer().get_bytes(buffer, EXTHDRSIZ) != EXTHDRSIZ) { return false; } // The data descriptor may or may not start with the signature // depending on .ZIP file format revision used. if (GETSIG(buffer) == EXTSIG) { // According to the Info-ZIP Application Note 970311, // the data descriptor starts with the signature. if (OsFile_write(data_file_handle, buffer, 1, EXTHDRSIZ) != EXTHDRSIZ) { return false; } data_file_position += EXTHDRSIZ; } else { // According to the .ZIP format specification version 6.1.0, // the data descriptor doesn't start with the signature. if (OsFile_write(data_file_handle, buffer, 1, EXTHDRSIZ - 4) != EXTHDRSIZ - 4) { return false; } data_file_position += EXTHDRSIZ - 4; } } } written_entry_count++; } } cen_header_offset += CENHDRSIZ + name_length + CENEXT(cenp) + CENCOM(cenp); raw_current_entry()->nextCenOffset = cen_header_offset; } // Now that all central directory entries are processed, // cen_header_offset points to the end of the central directory. if (jar_buffer().seek(cen_header_offset, SEEK_SET) < 0) { return false; } if (jar_buffer().get_bytes(buffer, ENDHDRSIZ) != ENDHDRSIZ) { return false; } { unsigned char *endp = (unsigned char *)buffer; if (GETSIG(endp) != ENDSIG) { return false; } // Update the record to match the new number of entries. // Use little-endian order according to the .ZIP format. Bytes::put_Java_u2(endp + ENDSUB_OFFSET, Bytes::swap_u2(written_entry_count)); Bytes::put_Java_u2(endp + ENDTOT_OFFSET, Bytes::swap_u2(written_entry_count)); // The size of the central directory is exactly // the number of bytes written to the directory_file. Bytes::put_Java_u4(endp + ENDSIZ_OFFSET, Bytes::swap_u4(directory_file_position)); // The offset of the central directory is exactly // the number of bytes written to the data_file. Bytes::put_Java_u4(endp + ENDOFF_OFFSET, Bytes::swap_u4(data_file_position)); if (OsFile_write(directory_file_handle, endp, 1, ENDHDRSIZ) != ENDHDRSIZ) { return false; } if (block_copy(&jar_buffer, directory_file_handle, ENDCOM(endp)) != (size_t)ENDCOM(endp)) { return false; } } return true; }
int JarFileParser::filtered_do_next_entries(JvmNameFilterProc entry_filter_proc, JvmDoJarEntryProc do_jar_entry_proc, void* caller_data, int entry_id, int max_size JVM_TRAPS) { GUARANTEE(entry_id >= 0 && max_size > 0, "Sanity"); DECLARE_STATIC_BUFFER(char, entry_name, MAX_ENTRY_NAME); unsigned int name_length = 0; int total_size = 0; if (max_size <= 0) { max_size = max_jint; } if (entry_id > 0) { raw_current_entry()->nextCenOffset = entry_id; } // NOTE: max_entries can be -1 that indicates no limitation on the number of // entries processed. for (total_size = 0; total_size < max_size;) { bool found = find_entry(NULL JVM_MUST_SUCCEED); if (!found) { break; } // If find_entry succeeded, centralHeader contains the central directory // header for the found entry. unsigned char *cenp = (unsigned char *)raw_current_entry()->centralHeader; name_length = CENNAM(cenp); if (name_length >= MAX_ENTRY_NAME) { return -1; } // Save the next offset as entry_filter_proc may move raw_current_entry() juint nextCenOffset = raw_current_entry()->nextCenOffset + CENHDRSIZ + name_length + CENEXT(cenp) + CENCOM(cenp); { UsingFastOops fast_oops; BufferedFile::Fast bf = buffered_file(); if (bf().get_bytes((address)entry_name, name_length) != name_length) { return -1; } } entry_name[name_length] = '\0'; if (((entry_filter_proc == NULL) || (entry_filter_proc(entry_name, caller_data) == KNI_TRUE)) && (do_jar_entry_proc != NULL)) { UsingFastOops fast_oops; Buffer::Fast buffer = load_entry(JVM_SINGLE_ARG_CHECK_0); if (buffer.is_null()) { return -1; } if (do_jar_entry_proc((char*)entry_name, buffer().data(), buffer().length(), caller_data) == KNI_FALSE) { return 0; } } total_size += raw_current_entry()->length; if (CURRENT_HAS_PENDING_EXCEPTION) { // if entry_filter_proc returned NULL, check for exception return -1; } raw_current_entry()->nextCenOffset = nextCenOffset; } // If we reached the end of JAR return 0. // Otherwise return nextCenOffset, it is used as a JAR entry id. return (total_size < max_size) ? 0 : raw_current_entry()->nextCenOffset; }
/* * 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 */ }