Back to index

php5  5.3.10
dirstream.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | phar:// stream wrapper support                                       |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 2005-2012 The PHP Group                                |
00006   +----------------------------------------------------------------------+
00007   | This source file is subject to version 3.01 of the PHP license,      |
00008   | that is bundled with this package in the file LICENSE, and is        |
00009   | available through the world-wide-web at the following url:           |
00010   | http://www.php.net/license/3_01.txt.                                 |
00011   | If you did not receive a copy of the PHP license and are unable to   |
00012   | obtain it through the world-wide-web, please send a note to          |
00013   | license@php.net so we can mail you a copy immediately.               |
00014   +----------------------------------------------------------------------+
00015   | Authors: Gregory Beaver <cellog@php.net>                             |
00016   |          Marcus Boerger <helly@php.net>                              |
00017   +----------------------------------------------------------------------+
00018 */
00019 
00020 #define PHAR_DIRSTREAM 1
00021 #include "phar_internal.h"
00022 #include "dirstream.h"
00023 
00024 BEGIN_EXTERN_C()
00025 void phar_dostat(phar_archive_data *phar, phar_entry_info *data, php_stream_statbuf *ssb, zend_bool is_dir TSRMLS_DC);
00026 END_EXTERN_C()
00027 
00028 php_stream_ops phar_dir_ops = {
00029        phar_dir_write, /* write */
00030        phar_dir_read,  /* read  */
00031        phar_dir_close, /* close */
00032        phar_dir_flush, /* flush */
00033        "phar dir",
00034        phar_dir_seek,  /* seek */
00035        NULL,           /* cast */
00036        NULL,           /* stat */
00037        NULL, /* set option */
00038 };
00039 
00043 static int phar_dir_close(php_stream *stream, int close_handle TSRMLS_DC)  /* {{{ */
00044 {
00045        HashTable *data = (HashTable *)stream->abstract;
00046 
00047        if (data && data->arBuckets) {
00048               zend_hash_destroy(data);
00049               data->arBuckets = 0;
00050               FREE_HASHTABLE(data);
00051               stream->abstract = NULL;
00052        }
00053 
00054        return 0;
00055 }
00056 /* }}} */
00057 
00061 static int phar_dir_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC) /* {{{ */
00062 {
00063        HashTable *data = (HashTable *)stream->abstract;
00064 
00065        if (!data) {
00066               return -1;
00067        }
00068 
00069        if (whence == SEEK_END) {
00070               whence = SEEK_SET;
00071               offset = zend_hash_num_elements(data) + offset;
00072        }
00073 
00074        if (whence == SEEK_SET) {
00075               zend_hash_internal_pointer_reset(data);
00076        }
00077 
00078        if (offset < 0) {
00079               return -1;
00080        } else {
00081               *newoffset = 0;
00082               while (*newoffset < offset && zend_hash_move_forward(data) == SUCCESS) {
00083                      ++(*newoffset);
00084               }
00085               return 0;
00086        }
00087 }
00088 /* }}} */
00089 
00093 static size_t phar_dir_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */
00094 {
00095        size_t to_read;
00096        HashTable *data = (HashTable *)stream->abstract;
00097        phar_zstr key;
00098        char *str_key;
00099        uint keylen;
00100        ulong unused;
00101 
00102        if (FAILURE == zend_hash_has_more_elements(data)) {
00103               return 0;
00104        }
00105 
00106        if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(data, &key, &keylen, &unused, 0, NULL)) {
00107               return 0;
00108        }
00109 
00110        PHAR_STR(key, str_key);
00111        zend_hash_move_forward(data);
00112        to_read = MIN(keylen, count);
00113 
00114        if (to_read == 0 || count < keylen) {
00115               PHAR_STR_FREE(str_key);
00116               return 0;
00117        }
00118 
00119        memset(buf, 0, sizeof(php_stream_dirent));
00120        memcpy(((php_stream_dirent *) buf)->d_name, str_key, to_read);
00121        PHAR_STR_FREE(str_key);
00122        ((php_stream_dirent *) buf)->d_name[to_read + 1] = '\0';
00123 
00124        return sizeof(php_stream_dirent);
00125 }
00126 /* }}} */
00127 
00131 static size_t phar_dir_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */
00132 {
00133        return 0;
00134 }
00135 /* }}} */
00136 
00140 static int phar_dir_flush(php_stream *stream TSRMLS_DC) /* {{{ */
00141 {
00142        return EOF;
00143 }
00144 /* }}} */
00145 
00152 static int phar_add_empty(HashTable *ht, char *arKey, uint nKeyLength)  /* {{{ */
00153 {
00154        void *dummy = (char *) 1;
00155 
00156        return zend_hash_update(ht, arKey, nKeyLength, (void *) &dummy, sizeof(void *), NULL);
00157 }
00158 /* }}} */
00159 
00163 static int phar_compare_dir_name(const void *a, const void *b TSRMLS_DC)  /* {{{ */
00164 {
00165        Bucket *f;
00166        Bucket *s;
00167        int result;
00168 
00169        f = *((Bucket **) a);
00170        s = *((Bucket **) b);
00171 #if (PHP_MAJOR_VERSION < 6)
00172        result = zend_binary_strcmp(f->arKey, f->nKeyLength, s->arKey, s->nKeyLength);
00173 #else
00174        result = zend_binary_strcmp(f->key.arKey.s, f->nKeyLength, s->key.arKey.s, s->nKeyLength);
00175 #endif
00176 
00177        if (result < 0) {
00178               return -1;
00179        } else if (result > 0) {
00180               return 1;
00181        } else {
00182               return 0;
00183        }
00184 }
00185 /* }}} */
00186 
00192 static php_stream *phar_make_dirstream(char *dir, HashTable *manifest TSRMLS_DC) /* {{{ */
00193 {
00194        HashTable *data;
00195        int dirlen = strlen(dir);
00196        phar_zstr key;
00197        char *entry, *found, *save, *str_key;
00198        uint keylen;
00199        ulong unused;
00200 
00201        ALLOC_HASHTABLE(data);
00202        zend_hash_init(data, 64, zend_get_hash_value, NULL, 0);
00203 
00204        if ((*dir == '/' && dirlen == 1 && (manifest->nNumOfElements == 0)) || (dirlen >= sizeof(".phar")-1 && !memcmp(dir, ".phar", sizeof(".phar")-1))) {
00205               /* make empty root directory for empty phar */
00206               /* make empty directory for .phar magic directory */
00207               efree(dir);
00208               return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
00209        }
00210 
00211        zend_hash_internal_pointer_reset(manifest);
00212 
00213        while (FAILURE != zend_hash_has_more_elements(manifest)) {
00214               if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(manifest, &key, &keylen, &unused, 0, NULL)) {
00215                      break;
00216               }
00217 
00218               PHAR_STR(key, str_key);
00219 
00220               if (keylen <= (uint)dirlen) {
00221                      if (keylen < (uint)dirlen || !strncmp(str_key, dir, dirlen)) {
00222                             PHAR_STR_FREE(str_key);
00223                             if (SUCCESS != zend_hash_move_forward(manifest)) {
00224                                    break;
00225                             }
00226                             continue;
00227                      }
00228               }
00229 
00230               if (*dir == '/') {
00231                      /* root directory */
00232                      if (keylen >= sizeof(".phar")-1 && !memcmp(str_key, ".phar", sizeof(".phar")-1)) {
00233                             PHAR_STR_FREE(str_key);
00234                             /* do not add any magic entries to this directory */
00235                             if (SUCCESS != zend_hash_move_forward(manifest)) {
00236                                    break;
00237                             }
00238                             continue;
00239                      }
00240 
00241                      if (NULL != (found = (char *) memchr(str_key, '/', keylen))) {
00242                             /* the entry has a path separator and is a subdirectory */
00243                             entry = (char *) safe_emalloc(found - str_key, 1, 1);
00244                             memcpy(entry, str_key, found - str_key);
00245                             keylen = found - str_key;
00246                             entry[keylen] = '\0';
00247                      } else {
00248                             entry = (char *) safe_emalloc(keylen, 1, 1);
00249                             memcpy(entry, str_key, keylen);
00250                             entry[keylen] = '\0';
00251                      }
00252 
00253                      PHAR_STR_FREE(str_key);
00254                      goto PHAR_ADD_ENTRY;
00255               } else {
00256                      if (0 != memcmp(str_key, dir, dirlen)) {
00257                             /* entry in directory not found */
00258                             PHAR_STR_FREE(str_key);
00259                             if (SUCCESS != zend_hash_move_forward(manifest)) {
00260                                    break;
00261                             }
00262                             continue;
00263                      } else {
00264                             if (str_key[dirlen] != '/') {
00265                                    PHAR_STR_FREE(str_key);
00266                                    if (SUCCESS != zend_hash_move_forward(manifest)) {
00267                                           break;
00268                                    }
00269                                    continue;
00270                             }
00271                      }
00272               }
00273 
00274               save = str_key;
00275               save += dirlen + 1; /* seek to just past the path separator */
00276 
00277               if (NULL != (found = (char *) memchr(save, '/', keylen - dirlen - 1))) {
00278                      /* is subdirectory */
00279                      save -= dirlen + 1;
00280                      entry = (char *) safe_emalloc(found - save + dirlen, 1, 1);
00281                      memcpy(entry, save + dirlen + 1, found - save - dirlen - 1);
00282                      keylen = found - save - dirlen - 1;
00283                      entry[keylen] = '\0';
00284               } else {
00285                      /* is file */
00286                      save -= dirlen + 1;
00287                      entry = (char *) safe_emalloc(keylen - dirlen, 1, 1);
00288                      memcpy(entry, save + dirlen + 1, keylen - dirlen - 1);
00289                      entry[keylen - dirlen - 1] = '\0';
00290                      keylen = keylen - dirlen - 1;
00291               }
00292               PHAR_STR_FREE(str_key);
00293 PHAR_ADD_ENTRY:
00294               if (keylen) {
00295                      phar_add_empty(data, entry, keylen);
00296               }
00297 
00298               efree(entry);
00299 
00300               if (SUCCESS != zend_hash_move_forward(manifest)) {
00301                      break;
00302               }
00303        }
00304 
00305        if (FAILURE != zend_hash_has_more_elements(data)) {
00306               efree(dir);
00307               if (zend_hash_sort(data, zend_qsort, phar_compare_dir_name, 0 TSRMLS_CC) == FAILURE) {
00308                      FREE_HASHTABLE(data);
00309                      return NULL;
00310               }
00311               return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
00312        } else {
00313               efree(dir);
00314               return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
00315        }
00316 }
00317 /* }}}*/
00318 
00322 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) /* {{{ */
00323 {
00324        php_url *resource = NULL;
00325        php_stream *ret;
00326        char *internal_file, *error, *str_key;
00327        phar_zstr key;
00328        uint keylen;
00329        ulong unused;
00330        phar_archive_data *phar;
00331        phar_entry_info *entry = NULL;
00332        uint host_len;
00333 
00334        if ((resource = phar_parse_url(wrapper, path, mode, options TSRMLS_CC)) == NULL) {
00335               php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar url \"%s\" is unknown", path);
00336               return NULL;
00337        }
00338 
00339        /* we must have at the very least phar://alias.phar/ */
00340        if (!resource->scheme || !resource->host || !resource->path) {
00341               if (resource->host && !resource->path) {
00342                      php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory (always use full path to a new phar)", path, resource->host);
00343                      php_url_free(resource);
00344                      return NULL;
00345               }
00346               php_url_free(resource);
00347               php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\", must have at least phar://%s/", path, path);
00348               return NULL;
00349        }
00350 
00351        if (strcasecmp("phar", resource->scheme)) {
00352               php_url_free(resource);
00353               php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar url \"%s\"", path);
00354               return NULL;
00355        }
00356 
00357        host_len = strlen(resource->host);
00358        phar_request_initialize(TSRMLS_C);
00359        internal_file = resource->path + 1; /* strip leading "/" */
00360 
00361        if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) {
00362               if (error) {
00363                      php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", error);
00364                      efree(error);
00365               } else {
00366                      php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar file \"%s\" is unknown", resource->host);
00367               }
00368               php_url_free(resource);
00369               return NULL;
00370        }
00371 
00372        if (error) {
00373               efree(error);
00374        }
00375 
00376        if (*internal_file == '\0') {
00377               /* root directory requested */
00378               internal_file = estrndup(internal_file - 1, 1);
00379               ret = phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC);
00380               php_url_free(resource);
00381               return ret;
00382        }
00383 
00384        if (!phar->manifest.arBuckets) {
00385               php_url_free(resource);
00386               return NULL;
00387        }
00388 
00389        if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, strlen(internal_file), (void**)&entry) && !entry->is_dir) {
00390               php_url_free(resource);
00391               return NULL;
00392        } else if (entry && entry->is_dir) {
00393               if (entry->is_mounted) {
00394                      php_url_free(resource);
00395                      return php_stream_opendir(entry->tmp, options, context);
00396               }
00397               internal_file = estrdup(internal_file);
00398               php_url_free(resource);
00399               return phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC);
00400        } else {
00401               int i_len = strlen(internal_file);
00402 
00403               /* search for directory */
00404               zend_hash_internal_pointer_reset(&phar->manifest);
00405               while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) {
00406                      if (HASH_KEY_NON_EXISTANT != 
00407                                    zend_hash_get_current_key_ex(
00408                                           &phar->manifest, &key, &keylen, &unused, 0, NULL)) {
00409                             PHAR_STR(key, str_key);
00410                             if (keylen > (uint)i_len && 0 == memcmp(str_key, internal_file, i_len)) {
00411                                    PHAR_STR_FREE(str_key);
00412                                    /* directory found */
00413                                    internal_file = estrndup(internal_file,
00414                                                  i_len);
00415                                    php_url_free(resource);
00416                                    return phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC);
00417                             }
00418                             PHAR_STR_FREE(str_key);
00419                      }
00420 
00421                      if (SUCCESS != zend_hash_move_forward(&phar->manifest)) {
00422                             break;
00423                      }
00424               }
00425        }
00426 
00427        php_url_free(resource);
00428        return NULL;
00429 }
00430 /* }}} */
00431 
00435 int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, int options, php_stream_context *context TSRMLS_DC) /* {{{ */
00436 {
00437        phar_entry_info entry, *e;
00438        phar_archive_data *phar = NULL;
00439        char *error, *arch, *entry2;
00440        int arch_len, entry_len;
00441        php_url *resource = NULL;
00442        uint host_len;
00443 
00444        /* pre-readonly check, we need to know if this is a data phar */
00445        if (FAILURE == phar_split_fname(url_from, strlen(url_from), &arch, &arch_len, &entry2, &entry_len, 2, 2 TSRMLS_CC)) {
00446               php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\", no phar archive specified", url_from);
00447               return 0;
00448        }
00449 
00450        if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
00451               phar = NULL;
00452        }
00453 
00454        efree(arch);
00455        efree(entry2);
00456 
00457        if (PHAR_G(readonly) && (!phar || !phar->is_data)) {
00458               php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\", write operations disabled", url_from);
00459               return 0;
00460        }
00461 
00462        if ((resource = phar_parse_url(wrapper, url_from, "w", options TSRMLS_CC)) == NULL) {
00463               return 0;
00464        }
00465 
00466        /* we must have at the very least phar://alias.phar/internalfile.php */
00467        if (!resource->scheme || !resource->host || !resource->path) {
00468               php_url_free(resource);
00469               php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url_from);
00470               return 0;
00471        }
00472 
00473        if (strcasecmp("phar", resource->scheme)) {
00474               php_url_free(resource);
00475               php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url_from);
00476               return 0;
00477        }
00478 
00479        host_len = strlen(resource->host);
00480 
00481        if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) {
00482               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);
00483               efree(error);
00484               php_url_free(resource);
00485               return 0;
00486        }
00487 
00488        if ((e = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 2, &error, 1 TSRMLS_CC))) {
00489               /* directory exists, or is a subdirectory of an existing file */
00490               if (e->is_temp_dir) {
00491                      efree(e->filename);
00492                      efree(e);
00493               }
00494               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);
00495               php_url_free(resource);
00496               return 0;
00497        }
00498 
00499        if (error) {
00500               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);
00501               efree(error);
00502               php_url_free(resource);
00503               return 0;
00504        }
00505 
00506        if (phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 0, &error, 1 TSRMLS_CC)) {
00507               /* entry exists as a file */
00508               php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", file already exists", resource->path+1, resource->host);
00509               php_url_free(resource);
00510               return 0;
00511        }
00512 
00513        if (error) {
00514               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);
00515               efree(error);
00516               php_url_free(resource);
00517               return 0;
00518        }
00519 
00520        memset((void *) &entry, 0, sizeof(phar_entry_info));
00521 
00522        /* strip leading "/" */
00523        if (phar->is_zip) {
00524               entry.is_zip = 1;
00525        }
00526 
00527        entry.filename = estrdup(resource->path + 1);
00528 
00529        if (phar->is_tar) {
00530               entry.is_tar = 1;
00531               entry.tar_type = TAR_DIR;
00532        }
00533 
00534        entry.filename_len = strlen(resource->path + 1);
00535        php_url_free(resource);
00536        entry.is_dir = 1;
00537        entry.phar = phar;
00538        entry.is_modified = 1;
00539        entry.is_crc_checked = 1;
00540        entry.flags = PHAR_ENT_PERM_DEF_DIR;
00541        entry.old_flags = PHAR_ENT_PERM_DEF_DIR;
00542 
00543        if (SUCCESS != zend_hash_add(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
00544               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);
00545               efree(error);
00546               efree(entry.filename);
00547               return 0;
00548        }
00549 
00550        phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
00551 
00552        if (error) {
00553               php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", entry.filename, phar->fname, error);
00554               zend_hash_del(&phar->manifest, entry.filename, entry.filename_len);
00555               efree(error);
00556               return 0;
00557        }
00558 
00559        phar_add_virtual_dirs(phar, entry.filename, entry.filename_len TSRMLS_CC);
00560        return 1;
00561 }
00562 /* }}} */
00563 
00567 int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC) /* {{{ */
00568 {
00569        phar_entry_info *entry;
00570        phar_archive_data *phar = NULL;
00571        char *error, *arch, *entry2;
00572        int arch_len, entry_len;
00573        php_url *resource = NULL;
00574        uint host_len;
00575        phar_zstr key;
00576        char *str_key;
00577        uint key_len;
00578        ulong unused;
00579        uint path_len;
00580 
00581        /* pre-readonly check, we need to know if this is a data phar */
00582        if (FAILURE == phar_split_fname(url, strlen(url), &arch, &arch_len, &entry2, &entry_len, 2, 2 TSRMLS_CC)) {
00583               php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\", no phar archive specified, or phar archive does not exist", url);
00584               return 0;
00585        }
00586 
00587        if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
00588               phar = NULL;
00589        }
00590 
00591        efree(arch);
00592        efree(entry2);
00593 
00594        if (PHAR_G(readonly) && (!phar || !phar->is_data)) {
00595               php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot rmdir directory \"%s\", write operations disabled", url);
00596               return 0;
00597        }
00598 
00599        if ((resource = phar_parse_url(wrapper, url, "w", options TSRMLS_CC)) == NULL) {
00600               return 0;
00601        }
00602 
00603        /* we must have at the very least phar://alias.phar/internalfile.php */
00604        if (!resource->scheme || !resource->host || !resource->path) {
00605               php_url_free(resource);
00606               php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url);
00607               return 0;
00608        }
00609 
00610        if (strcasecmp("phar", resource->scheme)) {
00611               php_url_free(resource);
00612               php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url);
00613               return 0;
00614        }
00615 
00616        host_len = strlen(resource->host);
00617 
00618        if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) {
00619               php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", error retrieving phar information: %s", resource->path+1, resource->host, error);
00620               efree(error);
00621               php_url_free(resource);
00622               return 0;
00623        }
00624 
00625        path_len = strlen(resource->path+1);
00626 
00627        if (!(entry = phar_get_entry_info_dir(phar, resource->path + 1, path_len, 2, &error, 1 TSRMLS_CC))) {
00628               if (error) {
00629                      php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error);
00630                      efree(error);
00631               } else {
00632                      php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", directory does not exist", resource->path+1, resource->host);
00633               }
00634               php_url_free(resource);
00635               return 0;
00636        }
00637 
00638        if (!entry->is_deleted) {
00639               for (zend_hash_internal_pointer_reset(&phar->manifest);
00640               HASH_KEY_NON_EXISTANT != zend_hash_get_current_key_ex(&phar->manifest, &key, &key_len, &unused, 0, NULL);
00641               zend_hash_move_forward(&phar->manifest)) {
00642 
00643                      PHAR_STR(key, str_key);
00644 
00645                      if (key_len > path_len && 
00646                             memcmp(str_key, resource->path+1, path_len) == 0 && 
00647                             IS_SLASH(str_key[path_len])) {
00648                             PHAR_STR_FREE(str_key);
00649                             php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: Directory not empty");
00650                             if (entry->is_temp_dir) {
00651                                    efree(entry->filename);
00652                                    efree(entry);
00653                             }
00654                             php_url_free(resource);
00655                             return 0;
00656                      }
00657                      PHAR_STR_FREE(str_key);
00658               }
00659 
00660               for (zend_hash_internal_pointer_reset(&phar->virtual_dirs);
00661                      HASH_KEY_NON_EXISTANT != zend_hash_get_current_key_ex(&phar->virtual_dirs, &key, &key_len, &unused, 0, NULL);
00662                      zend_hash_move_forward(&phar->virtual_dirs)) {
00663        
00664                      PHAR_STR(key, str_key);
00665        
00666                      if (key_len > path_len && 
00667                             memcmp(str_key, resource->path+1, path_len) == 0 && 
00668                             IS_SLASH(str_key[path_len])) {
00669                             PHAR_STR_FREE(str_key);
00670                             php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: Directory not empty");
00671                             if (entry->is_temp_dir) {
00672                                    efree(entry->filename);
00673                                    efree(entry);
00674                             }
00675                             php_url_free(resource);
00676                             return 0;
00677                      }
00678                      PHAR_STR_FREE(str_key);
00679               }
00680        }
00681 
00682        if (entry->is_temp_dir) {
00683               zend_hash_del(&phar->virtual_dirs, resource->path+1, path_len);
00684               efree(entry->filename);
00685               efree(entry);
00686        } else {
00687               entry->is_deleted = 1;
00688               entry->is_modified = 1;
00689               phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
00690 
00691               if (error) {
00692                      php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", entry->filename, phar->fname, error);
00693                      php_url_free(resource);
00694                      efree(error);
00695                      return 0;
00696               }
00697        }
00698 
00699        php_url_free(resource);
00700        return 1;
00701 }
00702 /* }}} */
00703 
00704 /*
00705  * Local variables:
00706  * tab-width: 4
00707  * c-basic-offset: 4
00708  * End:
00709  * vim600: noet sw=4 ts=4 fdm=marker
00710  * vim<600: noet sw=4 ts=4
00711  */