From: Greg Beaver Date: Wed, 23 Jan 2008 23:19:03 +0000 (+0000) Subject: initial work on more efficient zip implementation, read support working, write not... X-Git-Tag: RELEASE_2_0_0a1~802 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=29c5c804d0bfb87aae4401a908b36691ad0ee67d;p=php initial work on more efficient zip implementation, read support working, write not implemented yet This implementation will support read/write of extra field headers, both zlib/bzip2 compression read/write it will also delay header comparison/crc32 check until file open, making opening a single file within the zip much more efficient for large zip files it also uses emalloc/php streams and is therefore less likely to leak. this code is not yet built in config.m4/config.w32 --- diff --git a/ext/phar/pharzip.c b/ext/phar/pharzip.c new file mode 100644 index 0000000000..ed21c1d022 --- /dev/null +++ b/ext/phar/pharzip.c @@ -0,0 +1,371 @@ +/* + +----------------------------------------------------------------------+ + | phar php single-file executable PHP extension, zip implementation | + +----------------------------------------------------------------------+ + | Copyright (c) 2005-2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gregory Beaver | + | Marcus Boerger | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "phar_internal.h" + +#ifdef PHP_WIN32 +static inline void phar_unixify_path_separators(char *path, int path_len) /* {{{ */ +{ + char *s; + + /* unixify win paths */ + for (s = path; s - path < path_len; s++) { + if (*s == '\\') { + *s = '/'; + } + } +} +/* }}} */ +#endif + +static int phar_zip_process_extra(php_stream *fp, phar_entry_info *entry, php_uint16 len TSRMLS_DC) +{ + php_uint16 left = len; + union { + phar_zip_extra_field_header header; + phar_zip_unix3 unix3; + } h; + + do { + if (sizeof(h.header) != php_stream_read(fp, (char *) &h.header, sizeof(h.header))) { + return FAILURE; + } + /* clean up header for big-endian systems */ + if (h.header.tag != "\x75\x6e") { + /* skip to next header */ + php_stream_seek(fp, h.header.size, SEEK_CUR); + len -= h.header.size; + continue; + } + /* unix3 header found */ + /* clean up header for big-endian systems */ + if (sizeof(h.unix3) != php_stream_read(fp, (char *) &h.unix3, sizeof(h.unix3))) { + if (h.unix3.size > sizeof(h.unix3) - 4) { + /* skip symlink filename - we may add this support in later */ + php_stream_seek(fp, h.unix3.size - sizeof(h.unix3.size), SEEK_CUR); + } + /* set permissions */ + entry->flags &= PHAR_ENT_COMPRESSION_MASK; + if (entry->is_dir) { + entry->flags |= h.unix3.perms & PHAR_ENT_PERM_DEF_DIR; + } else { + entry->flags |= h.unix3.perms & PHAR_ENT_PERM_DEF_FILE; + } + } + } while (len); + return SUCCESS; +} + +/* + extracted from libzip + zip_dirent.c -- read directory entry (local or central), clean dirent + Copyright (C) 1999, 2003, 2004, 2005 Dieter Baron and Thomas Klausner + + This function is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +static time_t phar_zip_d2u_time(int dtime, int ddate) +{ + struct tm *tm, tmbuf; + time_t now; + + now = time(NULL); + tm = php_localtime_r(&now, &tmbuf); + + tm->tm_year = ((ddate>>9)&127) + 1980 - 1900; + tm->tm_mon = ((ddate>>5)&15) - 1; + tm->tm_mday = ddate&31; + + tm->tm_hour = (dtime>>11)&31; + tm->tm_min = (dtime>>5)&63; + tm->tm_sec = (dtime<<1)&62; + + return mktime(tm); +} + +int phar_zip_parse(char *fname, int fname_len, char **error TSRMLS_DC) +{ + php_stream *fp; + char buf[8192], *metadata; + phar_zip_dir_end locator; + long size; + size_t read; + php_uint16 i; + phar_archive_data *mydata = NULL; + phar_entry_info entry = {0}; + + fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL); + + php_stream_seek(fp, 0, SEEK_END); + size = php_stream_tell(fp); + if (size > sizeof(locator) + 65536) { + /* seek to max comment length + end of central directory record */ + size = sizeof(locator) + 65536; + if (FAILURE == php_stream_seek(fp, -size, SEEK_END)) { + php_stream_close(fp); + return FAILURE; + } + } else { + php_stream_seek(fp, 0, SEEK_SET); + } + do { + char *p = buf; + if (!(read = php_stream_read(fp, buf, 8192))) { + php_stream_close(fp); + return FAILURE; + } + while ((p=(char *) memchr(p + 1, 'P', (size_t)(buf - (p+1) + 8192 - 4 + 1))) != NULL) { + if (!memcmp(p + 1, "K\5\6", 3)) { + if (p - buf < sizeof(locator)) { + /* didn't read in the whole thing, back up */ + php_stream_seek(fp, 8192 - (p - buf), SEEK_CUR); + if (sizeof(locator) != php_stream_read(fp, (char *) &locator, sizeof(locator))) { + php_stream_close(fp); + return FAILURE; + } + } else { + memcpy((void *)&locator, (void *) p, sizeof(locator)); + } + goto foundit; + } + } + } while (read == 8192); + php_stream_close(fp); + return FAILURE; +foundit: + if (locator.centraldisk != 0 || locator.disknumber != 0) { + /* split archives not handled */ + php_stream_close(fp); + return FAILURE; + } + mydata = ecalloc(sizeof(phar_archive_data), 1); + mydata->fname = estrndup(fname, fname_len); +#ifdef PHP_WIN32 + phar_unixify_path_separators(mydata->fname, fname_len); +#endif + mydata->is_zip = 1; + mydata->fname_len = fname_len; + /* clean up on big-endian systems */ + /* read in archive comment, if any */ + if (locator.comment_len) { + metadata = (char *) emalloc(locator.comment_len); + if (locator.comment_len != php_stream_read(fp, metadata, locator.comment_len)) { + php_stream_close(fp); + efree(mydata->fname); + efree(mydata); + return FAILURE; + } + if (phar_parse_metadata(&metadata, &mydata->metadata, locator.comment_len TSRMLS_CC) == FAILURE) { + /* if not valid serialized data, it is a regular string */ + ALLOC_INIT_ZVAL(mydata->metadata); + Z_STRVAL_P(mydata->metadata) = metadata; + Z_STRLEN_P(mydata->metadata) = locator.comment_len; + Z_TYPE_P(mydata->metadata) = IS_STRING; + } + } else { + mydata->metadata = NULL; + } + /* seek to central directory */ + php_stream_seek(fp, locator.cdir_offset, SEEK_SET); + /* read in central directory */ + zend_hash_init(&mydata->manifest, sizeof(phar_entry_info), + zend_get_hash_value, destroy_phar_manifest_entry, 0); + entry.phar = mydata; + entry.is_zip = 1; +#define PHAR_ZIP_FAIL \ + zend_hash_destroy(&mydata->manifest); \ + php_stream_close(fp); \ + efree(mydata->fname); \ + if (mydata->metadata) { \ + zval_dtor(mydata->metadata); \ + } \ + efree(mydata); \ + return FAILURE + + /* add each central directory item to the manifest */ + for (i = 0; i < locator.cdir_size; i++) { + phar_zip_central_dir_file zipentry; + + /* sizeof(zipentry) reports size of contents + 2, no idea why */ + if (sizeof(zipentry)-2 != php_stream_read(fp, (char *) &zipentry, sizeof(zipentry)-2)) { + PHAR_ZIP_FAIL; + } + /* clean up for bigendian systems */ + if (memcmp("PK\1\2", zipentry.signature, 4)) { + /* corrupted entry */ + PHAR_ZIP_FAIL; + } + entry.compressed_filesize = zipentry.compsize; + entry.uncompressed_filesize = zipentry.uncompsize; + entry.crc32 = zipentry.crc32; + entry.timestamp = phar_zip_d2u_time(zipentry.timestamp, zipentry.datestamp); + entry.flags = PHAR_ENT_PERM_DEF_FILE; + if (zipentry.flags & PHAR_ZIP_FLAG_ENCRYPTED) { + PHAR_ZIP_FAIL; + } + if (!zipentry.filename_len) { + PHAR_ZIP_FAIL; + } + entry.filename_len = zipentry.filename_len; + entry.filename = (char *) emalloc(zipentry.filename_len+1); + if (entry.filename_len != php_stream_read(fp, entry.filename, entry.filename_len)) { + efree(entry.filename); + PHAR_ZIP_FAIL; + } + entry.filename[entry.filename_len] = '\0'; + if (entry.filename[entry.filename_len - 1] == '/') { + entry.is_dir = 1; + entry.filename_len--; + entry.flags |= PHAR_ENT_PERM_DEF_DIR; + } else { + entry.is_dir = 0; + } + if (zipentry.extra_len) { + if (FAILURE == phar_zip_process_extra(fp, &entry, zipentry.extra_len TSRMLS_CC)) { + PHAR_ZIP_FAIL; + } + } + switch (zipentry.compressed) { + case PHAR_ZIP_COMP_NONE : + /* compression flag already set */ + break; + case PHAR_ZIP_COMP_DEFLATE : + entry.flags |= PHAR_ENT_COMPRESSED_GZ; + if (!phar_has_zlib) { + if (error) { + spprintf(error, 0, "zlib extension is required for zlib compressed zip-based .phar file \"%s\"", fname); + } + PHAR_ZIP_FAIL; + } + break; + case PHAR_ZIP_COMP_BZIP2 : + entry.flags |= PHAR_ENT_COMPRESSED_BZ2; + if (!phar_has_bz2) { + if (error) { + spprintf(error, 0, "bz2 extension is required for Bzip2 compressed zip-based .phar file \"%s\"", fname); + } + PHAR_ZIP_FAIL; + } + break; + default : + PHAR_ZIP_FAIL; + } + /* get file metadata */ + if (zipentry.comment_len) { + metadata = (char *) emalloc(zipentry.comment_len); + if (zipentry.comment_len != php_stream_read(fp, metadata, zipentry.comment_len)) { + PHAR_ZIP_FAIL; + } + if (phar_parse_metadata(&metadata, &(entry.metadata), zipentry.comment_len TSRMLS_CC) == FAILURE) { + /* if not valid serialized data, it is a regular string */ + ALLOC_INIT_ZVAL(entry.metadata); + Z_STRVAL_P(entry.metadata) = metadata; + Z_STRLEN_P(entry.metadata) = zipentry.comment_len; + Z_TYPE_P(entry.metadata) = IS_STRING; + } else { + efree(metadata); + } + } else { + entry.metadata = NULL; + } + if (entry.filename_len == sizeof(".phar/alias.txt")-1 && strncmp(entry.filename, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) { + size_t remember = php_stream_tell(fp); + php_stream_filter *filter; + /* to properly decompress, we have to tell zlib to look for a zlib or gzip header */ + zval filterparams; + + /* archive alias found, seek to file contents, do not validate local header. Potentially risky, but + not very. */ + php_stream_seek(fp, zipentry.offset + sizeof(phar_zip_file_header) + entry.filename_len + zipentry.extra_len, SEEK_SET); + if (entry.flags & PHAR_ENT_COMPRESSED_GZ) { +/* this is defined in zlib's zconf.h */ +#ifndef MAX_WBITS +#define MAX_WBITS 15 +#endif + array_init(&filterparams); + add_assoc_long(&filterparams, "window", MAX_WBITS + 32); + filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp) TSRMLS_CC); + if (!filter) { + add_assoc_long(&filterparams, "window", MAX_WBITS); + filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp) TSRMLS_CC); + if (!filter) { + PHAR_ZIP_FAIL; + } + } + zval_dtor(&filterparams); + php_stream_filter_append(&fp->readfilters, filter); + if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &(mydata->alias), entry.uncompressed_filesize, 0)) || !mydata->alias) { + PHAR_ZIP_FAIL; + } + php_stream_filter_flush(filter, 1); + php_stream_filter_remove(filter, 1 TSRMLS_CC); + } else if (entry.flags & PHAR_ENT_COMPRESSED_BZ2) { + php_stream_filter *filter; + filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp) TSRMLS_CC); + if (!filter) { + PHAR_ZIP_FAIL; + } + php_stream_filter_append(&fp->readfilters, filter); + php_stream_filter_append(&fp->readfilters, filter); + if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &(mydata->alias), entry.uncompressed_filesize, 0)) || !mydata->alias) { + PHAR_ZIP_FAIL; + } + php_stream_filter_flush(filter, 1); + php_stream_filter_remove(filter, 1 TSRMLS_CC); + } + + mydata->is_explicit_alias = 1; + mydata->alias_len = zipentry.uncompsize; + zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), mydata->alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL); + } + zend_hash_add(&mydata->manifest, entry.filename, entry.filename_len, (void *)&entry,sizeof(phar_entry_info), NULL); + } + zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL); + if (pphar) { + *pphar = mydata; + } + return SUCCESS; +} diff --git a/ext/phar/pharzip.h b/ext/phar/pharzip.h new file mode 100644 index 0000000000..066c167cbf --- /dev/null +++ b/ext/phar/pharzip.h @@ -0,0 +1,242 @@ +/* + +----------------------------------------------------------------------+ + | phar php single-file executable PHP extension | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gregory Beaver | + | Marcus Boerger | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +typedef struct _phar_zip_file_header { + char magic[4]; /* local file header signature 4 bytes (0x04034b50) */ + char zipversion[2]; /* version needed to extract 2 bytes */ + php_uint16 flags; /* general purpose bit flag 2 bytes */ + php_uint16 compressed; /* compression method 2 bytes */ + php_uint16 timestamp; /* last mod file time 2 bytes */ + php_uint16 datestamp; /* last mod file date 2 bytes */ + php_uint32 crc32; /* crc-32 4 bytes */ + php_uint32 compsize; /* compressed size 4 bytes */ + php_uint32 uncompsize; /* uncompressed size 4 bytes */ + php_uint16 filename_len; /* file name length 2 bytes */ + php_uint16 extra_len; /* extra field length 2 bytes */ +/* file name (variable size) */ +/* extra field (variable size) */ +} phar_zip_file_header; + +typedef struct _phar_zip_file_datadesc { + php_uint32 crc32; /* crc-32 4 bytes */ + php_uint32 compsize; /* compressed size 4 bytes */ + php_uint32 uncompsize; /* uncompressed size 4 bytes */ +} phar_zip_data_desc; + +typedef struct _phar_zip_file_datadesc_zip64 { + php_uint32 crc32; /* crc-32 4 bytes */ + php_uint32 compsize; /* compressed size 8 bytes */ + php_uint32 compsize2; + php_uint32 uncompsize; /* uncompressed size 8 bytes */ + php_uint32 uncompsize2; +} phar_zip_data_desc_zip64; + +typedef struct _phar_zip_archive_extra_data_record { + char signature[4]; /* archive extra data signature 4 bytes (0x08064b50) */ + php_uint32 len; /* extra field length 4 bytes */ +/* extra field data (variable size) */ +} phar_zip_archive_extra_data_record; + +/* madeby/extractneeded value if bzip2 compression is used */ +#define PHAR_ZIP_BZIP2 "46" +/* madeby/extractneeded value for other cases */ +#define PHAR_ZIP_NORM "20" + +#define PHAR_ZIP_FLAG_ENCRYPTED 0x0001 +/* data descriptor present for this file */ +#define PHAR_ZIP_FLAG_DATADESC 0x0008 +#define PHAR_ZIP_FLAG_UTF8 0x0400 + +/* +0 - The file is stored (no compression) +1 - The file is Shrunk +2 - The file is Reduced with compression factor 1 +3 - The file is Reduced with compression factor 2 +4 - The file is Reduced with compression factor 3 +5 - The file is Reduced with compression factor 4 +6 - The file is Imploded +7 - Reserved for Tokenizing compression algorithm +8 - The file is Deflated +9 - Enhanced Deflating using Deflate64(tm) +10 - PKWARE Data Compression Library Imploding (old IBM TERSE) +11 - Reserved by PKWARE +12 - File is compressed using BZIP2 algorithm +13 - Reserved by PKWARE +14 - LZMA (EFS) +15 - Reserved by PKWARE +16 - Reserved by PKWARE +17 - Reserved by PKWARE +18 - File is compressed using IBM TERSE (new) +19 - IBM LZ77 z Architecture (PFS) +97 - WavPack compressed data +98 - PPMd version I, Rev 1 +*/ +#define PHAR_ZIP_COMP_NONE 0 +#define PHAR_ZIP_COMP_DEFLATE 8 +#define PHAR_ZIP_COMP_BZIP2 12 + +/* + -ASi Unix Extra Field: + ==================== + + The following is the layout of the ASi extra block for Unix. The + local-header and central-header versions are identical. + (Last Revision 19960916) + + Value Size Description + ----- ---- ----------- + (Unix3) 0x756e Short tag for this extra block type ("nu") + TSize Short total data size for this block + CRC Long CRC-32 of the remaining data + Mode Short file permissions + SizDev Long symlink'd size OR major/minor dev num + UID Short user ID + GID Short group ID + (var.) variable symbolic link filename + + Mode is the standard Unix st_mode field from struct stat, containing + user/group/other permissions, setuid/setgid and symlink info, etc. + + If Mode indicates that this file is a symbolic link, SizDev is the + size of the file to which the link points. Otherwise, if the file + is a device, SizDev contains the standard Unix st_rdev field from + struct stat (includes the major and minor numbers of the device). + SizDev is undefined in other cases. + + If Mode indicates that the file is a symbolic link, the final field + will be the name of the file to which the link points. The file- + name length can be inferred from TSize. + + [Note that TSize may incorrectly refer to the data size not counting + the CRC; i.e., it may be four bytes too small.] +*/ + +typedef struct _phar_zip_extra_field_header { + char tag[2]; + php_uint16 size; +} phar_zip_extra_field_header; + +typedef struct _phar_zip_unix3 { + char tag[2]; /* 0x756e Short tag for this extra block type ("nu") */ + php_uint16 size; /* TSize Short total data size for this block */ + php_uint32 crc32; /* CRC Long CRC-32 of the remaining data */ + php_uint16 perms; /* Mode Short file permissions */ + php_uint32 smylinksize; /* SizDev Long symlink'd size OR major/minor dev num */ + php_uint16 uid; /* UID Short user ID */ + php_uint16 gid; /* GID Short group ID */ +/* (var.) variable symbolic link filename */ +} phar_zip_unix3; + +typedef struct _phar_zip_central_dir_file { + char signature[4]; /* central file header signature 4 bytes (0x02014b50) */ + char madeby[2]; /* version made by 2 bytes */ + char zipversion[2]; /* version needed to extract 2 bytes */ + php_uint16 flags; /* general purpose bit flag 2 bytes */ + php_uint16 compressed; /* compression method 2 bytes */ + php_uint16 timestamp; /* last mod file time 2 bytes */ + php_uint16 datestamp; /* last mod file date 2 bytes */ + php_uint32 crc32; /* crc-32 4 bytes */ + php_uint32 compsize; /* compressed size 4 bytes */ + php_uint32 uncompsize; /* uncompressed size 4 bytes */ + php_uint16 filename_len; /* file name length 2 bytes */ + php_uint16 extra_len; /* extra field length 2 bytes */ + php_uint16 comment_len; /* file comment length 2 bytes */ + php_uint16 disknumber; /* disk number start 2 bytes */ + php_uint16 internal_atts; /* internal file attributes 2 bytes */ + php_uint32 external_atts; /* external file attributes 4 bytes */ + php_uint32 offset; /* relative offset of local header 4 bytes */ + +/* file name (variable size) */ +/* extra field (variable size) */ +/* file comment (variable size) */ +} phar_zip_central_dir_file; + +typedef struct _phar_zip_dir_signature { + char signature[4]; /* header signature 4 bytes (0x05054b50) */ + php_uint16 size; /* size of data 2 bytes */ +} phar_zip_dir_signature; + +typedef struct _phar_zip64_dir_end { + char signature[4]; /* zip64 end of central dir + signature 4 bytes (0x06064b50) */ + php_uint32 size1; /* size of zip64 end of central + directory record 8 bytes */ + php_uint32 size2; + char madeby[2]; /* version made by 2 bytes */ + php_uint16 extractneeded; /* version needed to extract 2 bytes */ + php_uint32 disknum; /* number of this disk 4 bytes */ + php_uint32 cdir_num; /* number of the disk with the + start of the central directory 4 bytes */ + php_uint32 entries1; /* total number of entries in the + central directory on this disk 8 bytes */ + php_uint32 entries2; + php_uint32 entriestotal1; /* total number of entries in the + central directory 8 bytes */ + php_uint32 entriestotal2; + php_uint32 cdirsize1; /* size of the central directory 8 bytes */ + php_uint32 cdirsize2; + php_uint32 offset1; /* offset of start of central + directory with respect to + the starting disk number 8 bytes */ + php_uint32 offset2; +/* zip64 extensible data sector (variable size) */ +} phar_zip64_dir_end; + +typedef struct _phar_zip64_dir_locator { + char signature[4]; /* zip64 end of central dir locator + signature 4 bytes (0x07064b50) */ + php_uint32 disknum; /* number of the disk with the + start of the zip64 end of + central directory 4 bytes */ + php_uint32 diroffset1; /* relative offset of the zip64 + end of central directory record 8 bytes */ + php_uint32 diroffset2; + php_uint32 totaldisks; /* total number of disks 4 bytes */ +} phar_zip64_dir_locator; + +typedef struct _phar_zip_dir_end { + char signature[4]; /* end of central dir signature 4 bytes (0x06054b50) */ + php_uint16 disknumber; /* number of this disk 2 bytes */ + php_uint16 centraldisk; /* number of the disk with the + start of the central directory 2 bytes */ + php_uint16 counthere; /* total number of entries in the + central directory on this disk 2 bytes */ + php_uint16 count; /* total number of entries in + the central directory 2 bytes */ + php_uint32 cdir_size; /* size of the central directory 4 bytes */ + php_uint32 cdir_offset; /* offset of start of central + directory with respect to + the starting disk number 4 bytes */ + php_uint16 comment_len; /* .ZIP file comment length 2 bytes */ +/* .ZIP file comment (variable size) */ +} phar_zip_dir_end; + +BEGIN_EXTERN_C() +int phar_zip_parse(char *fname, int fname_len, char **error TSRMLS_DC); +END_EXTERN_C() +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */