root/ext/phar/dirstream.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. phar_dir_close
  2. phar_dir_seek
  3. phar_dir_read
  4. phar_dir_write
  5. phar_dir_flush
  6. phar_add_empty
  7. phar_compare_dir_name
  8. phar_make_dirstream
  9. phar_wrapper_open_dir
  10. phar_wrapper_mkdir
  11. phar_wrapper_rmdir

   1 /*
   2   +----------------------------------------------------------------------+
   3   | phar:// stream wrapper support                                       |
   4   +----------------------------------------------------------------------+
   5   | Copyright (c) 2005-2016 The PHP Group                                |
   6   +----------------------------------------------------------------------+
   7   | This source file is subject to version 3.01 of the PHP license,      |
   8   | that is bundled with this package in the file LICENSE, and is        |
   9   | available through the world-wide-web at the following url:           |
  10   | http://www.php.net/license/3_01.txt.                                 |
  11   | If you did not receive a copy of the PHP license and are unable to   |
  12   | obtain it through the world-wide-web, please send a note to          |
  13   | license@php.net so we can mail you a copy immediately.               |
  14   +----------------------------------------------------------------------+
  15   | Authors: Gregory Beaver <cellog@php.net>                             |
  16   |          Marcus Boerger <helly@php.net>                              |
  17   +----------------------------------------------------------------------+
  18 */
  19 
  20 #define PHAR_DIRSTREAM 1
  21 #include "phar_internal.h"
  22 #include "dirstream.h"
  23 
  24 BEGIN_EXTERN_C()
  25 void phar_dostat(phar_archive_data *phar, phar_entry_info *data, php_stream_statbuf *ssb, zend_bool is_dir);
  26 END_EXTERN_C()
  27 
  28 php_stream_ops phar_dir_ops = {
  29         phar_dir_write, /* write */
  30         phar_dir_read,  /* read  */
  31         phar_dir_close, /* close */
  32         phar_dir_flush, /* flush */
  33         "phar dir",
  34         phar_dir_seek,  /* seek */
  35         NULL,           /* cast */
  36         NULL,           /* stat */
  37         NULL, /* set option */
  38 };
  39 
  40 /**
  41  * Used for closedir($fp) where $fp is an opendir('phar://...') directory handle
  42  */
  43 static int phar_dir_close(php_stream *stream, int close_handle)  /* {{{ */
  44 {
  45         HashTable *data = (HashTable *)stream->abstract;
  46 
  47         if (data && data->u.flags) {
  48                 zend_hash_destroy(data);
  49                 data->u.flags = 0;
  50                 FREE_HASHTABLE(data);
  51                 stream->abstract = NULL;
  52         }
  53 
  54         return 0;
  55 }
  56 /* }}} */
  57 
  58 /**
  59  * Used for seeking on a phar directory handle
  60  */
  61 static int phar_dir_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset) /* {{{ */
  62 {
  63         HashTable *data = (HashTable *)stream->abstract;
  64 
  65         if (!data) {
  66                 return -1;
  67         }
  68 
  69         if (whence == SEEK_END) {
  70                 whence = SEEK_SET;
  71                 offset = zend_hash_num_elements(data) + offset;
  72         }
  73 
  74         if (whence == SEEK_SET) {
  75                 zend_hash_internal_pointer_reset(data);
  76         }
  77 
  78         if (offset < 0) {
  79                 return -1;
  80         } else {
  81                 *newoffset = 0;
  82                 while (*newoffset < offset && zend_hash_move_forward(data) == SUCCESS) {
  83                         ++(*newoffset);
  84                 }
  85                 return 0;
  86         }
  87 }
  88 /* }}} */
  89 
  90 /**
  91  * Used for readdir() on an opendir()ed phar directory handle
  92  */
  93 static size_t phar_dir_read(php_stream *stream, char *buf, size_t count) /* {{{ */
  94 {
  95         size_t to_read;
  96         HashTable *data = (HashTable *)stream->abstract;
  97         zend_string *str_key;
  98         zend_ulong unused;
  99 
 100         if (HASH_KEY_NON_EXISTENT == zend_hash_get_current_key(data, &str_key, &unused)) {
 101                 return 0;
 102         }
 103 
 104         zend_hash_move_forward(data);
 105         to_read = MIN(ZSTR_LEN(str_key), count);
 106 
 107         if (to_read == 0 || count < ZSTR_LEN(str_key)) {
 108                 return 0;
 109         }
 110 
 111         memset(buf, 0, sizeof(php_stream_dirent));
 112         memcpy(((php_stream_dirent *) buf)->d_name, ZSTR_VAL(str_key), to_read);
 113         ((php_stream_dirent *) buf)->d_name[to_read + 1] = '\0';
 114 
 115         return sizeof(php_stream_dirent);
 116 }
 117 /* }}} */
 118 
 119 /**
 120  * Dummy: Used for writing to a phar directory (i.e. not used)
 121  */
 122 static size_t phar_dir_write(php_stream *stream, const char *buf, size_t count) /* {{{ */
 123 {
 124         return 0;
 125 }
 126 /* }}} */
 127 
 128 /**
 129  * Dummy: Used for flushing writes to a phar directory (i.e. not used)
 130  */
 131 static int phar_dir_flush(php_stream *stream) /* {{{ */
 132 {
 133         return EOF;
 134 }
 135 /* }}} */
 136 
 137 /**
 138  * add an empty element with a char * key to a hash table, avoiding duplicates
 139  *
 140  * This is used to get a unique listing of virtual directories within a phar,
 141  * for iterating over opendir()ed phar directories.
 142  */
 143 static int phar_add_empty(HashTable *ht, char *arKey, uint nKeyLength)  /* {{{ */
 144 {
 145         zval dummy;
 146 
 147         ZVAL_NULL(&dummy);
 148         return (zend_hash_str_update(ht, arKey, nKeyLength, &dummy) != NULL) ? SUCCESS : FAILURE;
 149 }
 150 /* }}} */
 151 
 152 /**
 153  * Used for sorting directories alphabetically
 154  */
 155 static int phar_compare_dir_name(const void *a, const void *b)  /* {{{ */
 156 {
 157         Bucket *f;
 158         Bucket *s;
 159         int result;
 160 
 161         f = (Bucket *) a;
 162         s = (Bucket *) b;
 163         result = zend_binary_strcmp(ZSTR_VAL(f->key), ZSTR_LEN(f->key), ZSTR_VAL(s->key), ZSTR_LEN(s->key));
 164 
 165         if (result < 0) {
 166                 return -1;
 167         } else if (result > 0) {
 168                 return 1;
 169         } else {
 170                 return 0;
 171         }
 172 }
 173 /* }}} */
 174 
 175 /**
 176  * Create a opendir() directory stream handle by iterating over each of the
 177  * files in a phar and retrieving its relative path.  From this, construct
 178  * a list of files/directories that are "in" the directory represented by dir
 179  */
 180 static php_stream *phar_make_dirstream(char *dir, HashTable *manifest) /* {{{ */
 181 {
 182         HashTable *data;
 183         int dirlen = strlen(dir);
 184         char *entry, *found, *save;
 185         zend_string *str_key;
 186         uint keylen;
 187         zend_ulong unused;
 188 
 189         ALLOC_HASHTABLE(data);
 190         zend_hash_init(data, 64, NULL, NULL, 0);
 191 
 192         if ((*dir == '/' && dirlen == 1 && (manifest->nNumOfElements == 0)) || (dirlen >= sizeof(".phar")-1 && !memcmp(dir, ".phar", sizeof(".phar")-1))) {
 193                 /* make empty root directory for empty phar */
 194                 /* make empty directory for .phar magic directory */
 195                 efree(dir);
 196                 return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
 197         }
 198 
 199         zend_hash_internal_pointer_reset(manifest);
 200 
 201         while (FAILURE != zend_hash_has_more_elements(manifest)) {
 202                 keylen = 0;
 203                 if (HASH_KEY_NON_EXISTENT == zend_hash_get_current_key(manifest, &str_key, &unused)) {
 204                         break;
 205                 }
 206 
 207                 keylen = ZSTR_LEN(str_key);
 208                 if (keylen <= (uint)dirlen) {
 209                         if (keylen == 0 || keylen < (uint)dirlen || !strncmp(ZSTR_VAL(str_key), dir, dirlen)) {
 210                                 if (SUCCESS != zend_hash_move_forward(manifest)) {
 211                                         break;
 212                                 }
 213                                 continue;
 214                         }
 215                 }
 216 
 217                 if (*dir == '/') {
 218                         /* root directory */
 219                         if (keylen >= sizeof(".phar")-1 && !memcmp(ZSTR_VAL(str_key), ".phar", sizeof(".phar")-1)) {
 220                                 /* do not add any magic entries to this directory */
 221                                 if (SUCCESS != zend_hash_move_forward(manifest)) {
 222                                         break;
 223                                 }
 224                                 continue;
 225                         }
 226 
 227                         if (NULL != (found = (char *) memchr(ZSTR_VAL(str_key), '/', keylen))) {
 228                                 /* the entry has a path separator and is a subdirectory */
 229                                 entry = (char *) safe_emalloc(found - ZSTR_VAL(str_key), 1, 1);
 230                                 memcpy(entry, ZSTR_VAL(str_key), found - ZSTR_VAL(str_key));
 231                                 keylen = found - ZSTR_VAL(str_key);
 232                                 entry[keylen] = '\0';
 233                         } else {
 234                                 entry = (char *) safe_emalloc(keylen, 1, 1);
 235                                 memcpy(entry, ZSTR_VAL(str_key), keylen);
 236                                 entry[keylen] = '\0';
 237                         }
 238 
 239                         goto PHAR_ADD_ENTRY;
 240                 } else {
 241                         if (0 != memcmp(ZSTR_VAL(str_key), dir, dirlen)) {
 242                                 /* entry in directory not found */
 243                                 if (SUCCESS != zend_hash_move_forward(manifest)) {
 244                                         break;
 245                                 }
 246                                 continue;
 247                         } else {
 248                                 if (ZSTR_VAL(str_key)[dirlen] != '/') {
 249                                         if (SUCCESS != zend_hash_move_forward(manifest)) {
 250                                                 break;
 251                                         }
 252                                         continue;
 253                                 }
 254                         }
 255                 }
 256 
 257                 save = ZSTR_VAL(str_key);
 258                 save += dirlen + 1; /* seek to just past the path separator */
 259 
 260                 if (NULL != (found = (char *) memchr(save, '/', keylen - dirlen - 1))) {
 261                         /* is subdirectory */
 262                         save -= dirlen + 1;
 263                         entry = (char *) safe_emalloc(found - save + dirlen, 1, 1);
 264                         memcpy(entry, save + dirlen + 1, found - save - dirlen - 1);
 265                         keylen = found - save - dirlen - 1;
 266                         entry[keylen] = '\0';
 267                 } else {
 268                         /* is file */
 269                         save -= dirlen + 1;
 270                         entry = (char *) safe_emalloc(keylen - dirlen, 1, 1);
 271                         memcpy(entry, save + dirlen + 1, keylen - dirlen - 1);
 272                         entry[keylen - dirlen - 1] = '\0';
 273                         keylen = keylen - dirlen - 1;
 274                 }
 275 PHAR_ADD_ENTRY:
 276                 if (keylen) {
 277                         phar_add_empty(data, entry, keylen);
 278                 }
 279 
 280                 efree(entry);
 281 
 282                 if (SUCCESS != zend_hash_move_forward(manifest)) {
 283                         break;
 284                 }
 285         }
 286 
 287         if (FAILURE != zend_hash_has_more_elements(data)) {
 288                 efree(dir);
 289                 if (zend_hash_sort(data, phar_compare_dir_name, 0) == FAILURE) {
 290                         FREE_HASHTABLE(data);
 291                         return NULL;
 292                 }
 293                 return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
 294         } else {
 295                 efree(dir);
 296                 return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
 297         }
 298 }
 299 /* }}}*/
 300 
 301 /**
 302  * Open a directory handle within a phar archive
 303  */
 304 php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, const char *path, const char *mode, int options, zend_string **opened_path, php_stream_context *context STREAMS_DC) /* {{{ */
 305 {
 306         php_url *resource = NULL;
 307         php_stream *ret;
 308         char *internal_file, *error;
 309         zend_string *str_key;
 310         zend_ulong unused;
 311         phar_archive_data *phar;
 312         phar_entry_info *entry = NULL;
 313         uint host_len;
 314 
 315         if ((resource = phar_parse_url(wrapper, path, mode, options)) == NULL) {
 316                 php_stream_wrapper_log_error(wrapper, options, "phar url \"%s\" is unknown", path);
 317                 return NULL;
 318         }
 319 
 320         /* we must have at the very least phar://alias.phar/ */
 321         if (!resource->scheme || !resource->host || !resource->path) {
 322                 if (resource->host && !resource->path) {
 323                         php_stream_wrapper_log_error(wrapper, options, "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);
 324                         php_url_free(resource);
 325                         return NULL;
 326                 }
 327                 php_url_free(resource);
 328                 php_stream_wrapper_log_error(wrapper, options, "phar error: invalid url \"%s\", must have at least phar://%s/", path, path);
 329                 return NULL;
 330         }
 331 
 332         if (strcasecmp("phar", resource->scheme)) {
 333                 php_url_free(resource);
 334                 php_stream_wrapper_log_error(wrapper, options, "phar error: not a phar url \"%s\"", path);
 335                 return NULL;
 336         }
 337 
 338         host_len = strlen(resource->host);
 339         phar_request_initialize();
 340         internal_file = resource->path + 1; /* strip leading "/" */
 341 
 342         if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error)) {
 343                 if (error) {
 344                         php_stream_wrapper_log_error(wrapper, options, "%s", error);
 345                         efree(error);
 346                 } else {
 347                         php_stream_wrapper_log_error(wrapper, options, "phar file \"%s\" is unknown", resource->host);
 348                 }
 349                 php_url_free(resource);
 350                 return NULL;
 351         }
 352 
 353         if (error) {
 354                 efree(error);
 355         }
 356 
 357         if (*internal_file == '\0') {
 358                 /* root directory requested */
 359                 internal_file = estrndup(internal_file - 1, 1);
 360                 ret = phar_make_dirstream(internal_file, &phar->manifest);
 361                 php_url_free(resource);
 362                 return ret;
 363         }
 364 
 365         if (!phar->manifest.u.flags) {
 366                 php_url_free(resource);
 367                 return NULL;
 368         }
 369 
 370         if (NULL != (entry = zend_hash_str_find_ptr(&phar->manifest, internal_file, strlen(internal_file))) && !entry->is_dir) {
 371                 php_url_free(resource);
 372                 return NULL;
 373         } else if (entry && entry->is_dir) {
 374                 if (entry->is_mounted) {
 375                         php_url_free(resource);
 376                         return php_stream_opendir(entry->tmp, options, context);
 377                 }
 378                 internal_file = estrdup(internal_file);
 379                 php_url_free(resource);
 380                 return phar_make_dirstream(internal_file, &phar->manifest);
 381         } else {
 382                 int i_len = strlen(internal_file);
 383 
 384                 /* search for directory */
 385                 zend_hash_internal_pointer_reset(&phar->manifest);
 386                 while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) {
 387                         if (HASH_KEY_NON_EXISTENT !=
 388                                         zend_hash_get_current_key(&phar->manifest, &str_key, &unused)) {
 389                                 if (ZSTR_LEN(str_key) > (uint)i_len && 0 == memcmp(ZSTR_VAL(str_key), internal_file, i_len)) {
 390                                         /* directory found */
 391                                         internal_file = estrndup(internal_file,
 392                                                         i_len);
 393                                         php_url_free(resource);
 394                                         return phar_make_dirstream(internal_file, &phar->manifest);
 395                                 }
 396                         }
 397 
 398                         if (SUCCESS != zend_hash_move_forward(&phar->manifest)) {
 399                                 break;
 400                         }
 401                 }
 402         }
 403 
 404         php_url_free(resource);
 405         return NULL;
 406 }
 407 /* }}} */
 408 
 409 /**
 410  * Make a new directory within a phar archive
 411  */
 412 int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mode, int options, php_stream_context *context) /* {{{ */
 413 {
 414         phar_entry_info entry, *e;
 415         phar_archive_data *phar = NULL;
 416         char *error, *arch, *entry2;
 417         int arch_len, entry_len;
 418         php_url *resource = NULL;
 419         uint host_len;
 420 
 421         /* pre-readonly check, we need to know if this is a data phar */
 422         if (FAILURE == phar_split_fname(url_from, strlen(url_from), &arch, &arch_len, &entry2, &entry_len, 2, 2)) {
 423                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\", no phar archive specified", url_from);
 424                 return 0;
 425         }
 426 
 427         if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) {
 428                 phar = NULL;
 429         }
 430 
 431         efree(arch);
 432         efree(entry2);
 433 
 434         if (PHAR_G(readonly) && (!phar || !phar->is_data)) {
 435                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\", write operations disabled", url_from);
 436                 return 0;
 437         }
 438 
 439         if ((resource = phar_parse_url(wrapper, url_from, "w", options)) == NULL) {
 440                 return 0;
 441         }
 442 
 443         /* we must have at the very least phar://alias.phar/internalfile.php */
 444         if (!resource->scheme || !resource->host || !resource->path) {
 445                 php_url_free(resource);
 446                 php_stream_wrapper_log_error(wrapper, options, "phar error: invalid url \"%s\"", url_from);
 447                 return 0;
 448         }
 449 
 450         if (strcasecmp("phar", resource->scheme)) {
 451                 php_url_free(resource);
 452                 php_stream_wrapper_log_error(wrapper, options, "phar error: not a phar stream url \"%s\"", url_from);
 453                 return 0;
 454         }
 455 
 456         host_len = strlen(resource->host);
 457 
 458         if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error)) {
 459                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", error retrieving phar information: %s", resource->path+1, resource->host, error);
 460                 efree(error);
 461                 php_url_free(resource);
 462                 return 0;
 463         }
 464 
 465         if ((e = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 2, &error, 1))) {
 466                 /* directory exists, or is a subdirectory of an existing file */
 467                 if (e->is_temp_dir) {
 468                         efree(e->filename);
 469                         efree(e);
 470                 }
 471                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", directory already exists", resource->path+1, resource->host);
 472                 php_url_free(resource);
 473                 return 0;
 474         }
 475 
 476         if (error) {
 477                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error);
 478                 efree(error);
 479                 php_url_free(resource);
 480                 return 0;
 481         }
 482 
 483         if (phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 0, &error, 1)) {
 484                 /* entry exists as a file */
 485                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", file already exists", resource->path+1, resource->host);
 486                 php_url_free(resource);
 487                 return 0;
 488         }
 489 
 490         if (error) {
 491                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error);
 492                 efree(error);
 493                 php_url_free(resource);
 494                 return 0;
 495         }
 496 
 497         memset((void *) &entry, 0, sizeof(phar_entry_info));
 498 
 499         /* strip leading "/" */
 500         if (phar->is_zip) {
 501                 entry.is_zip = 1;
 502         }
 503 
 504         entry.filename = estrdup(resource->path + 1);
 505 
 506         if (phar->is_tar) {
 507                 entry.is_tar = 1;
 508                 entry.tar_type = TAR_DIR;
 509         }
 510 
 511         entry.filename_len = strlen(resource->path + 1);
 512         php_url_free(resource);
 513         entry.is_dir = 1;
 514         entry.phar = phar;
 515         entry.is_modified = 1;
 516         entry.is_crc_checked = 1;
 517         entry.flags = PHAR_ENT_PERM_DEF_DIR;
 518         entry.old_flags = PHAR_ENT_PERM_DEF_DIR;
 519 
 520         if (NULL == zend_hash_str_add_mem(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info))) {
 521                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", adding to manifest failed", entry.filename, phar->fname);
 522                 efree(error);
 523                 efree(entry.filename);
 524                 return 0;
 525         }
 526 
 527         phar_flush(phar, 0, 0, 0, &error);
 528 
 529         if (error) {
 530                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", entry.filename, phar->fname, error);
 531                 zend_hash_str_del(&phar->manifest, entry.filename, entry.filename_len);
 532                 efree(error);
 533                 return 0;
 534         }
 535 
 536         phar_add_virtual_dirs(phar, entry.filename, entry.filename_len);
 537         return 1;
 538 }
 539 /* }}} */
 540 
 541 /**
 542  * Remove a directory within a phar archive
 543  */
 544 int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context) /* {{{ */
 545 {
 546         phar_entry_info *entry;
 547         phar_archive_data *phar = NULL;
 548         char *error, *arch, *entry2;
 549         int arch_len, entry_len;
 550         php_url *resource = NULL;
 551         uint host_len;
 552         zend_string *str_key;
 553         zend_ulong unused;
 554         uint path_len;
 555 
 556         /* pre-readonly check, we need to know if this is a data phar */
 557         if (FAILURE == phar_split_fname(url, strlen(url), &arch, &arch_len, &entry2, &entry_len, 2, 2)) {
 558                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot remove directory \"%s\", no phar archive specified, or phar archive does not exist", url);
 559                 return 0;
 560         }
 561 
 562         if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) {
 563                 phar = NULL;
 564         }
 565 
 566         efree(arch);
 567         efree(entry2);
 568 
 569         if (PHAR_G(readonly) && (!phar || !phar->is_data)) {
 570                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot rmdir directory \"%s\", write operations disabled", url);
 571                 return 0;
 572         }
 573 
 574         if ((resource = phar_parse_url(wrapper, url, "w", options)) == NULL) {
 575                 return 0;
 576         }
 577 
 578         /* we must have at the very least phar://alias.phar/internalfile.php */
 579         if (!resource->scheme || !resource->host || !resource->path) {
 580                 php_url_free(resource);
 581                 php_stream_wrapper_log_error(wrapper, options, "phar error: invalid url \"%s\"", url);
 582                 return 0;
 583         }
 584 
 585         if (strcasecmp("phar", resource->scheme)) {
 586                 php_url_free(resource);
 587                 php_stream_wrapper_log_error(wrapper, options, "phar error: not a phar stream url \"%s\"", url);
 588                 return 0;
 589         }
 590 
 591         host_len = strlen(resource->host);
 592 
 593         if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error)) {
 594                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot remove directory \"%s\" in phar \"%s\", error retrieving phar information: %s", resource->path+1, resource->host, error);
 595                 efree(error);
 596                 php_url_free(resource);
 597                 return 0;
 598         }
 599 
 600         path_len = strlen(resource->path+1);
 601 
 602         if (!(entry = phar_get_entry_info_dir(phar, resource->path + 1, path_len, 2, &error, 1))) {
 603                 if (error) {
 604                         php_stream_wrapper_log_error(wrapper, options, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error);
 605                         efree(error);
 606                 } else {
 607                         php_stream_wrapper_log_error(wrapper, options, "phar error: cannot remove directory \"%s\" in phar \"%s\", directory does not exist", resource->path+1, resource->host);
 608                 }
 609                 php_url_free(resource);
 610                 return 0;
 611         }
 612 
 613         if (!entry->is_deleted) {
 614                 for (zend_hash_internal_pointer_reset(&phar->manifest);
 615                         HASH_KEY_NON_EXISTENT != zend_hash_get_current_key(&phar->manifest, &str_key, &unused);
 616                         zend_hash_move_forward(&phar->manifest)
 617                 ) {
 618                         if (ZSTR_LEN(str_key) > path_len &&
 619                                 memcmp(ZSTR_VAL(str_key), resource->path+1, path_len) == 0 &&
 620                                 IS_SLASH(ZSTR_VAL(str_key)[path_len])) {
 621                                 php_stream_wrapper_log_error(wrapper, options, "phar error: Directory not empty");
 622                                 if (entry->is_temp_dir) {
 623                                         efree(entry->filename);
 624                                         efree(entry);
 625                                 }
 626                                 php_url_free(resource);
 627                                 return 0;
 628                         }
 629                 }
 630 
 631                 for (zend_hash_internal_pointer_reset(&phar->virtual_dirs);
 632                         HASH_KEY_NON_EXISTENT != zend_hash_get_current_key(&phar->virtual_dirs, &str_key, &unused);
 633                         zend_hash_move_forward(&phar->virtual_dirs)) {
 634 
 635                         if (ZSTR_LEN(str_key) > path_len &&
 636                                 memcmp(ZSTR_VAL(str_key), resource->path+1, path_len) == 0 &&
 637                                 IS_SLASH(ZSTR_VAL(str_key)[path_len])) {
 638                                 php_stream_wrapper_log_error(wrapper, options, "phar error: Directory not empty");
 639                                 if (entry->is_temp_dir) {
 640                                         efree(entry->filename);
 641                                         efree(entry);
 642                                 }
 643                                 php_url_free(resource);
 644                                 return 0;
 645                         }
 646                 }
 647         }
 648 
 649         if (entry->is_temp_dir) {
 650                 zend_hash_str_del(&phar->virtual_dirs, resource->path+1, path_len);
 651                 efree(entry->filename);
 652                 efree(entry);
 653         } else {
 654                 entry->is_deleted = 1;
 655                 entry->is_modified = 1;
 656                 phar_flush(phar, 0, 0, 0, &error);
 657 
 658                 if (error) {
 659                         php_stream_wrapper_log_error(wrapper, options, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", entry->filename, phar->fname, error);
 660                         php_url_free(resource);
 661                         efree(error);
 662                         return 0;
 663                 }
 664         }
 665 
 666         php_url_free(resource);
 667         return 1;
 668 }
 669 /* }}} */
 670 
 671 /*
 672  * Local variables:
 673  * tab-width: 4
 674  * c-basic-offset: 4
 675  * End:
 676  * vim600: noet sw=4 ts=4 fdm=marker
 677  * vim<600: noet sw=4 ts=4
 678  */

/* [<][>][^][v][top][bottom][index][help] */