summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Beaver <cellog@php.net>2007-12-10 20:42:02 +0000
committerGreg Beaver <cellog@php.net>2007-12-10 20:42:02 +0000
commit0d38d74493bc5381117cf9d82fb0d11f3973b2e2 (patch)
treed131380ed99b3da6fcde4e42309aa53853acb7fe
parente4c2bc1863910264cf0ea6d75bd88d36b0961fc7 (diff)
downloadphp-git-0d38d74493bc5381117cf9d82fb0d11f3973b2e2.tar.gz
add unfinished experimental tar support (may not lead anywhere)
-rw-r--r--ext/phar/config.m42
-rw-r--r--ext/phar/phar.c5
-rw-r--r--ext/phar/phar2.c244
-rw-r--r--ext/phar/phar2.h34
-rw-r--r--ext/phar/phar2_openhash.c150
-rw-r--r--ext/phar/phar2_openhash.h59
-rwxr-xr-xext/phar/phar_internal.h10
7 files changed, 499 insertions, 5 deletions
diff --git a/ext/phar/config.m4 b/ext/phar/config.m4
index 75c26eae52..4782889d2f 100644
--- a/ext/phar/config.m4
+++ b/ext/phar/config.m4
@@ -5,7 +5,7 @@ PHP_ARG_ENABLE(phar, for phar support/phar zlib support,
[ --enable-phar Enable phar support, use --with-zlib-dir if zlib detection fails])
if test "$PHP_PHAR" != "no"; then
- PHP_NEW_EXTENSION(phar, phar.c phar_object.c phar_path_check.c, $ext_shared)
+ PHP_NEW_EXTENSION(phar, phar.c phar_object.c phar_path_check.c phar2.c phar2_openhash.c, $ext_shared)
PHP_ADD_EXTENSION_DEP(phar, zlib, false)
PHP_ADD_EXTENSION_DEP(phar, bz2, false)
PHP_ADD_EXTENSION_DEP(phar, spl, false)
diff --git a/ext/phar/phar.c b/ext/phar/phar.c
index 436943b36c..1183a799ab 100644
--- a/ext/phar/phar.c
+++ b/ext/phar/phar.c
@@ -21,6 +21,7 @@
#define PHAR_MAIN
#include "phar_internal.h"
+#include "phar2.h"
#include "SAPI.h"
ZEND_DECLARE_MODULE_GLOBALS(phar)
@@ -947,6 +948,10 @@ int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int
}
return FAILURE;
}
+ if ((manifest_ver & PHAR_API_MAJORVERSION) == PHAR_API_MAJORVERSION) {
+ /* this is a phar in tar format */
+ return phar2_open_file(fp, fname, fname_len, alias, alias_len, halt_offset, pphar, savebuf, error TSRMLS_CC);
+ }
PHAR_GET_32(buffer, manifest_flags);
diff --git a/ext/phar/phar2.c b/ext/phar/phar2.c
new file mode 100644
index 0000000000..7dae30c30d
--- /dev/null
+++ b/ext/phar/phar2.c
@@ -0,0 +1,244 @@
+/*
+ +----------------------------------------------------------------------+
+ | phar php single-file executable PHP extension |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006-2007 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 <cellog@php.net> |
+ | Marcus Boerger <helly@php.net> |
+ | based on work by Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "phar_internal.h"
+
+
+#define TAR_FILE '0'
+#define TAR_LINK '1'
+#define TAR_SYMLINK '2'
+#define TAR_DIR '5'
+#define TAR_NEW '8'
+
+/**
+ * the format of the header block for a file, in the older UNIX-compatible
+ * TAR format
+ */
+typedef struct _old_tar_header { /* {{{ */
+ char name[100]; /* name of file;
+ directory is indicated by a trailing slash (/) */
+ char mode[8]; /* file mode */
+ char uid[8]; /* owner user ID */
+ char gid[8]; /* owner group ID */
+ char size[12]; /* length of file in bytes */
+ char mtime[12]; /* modify time of file */
+ char chksum[8]; /* checksum for header */
+ char link; /* indicator for links;
+ 1 for a linked file,
+ 2 for a symbolic link,
+ 0 otherwise */
+ char linkname[100]; /* name of linked file */
+} old_tar_header;
+/* }}} */
+
+/**
+ * the new USTAR header format.
+ * Note that tar can determine that the USTAR format is being used by the
+ * presence of the null-terminated string "ustar" in the magic field.
+ */
+typedef struct _tar_header { /* {{{ */
+ char name[100]; /* name of file */
+ char mode[8]; /* file mode */
+ char uid[8]; /* owner user ID */
+ char gid[8]; /* owner group ID */
+ char size[12]; /* length of file in bytes */
+ char mtime[12]; /* modify time of file */
+ char chksum[8]; /* checksum for header */
+ char typeflag; /* type of file
+ 0 Regular file
+ 1 Link to another file already archived
+ 2 Symbolic link
+ 3 Character special device
+ 4 Block special device
+ 5 Directory
+ 6 FIFO special file
+ 7 Reserved */
+ char linkname[100]; /* name of linked file */
+ char magic[6]; /* USTAR indicator */
+ char version[2]; /* USTAR version */
+ char uname[32]; /* owner user name */
+ char gname[32]; /* owner group name */
+ char devmajor[8]; /* device major number */
+ char devminor[8]; /* device minor number */
+ char prefix[155]; /* prefix for file name;
+ the value of the prefix field, if non-null,
+ is prefixed to the name field to allow names
+ longer then 100 characters */
+} tar_header;
+/* }}} */
+
+typedef struct _tar_file tar_file;
+
+typedef struct _tar_entry { /* {{{ */
+ tar_file *tar;
+ char type;
+ off_t start;
+ off_t pos;
+ off_t size;
+ mode_t mode;
+ time_t mtime;
+ uid_t uid;
+ gid_t gid;
+ union {
+ HashTable *content;
+ char *link;
+ } u;
+} tar_entry;
+/* }}} */
+
+struct _tar_file { /* {{{ */
+ php_stream *stream;
+ char *real_name;
+ int refcount;
+ int opened;
+ tar_entry root;
+};
+/* }}} */
+
+static int tar_number(char* buf, int len) /* {{{ */
+{
+ int num = 0;
+ int i = 0;
+
+ while (i < len && buf[i] == ' ') {
+ i++;
+ }
+ while (i < len &&
+ buf[i] >= '0' &&
+ buf[i] <= '7') {
+ num = num * 8 + (buf[i] - '0');
+ i++;
+ }
+ return num;
+}
+/* }}} */
+
+static int tar_checksum(char* buf, int len) /* {{{ */
+{
+ int sum = 0;
+ char *end = buf + len;
+
+ while (buf != end) {
+ sum += (unsigned char)*buf;
+ buf++;
+ }
+ return sum;
+}
+/* }}} */
+#define MAPPHAR_ALLOC_FAIL(msg) \
+ php_stream_close(fp);\
+ if (error) {\
+ spprintf(error, 0, msg, fname);\
+ }\
+ return FAILURE;
+
+#ifdef WORDS_BIGENDIAN
+# define PHAR_GET_32(buffer, var) \
+ var = ((((unsigned char*)(buffer))[3]) << 24) \
+ | ((((unsigned char*)(buffer))[2]) << 16) \
+ | ((((unsigned char*)(buffer))[1]) << 8) \
+ | (((unsigned char*)(buffer))[0]); \
+ (buffer) += 4
+# define PHAR_GET_16(buffer, var) \
+ var = ((((unsigned char*)(buffer))[1]) << 8) \
+ | (((unsigned char*)(buffer))[0]); \
+ (buffer) += 2
+#else
+# define PHAR_GET_32(buffer, var) \
+ var = *(php_uint32*)(buffer); \
+ buffer += 4
+# define PHAR_GET_16(buffer, var) \
+ var = *(php_uint16*)(buffer); \
+ buffer += 2
+#endif
+
+int phar2_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, long halt_offset, phar_archive_data** pphar, char *buffer, char **error TSRMLS_DC) /* {{{ */
+{
+ /* The structure of a tar-based phar archive is as follows:
+ - the first file contains the loader stub and file hash. The file hash is a mapping
+ of filename hash to location of manifest data within the official phar manifest using
+ an implementation of open hash that allows the entire thing to be read in without any
+ processing beyond signature check.
+ - the second file contains the official phar manifest as used in phar 1.x
+ - third file to second-to-last file contain the phar's files
+ - final file contains the phar signature
+ */
+ php_uint32 openhash_len;
+ phar_archive_data *mydata;
+
+ buffer += 6;
+ PHAR_GET_32(buffer), openhash_len);
+ if (openhash_len != sizeof(phar2_openhash) && openhash_len != sizeof(phar2_openhash_large)) {
+ MAPPHAR_ALLOC_FAIL("Corrupted phar2 archive, filename hash is wrong size in phar \"%s\"");
+ }
+ buffer -= 6;
+ buffer = (char *) erealloc((void *) buffer, openhash_len);
+ if (!buffer) {
+ MAPPHAR_ALLOC_FAIL("Could not allocate space for fast filename hash in phar \"%s\"");
+ }
+ if (openhash_len != php_stream_read(fp, buffer, openhash_len)) {
+ MAPPHAR_ALLOC_FAIL("Could not read fast filename hash in phar \"%s\"");
+ }
+
+ PHAR_G(fast_fname_map) = (phar2_openhash *) buffer;
+ mydata = ecalloc(sizeof(phar_archive_data), 1);
+
+ /* check whether we have meta data, zero check works regardless of byte order */
+ if (phar_parse_metadata(fp, &buffer, endbuffer, &mydata->metadata TSRMLS_CC) == FAILURE) {
+ MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
+ }
+
+ /* set up our manifest - entries will be created JIT as accessed */
+ zend_hash_init(&mydata->manifest, sizeof(phar_entry_info),
+ zend_get_hash_value, destroy_phar_manifest, 0);
+ snprintf(mydata->version, sizeof(mydata->version), "%u.%u.%u", manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0xF);
+ mydata->internal_file_start = halt_offset + manifest_len + 4;
+ mydata->halt_offset = halt_offset;
+ mydata->flags = manifest_flags;
+ mydata->fp = fp;
+ mydata->fname = estrndup(fname, fname_len);
+#ifdef PHP_WIN32
+ phar_unixify_path_separators(mydata->fname, fname_len);
+#endif
+ mydata->fname_len = fname_len;
+ mydata->alias = alias ? estrndup(alias, alias_len) : mydata->fname;
+ mydata->alias_len = alias ? alias_len : fname_len;
+ mydata->sig_flags = sig_flags;
+ mydata->sig_len = sig_len;
+ mydata->signature = signature;
+ phar_request_initialize(TSRMLS_C);
+ zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
+ if (register_alias) {
+ mydata->is_explicit_alias = 1;
+ zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
+ } else {
+ mydata->is_explicit_alias = 0;
+ }
+ efree(savebuf);
+
+ if (pphar) {
+ *pphar = mydata;
+ }
+
+ return SUCCESS;
+}
+/* }}} */ \ No newline at end of file
diff --git a/ext/phar/phar2.h b/ext/phar/phar2.h
new file mode 100644
index 0000000000..b35e636638
--- /dev/null
+++ b/ext/phar/phar2.h
@@ -0,0 +1,34 @@
+/*
+ +----------------------------------------------------------------------+
+ | phar php single-file executable PHP extension |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006-2007 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 <cellog@php.net> |
+ | Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+BEGIN_EXTERN_C()
+
+int phar2_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, long halt_offset, phar_archive_data** pphar, char *buffer, 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
+ */
diff --git a/ext/phar/phar2_openhash.c b/ext/phar/phar2_openhash.c
new file mode 100644
index 0000000000..47c7be656d
--- /dev/null
+++ b/ext/phar/phar2_openhash.c
@@ -0,0 +1,150 @@
+/*
+ +----------------------------------------------------------------------+
+ | phar open hash implementation for phar2 tar-based archives |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006-2007 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 <cellog@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "zend_hash.h"
+
+static inline int phar2_openhash_doublehash(ulong k, int m, int i) /* {{{ */
+{
+ /* implement double hash probing */
+ return ((k % m) + (i + (k % (m - 1)))) % m;
+}
+/* }}} */
+
+phar2_openhash *phar2_openhash_init(int large) /* {{{ */
+{
+ phar2_openhash *hash;
+ if (large) {
+ hash = (phar2_openhash *) ecalloc(sizeof(phar2_openhash_large));
+ } else {
+ hash = (phar2_openhash *) ecalloc(sizeof(phar2_openhash));
+ hash->is_large = '\001';
+ }
+ return hash;
+}
+/* }}} */
+
+int phar2_openhash_destroy(phar2_openhash *hash) /* {{{ */
+{
+ return efree(hash);
+}
+/* }}} */
+
+/* retrieve the offset of this file's manifest entry. Returns offset or -1 */
+long phar2_openhash_getoffset(phar2_openhash *hash, char *fname, int len) /* {{{ */
+{
+ int myhash, hashsize;
+ char substr[20];
+
+ memset((void *) substr, 0, 20);
+ if (len < 20) {
+ memcpy((void *) &substr, (void *) fname, len);
+ } else {
+ memcpy((void *) &substr, (void *) fname + (len - 20), 20);
+ }
+ hashsize = (hash->is_large ? PHAR2_HASHSIZE : PHAR2_HASHSIZE_SMALL);
+ for (i = 0; i < hashsize; i ++) {
+ myhash = phar2_openhash_doublehash(zhash, hashsize, i);
+ if (hash->info[myhash].filepart[0]) {
+ if (!memcmp(hash->info[myhash].filepart, substr, 20)) {
+ /* found it */
+ return hash->info[myhash].offset;
+ }
+ } else {
+ /* empty - does not exist */
+ return -1;
+ }
+ }
+ return -1;
+}
+/* }}} */
+
+static int phar2_openhash_insert_ex(phar2_openhash *hash, char* fname, ulong zhash, long offset) /* {{{ */
+{
+ int myhash, hashsize;
+ hashsize = (hash->is_large ? PHAR2_HASHSIZE : PHAR2_HASHSIZE_SMALL);
+ for (i = 0; i < hashsize; i ++) {
+ myhash = phar2_openhash_doublehash(zhash, hashsize, i);
+ if (hash->info[myhash].filepart[0]) {
+ continue;
+ } else {
+ memcpy((void *) &hash->info[myhash].filepart, (void *) fname, 20);
+ hash->info[myhash].offset = offset;
+ hash->info[myhash].zhash = zhash;
+ hash->count++;
+ return SUCCESS;
+ }
+ }
+ return FAILURE;
+}
+/* }}} */
+
+/* a super-large phar is being created, enlarge the hash and re-populate it */
+phar2_openhash_large *phar2_openhash_enlarge(phar2_openhash *hash) /* {{{ */
+{
+ phar_openhash_large *newhash = phar2_openhash_init(1);
+ for (phar2_openhash_entry s = newhash->info, int i = 0; i < hash->count; i++) {
+ if (!s[i].filepart[0]) {
+ continue;
+ }
+ phar2_openhash_insert_ex((phar2_openhash *)newhash, &(s[i].filepart), s[i].zhash, s[i].offset);
+ }
+ phar2_openhash_destroy(hash);
+ return newhash;
+}
+/* }}} */
+
+int phar2_openhash_insert(phar2_openhash *hash, char* fname, int len, long offset) /* {{{ */
+{
+ ulong zhash = zend_inline_hash_func(string, len);
+ char substr[20];
+
+ if (-1 != phar2_openhash_getoffset(hash, fname, len)) {
+ /* already exists, so fail */
+ return FAILURE;
+ }
+ if (hash->is_large) {
+ if (hash->count + 1 == PHAR_HASHSIZE) {
+ return FAILURE;
+ }
+ } else {
+ if (hash->count + 1 == PHAR_HASHSIZE_SMALL) {
+ /* resize for mega-huge phars */
+ hash = (phar2_openhash *) phar2_openhash_enlarge(hash);
+ }
+ }
+
+ memset((void *) substr, 0, 20);
+ if (len < 20) {
+ memcpy((void *) &substr, (void *) fname, len);
+ } else {
+ memcpy((void *) &substr, (void *) fname + (len - 20), 20);
+ }
+ return phar2_openhash_insert_ex(hash, substr, zhash, offset);
+}
+/* }}} */
+
+/*
+ * 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
+ */
diff --git a/ext/phar/phar2_openhash.h b/ext/phar/phar2_openhash.h
new file mode 100644
index 0000000000..f8ef10006e
--- /dev/null
+++ b/ext/phar/phar2_openhash.h
@@ -0,0 +1,59 @@
+/*
+ +----------------------------------------------------------------------+
+ | phar open hash implementation for phar2 tar-based archives |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006-2007 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 <cellog@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+/* maximum number of files that will fit into a phar */
+#define PHAR2_HASHSIZE_SMALL 997
+#define PHAR2_HASHSIZE 4999
+
+typedef struct _phar2_openhash_entry {
+ char[20] filepart; /* last 10 characters of filename */
+ long offset; /* offset of this file's info in the manifest */
+ ulong zhash; /* value of zend_inline_hash_func() on the filename */
+} phar2_openhash_entry;
+
+typedef struct _phar2_openhash {
+ char is_large; /* always 0 */
+ int count;
+ phar2_openhash_entry info[PHAR2_HASHSIZE_SMALL];
+} phar2_openhash;
+
+typedef struct _phar2_openhash {
+ char is_large; /* always 1 */
+ int count;
+ phar2_openhash_entry info[PHAR2_HASHSIZE];
+} phar2_openhash_large;
+
+BEGIN_EXTERN_C()
+
+phar2_openhash *phar2_openhash_init(int large);
+int phar2_openhash_destroy(phar2_openhash *hash);
+long phar2_openhash_getoffset(char *fname, int len);
+int phar2_openhash_insert(phar2_openhash *hash, char* fname, int len, long offset);
+
+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
+ */
diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h
index 0c4e85c436..e075ebdf01 100755
--- a/ext/phar/phar_internal.h
+++ b/ext/phar/phar_internal.h
@@ -30,6 +30,7 @@
#include "zend_execute.h"
#include "zend_exceptions.h"
#include "zend_hash.h"
+#include "ext/phar/phar2_openhash.h"
#include "zend_interfaces.h"
#include "zend_operators.h"
#include "zend_qsort.h"
@@ -65,12 +66,12 @@
#define E_RECOVERABLE_ERROR E_ERROR
#endif
-#define PHAR_EXT_VERSION_STR "1.3.0"
-#define PHAR_API_VERSION_STR "1.1.0"
+#define PHAR_EXT_VERSION_STR "2.0.0"
+#define PHAR_API_VERSION_STR "2.0.0"
/* x.y.z maps to 0xyz0 */
-#define PHAR_API_VERSION 0x1100
+#define PHAR_API_VERSION 0x2000
#define PHAR_API_MIN_READ 0x1000
-#define PHAR_API_MAJORVERSION 0x1000
+#define PHAR_API_MAJORVERSION 0x2000
#define PHAR_API_MAJORVER_MASK 0xF000
#define PHAR_API_VER_MASK 0xFFF0
@@ -106,6 +107,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phar)
HashTable phar_fname_map;
HashTable phar_alias_map;
HashTable phar_plain_map;
+ phar2_openhash *fast_fname_map;
char* extract_list;
int readonly;
zend_bool readonly_orig;