From 1a3624494e04c8b9092b6f8f440824acaadee1b9 Mon Sep 17 00:00:00 2001 From: Greg Beaver Date: Tue, 8 Jan 2008 22:14:16 +0000 Subject: [PATCH] implement mkdir (compiles, not yet tested), support for empty directories in phar (not yet tested) revert last commit of efree(), it's necessary. --- ext/phar/dirstream.c | 106 +++++++++++++++++++++++++++++++++++++++ ext/phar/dirstream.h | 2 + ext/phar/phar.c | 34 +++++++++---- ext/phar/phar_internal.h | 9 +++- ext/phar/phar_object.c | 4 +- ext/phar/stream.c | 3 +- ext/phar/tar.c | 6 --- 7 files changed, 144 insertions(+), 20 deletions(-) diff --git a/ext/phar/dirstream.c b/ext/phar/dirstream.c index 63d960c337..74d3e7177c 100644 --- a/ext/phar/dirstream.c +++ b/ext/phar/dirstream.c @@ -391,3 +391,109 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, char *path, char return NULL; } /* }}} */ + +/** + * Make a new directory within a phar archive + */ +int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, int options, php_stream_context *context TSRMLS_DC) /* {{{ */ +{ + phar_entry_info entry; + phar_archive_data *phar; + char *error; + char *plain_map; + php_url *resource = NULL; + uint host_len; + + if ((resource = phar_open_url(wrapper, url_from, "w", options TSRMLS_CC)) == NULL) { + return FAILURE; + } + + /* we must have at the very least phar://alias.phar/internalfile.php */ + if (!resource->scheme || !resource->host || !resource->path) { + php_url_free(resource); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url_from); + return FAILURE; + } + + if (strcasecmp("phar", resource->scheme)) { + php_url_free(resource); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url_from); + return FAILURE; + } + + host_len = strlen(resource->host); + phar_request_initialize(TSRMLS_C); + if (zend_hash_find(&(PHAR_GLOBALS->phar_plain_map), resource->host, host_len+1, (void **)&plain_map) == SUCCESS) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: directory \"%s\" cannot be created in phar \"%s\", phar is extracted in plain map", resource->path+1, resource->host); + php_url_free(resource); + return FAILURE; + } + + if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", error retrieving phar information: %s", resource->path+1, resource->host, error); + efree(error); + php_url_free(resource); + return FAILURE; + } + + if (phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 1, &error TSRMLS_CC)) { + /* directory exists, or is a subdirectory of an existing file */ + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", directory already exists", resource->path+1, resource->host); + php_url_free(resource); + return FAILURE; + } + if (error) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error); + efree(error); + php_url_free(resource); + return FAILURE; + } + + memset((void *) &entry, 0, sizeof(phar_entry_info)); + + /* strip leading "/" */ +#if HAVE_PHAR_ZIP + if (phar->is_zip) { + entry.is_zip = 1; + /* prevent attempts to check the CRC */ + entry.index = -1; + } +#endif + entry.filename = estrdup(resource->path + 1); + if (phar->is_tar) { + entry.is_tar = 1; + entry.tar_type = TAR_DIR; + } + entry.filename_len = strlen(resource->path + 1); + php_url_free(resource); + entry.is_dir = 1; + entry.phar = phar; + entry.is_modified = 1; + entry.is_crc_checked = 1; + entry.flags = PHAR_ENT_PERM_DEF_DIR; + entry.old_flags = PHAR_ENT_PERM_DEF_DIR; + if (SUCCESS != zend_hash_add(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", adding to manifest failed", entry.filename, phar->fname); + efree(error); + efree(entry.filename); + return FAILURE; + } + phar_flush(phar, 0, 0, &error TSRMLS_CC); + if (error) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", entry.filename, phar->fname, error); + zend_hash_del(&phar->manifest, entry.filename, entry.filename_len); + efree(error); + efree(entry.filename); + return FAILURE; + } + return SUCCESS; +} +/* }}} */ + +/** + * Remove a directory within a phar archive + */ +int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC) /* {{{ */ +{ +} +/* }}} */ diff --git a/ext/phar/dirstream.h b/ext/phar/dirstream.h index d06a45a8c6..9326d9e0ec 100644 --- a/ext/phar/dirstream.h +++ b/ext/phar/dirstream.h @@ -21,6 +21,8 @@ BEGIN_EXTERN_C() php_stream* phar_wrapper_open_dir(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC); +int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, int options, php_stream_context *context TSRMLS_DC); +int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC); #ifdef PHAR_DIRSTREAM php_url* phar_open_url(php_stream_wrapper *wrapper, char *filename, char *mode, int options TSRMLS_DC); diff --git a/ext/phar/phar.c b/ext/phar/phar.c index ef2c7d8c7e..f637ec861e 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -468,9 +468,8 @@ phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, in } /* found a file in this path */ entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info)); - entry->is_dir = 1; /* this next line tells PharFileInfo->__destruct() to efree the filename */ - entry->is_zip = entry->is_tar = 0; + entry->is_temp_dir = entry->is_dir = 1; entry->filename = (char *) estrndup(path, path_len + 1); entry->filename_len = path_len; return entry; @@ -764,15 +763,13 @@ phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char /* prevent attempts to check the CRC */ etemp.is_crc_checked = 1; etemp.index = -1; - etemp.filename = estrndup(path, path_len); - } else { - etemp.is_tar = phar->is_tar; - etemp.tar_type = '0'; - etemp.filename = estrndup(path, path_len); } -#else - etemp.filename = estrndup(path, path_len); #endif + etemp.filename = estrndup(path, path_len); + if (phar->is_tar) { + etemp.is_tar = phar->is_tar; + etemp.tar_type = TAR_FILE; + } zend_hash_add(&phar->manifest, etemp.filename, path_len, (void*)&etemp, sizeof(phar_entry_info), (void **) &entry); if (!entry) { @@ -1293,8 +1290,15 @@ int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int if (buffer + entry.filename_len + 20 > endbuffer) { MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)"); } + if (buffer[entry.filename_len - 1] == '/') { + entry.is_dir = 1; + entry.filename_len--; + entry.flags |= PHAR_ENT_PERM_DEF_DIR; + } else { + entry.is_dir = 0; + } entry.filename = estrndup(buffer, entry.filename_len); - buffer += entry.filename_len; + buffer += entry.filename_len + entry.is_dir; PHAR_GET_32(buffer, entry.uncompressed_filesize); PHAR_GET_32(buffer, entry.timestamp); if (offset == 0) { @@ -2627,6 +2631,16 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len, char **err } return EOF; } + if (entry->is_dir && 1 != php_stream_write(newfile, "/", 1)) { + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + if (error) { + spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", entry->filename, archive->fname); + } + return EOF; + } /* set the manifest meta-data: 4: uncompressed filesize 4: creation timestamp diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index 8b3bb96692..fe98c6061e 100755 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -115,6 +115,12 @@ #define PHAR_ENT_PERM_DEF_FILE 0x000001B6 #define PHAR_ENT_PERM_DEF_DIR 0x000001FF +#define TAR_FILE '0' +#define TAR_LINK '1' +#define TAR_SYMLINK '2' +#define TAR_DIR '5' +#define TAR_NEW '8' + ZEND_BEGIN_MODULE_GLOBALS(phar) HashTable phar_fname_map; HashTable phar_alias_map; @@ -182,8 +188,9 @@ typedef struct _phar_entry_info { int is_crc_checked:1; int is_modified:1; int is_deleted:1; - /* used when iterating */ int is_dir:1; + /* used when iterating */ + int is_temp_dir:1; phar_archive_data *phar; smart_str metadata_str; /* tar-based phar file stuff */ diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index df3d25024e..f2f7a3aa0b 100755 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -2252,7 +2252,7 @@ PHP_METHOD(PharFileInfo, __destruct) { PHAR_ENTRY_OBJECT(); - if (entry_obj->ent.entry->is_dir&& !entry_obj->ent.entry->is_zip && !entry_obj->ent.entry->is_tar) { + if (entry_obj->ent.entry->is_temp_dir) { if (entry_obj->ent.entry->filename) { efree(entry_obj->ent.entry->filename); entry_obj->ent.entry->filename = NULL; @@ -2358,7 +2358,7 @@ PHP_METHOD(PharFileInfo, chmod) long perms; PHAR_ENTRY_OBJECT(); - if (entry_obj->ent.entry->is_dir && (!entry_obj->ent.entry->is_tar && !entry_obj->ent.entry->is_zip)) { + if (entry_obj->ent.entry->is_temp_dir) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \ "Phar entry is a directory, cannot chmod"); \ return; diff --git a/ext/phar/stream.c b/ext/phar/stream.c index 2c10800d62..047483c99e 100644 --- a/ext/phar/stream.c +++ b/ext/phar/stream.c @@ -176,8 +176,9 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *pat if (zend_hash_find(&(PHAR_GLOBALS->phar_plain_map), resource->host, host_len+1, (void **)&plain_map) == SUCCESS) { spprintf(&internal_file, 0, "%s%s", plain_map, resource->path); fp = php_stream_open_wrapper_ex(internal_file, mode, options, opened_path, context); + efree(internal_file); if (!fp) { - php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: file \"%s\" extracted from \"%s\" could not be opened", internal_file, resource->host); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: file \"%s\" extracted from \"%s\" could not be opened", resource->path+1, resource->host); } php_url_free(resource); return fp; diff --git a/ext/phar/tar.c b/ext/phar/tar.c index 23ba450c41..b8594a4e6d 100644 --- a/ext/phar/tar.c +++ b/ext/phar/tar.c @@ -19,12 +19,6 @@ #include "phar_internal.h" -#define TAR_FILE '0' -#define TAR_LINK '1' -#define TAR_SYMLINK '2' -#define TAR_DIR '5' -#define TAR_NEW '8' - static php_uint32 phar_tar_number(char *buf, int len) /* {{{ */ { php_uint32 num = 0; -- 2.40.0