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 TSRMLS_DC);
  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 TSRMLS_DC)  /* {{{ */
  44 {
  45         HashTable *data = (HashTable *)stream->abstract;
  46 
  47         if (data && data->arBuckets) {
  48                 zend_hash_destroy(data);
  49                 data->arBuckets = 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, off_t offset, int whence, off_t *newoffset TSRMLS_DC) /* {{{ */
  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 TSRMLS_DC) /* {{{ */
  94 {
  95         size_t to_read;
  96         HashTable *data = (HashTable *)stream->abstract;
  97         char *str_key;
  98         uint keylen;
  99         ulong unused;
 100 
 101         if (HASH_KEY_NON_EXISTENT == zend_hash_get_current_key_ex(data, &str_key, &keylen, &unused, 0, NULL)) {
 102                 return 0;
 103         }
 104 
 105         zend_hash_move_forward(data);
 106         to_read = MIN(keylen, count);
 107 
 108         if (to_read == 0 || count < keylen) {
 109                 return 0;
 110         }
 111 
 112         memset(buf, 0, sizeof(php_stream_dirent));
 113         memcpy(((php_stream_dirent *) buf)->d_name, str_key, to_read);
 114         ((php_stream_dirent *) buf)->d_name[to_read + 1] = '\0';
 115 
 116         return sizeof(php_stream_dirent);
 117 }
 118 /* }}} */
 119 
 120 /**
 121  * Dummy: Used for writing to a phar directory (i.e. not used)
 122  */
 123 static size_t phar_dir_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */
 124 {
 125         return 0;
 126 }
 127 /* }}} */
 128 
 129 /**
 130  * Dummy: Used for flushing writes to a phar directory (i.e. not used)
 131  */
 132 static int phar_dir_flush(php_stream *stream TSRMLS_DC) /* {{{ */
 133 {
 134         return EOF;
 135 }
 136 /* }}} */
 137 
 138 /**
 139  * add an empty element with a char * key to a hash table, avoiding duplicates
 140  *
 141  * This is used to get a unique listing of virtual directories within a phar,
 142  * for iterating over opendir()ed phar directories.
 143  */
 144 static int phar_add_empty(HashTable *ht, char *arKey, uint nKeyLength)  /* {{{ */
 145 {
 146         void *dummy = (char *) 1;
 147 
 148         return zend_hash_update(ht, arKey, nKeyLength, (void *) &dummy, sizeof(void *), NULL);
 149 }
 150 /* }}} */
 151 
 152 /**
 153  * Used for sorting directories alphabetically
 154  */
 155 static int phar_compare_dir_name(const void *a, const void *b TSRMLS_DC)  /* {{{ */
 156 {
 157         Bucket *f;
 158         Bucket *s;
 159         int result;
 160 
 161         f = *((Bucket **) a);
 162         s = *((Bucket **) b);
 163         result = zend_binary_strcmp(f->arKey, f->nKeyLength, s->arKey, s->nKeyLength);
 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 TSRMLS_DC) /* {{{ */
 181 {
 182         HashTable *data;
 183         int dirlen = strlen(dir);
 184         char *entry, *found, *save, *str_key;
 185         uint keylen;
 186         ulong unused;
 187 
 188         ALLOC_HASHTABLE(data);
 189         zend_hash_init(data, 64, NULL, NULL, 0);
 190 
 191         if ((*dir == '/' && dirlen == 1 && (manifest->nNumOfElements == 0)) || (dirlen >= sizeof(".phar")-1 && !memcmp(dir, ".phar", sizeof(".phar")-1))) {
 192                 /* make empty root directory for empty phar */
 193                 /* make empty directory for .phar magic directory */
 194                 efree(dir);
 195                 return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
 196         }
 197 
 198         zend_hash_internal_pointer_reset(manifest);
 199 
 200         while (FAILURE != zend_hash_has_more_elements(manifest)) {
 201                 keylen = 0;
 202                 if (HASH_KEY_NON_EXISTENT == zend_hash_get_current_key_ex(manifest, &str_key, &keylen, &unused, 0, NULL)) {
 203                         break;
 204                 }
 205 
 206                 if (keylen <= (uint)dirlen) {
 207                         if (keylen == 0 || keylen < (uint)dirlen || !strncmp(str_key, dir, dirlen)) {
 208                                 if (SUCCESS != zend_hash_move_forward(manifest)) {
 209                                         break;
 210                                 }
 211                                 continue;
 212                         }
 213                 }
 214 
 215                 if (*dir == '/') {
 216                         /* root directory */
 217                         if (keylen >= sizeof(".phar")-1 && !memcmp(str_key, ".phar", sizeof(".phar")-1)) {
 218                                 /* do not add any magic entries to this directory */
 219                                 if (SUCCESS != zend_hash_move_forward(manifest)) {
 220                                         break;
 221                                 }
 222                                 continue;
 223                         }
 224 
 225                         if (NULL != (found = (char *) memchr(str_key, '/', keylen))) {
 226                                 /* the entry has a path separator and is a subdirectory */
 227                                 entry = (char *) safe_emalloc(found - str_key, 1, 1);
 228                                 memcpy(entry, str_key, found - str_key);
 229                                 keylen = found - str_key;
 230                                 entry[keylen] = '\0';
 231                         } else {
 232                                 entry = (char *) safe_emalloc(keylen, 1, 1);
 233                                 memcpy(entry, str_key, keylen);
 234                                 entry[keylen] = '\0';
 235                         }
 236 
 237                         goto PHAR_ADD_ENTRY;
 238                 } else {
 239                         if (0 != memcmp(str_key, dir, dirlen)) {
 240                                 /* entry in directory not found */
 241                                 if (SUCCESS != zend_hash_move_forward(manifest)) {
 242                                         break;
 243                                 }
 244                                 continue;
 245                         } else {
 246                                 if (str_key[dirlen] != '/') {
 247                                         if (SUCCESS != zend_hash_move_forward(manifest)) {
 248                                                 break;
 249                                         }
 250                                         continue;
 251                                 }
 252                         }
 253                 }
 254 
 255                 save = str_key;
 256                 save += dirlen + 1; /* seek to just past the path separator */
 257 
 258                 if (NULL != (found = (char *) memchr(save, '/', keylen - dirlen - 1))) {
 259                         /* is subdirectory */
 260                         save -= dirlen + 1;
 261                         entry = (char *) safe_emalloc(found - save + dirlen, 1, 1);
 262                         memcpy(entry, save + dirlen + 1, found - save - dirlen - 1);
 263                         keylen = found - save - dirlen - 1;
 264                         entry[keylen] = '\0';
 265                 } else {
 266                         /* is file */
 267                         save -= dirlen + 1;
 268                         entry = (char *) safe_emalloc(keylen - dirlen, 1, 1);
 269                         memcpy(entry, save + dirlen + 1, keylen - dirlen - 1);
 270                         entry[keylen - dirlen - 1] = '\0';
 271                         keylen = keylen - dirlen - 1;
 272                 }
 273 PHAR_ADD_ENTRY:
 274                 if (keylen) {
 275                         phar_add_empty(data, entry, keylen);
 276                 }
 277 
 278                 efree(entry);
 279 
 280                 if (SUCCESS != zend_hash_move_forward(manifest)) {
 281                         break;
 282                 }
 283         }
 284 
 285         if (FAILURE != zend_hash_has_more_elements(data)) {
 286                 efree(dir);
 287                 if (zend_hash_sort(data, zend_qsort, phar_compare_dir_name, 0 TSRMLS_CC) == FAILURE) {
 288                         FREE_HASHTABLE(data);
 289                         return NULL;
 290                 }
 291                 return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
 292         } else {
 293                 efree(dir);
 294                 return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
 295         }
 296 }
 297 /* }}}*/
 298 
 299 /**
 300  * Open a directory handle within a phar archive
 301  */
 302 php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, const char *path, const char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) /* {{{ */
 303 {
 304         php_url *resource = NULL;
 305         php_stream *ret;
 306         char *internal_file, *error, *str_key;
 307         uint keylen;
 308         ulong unused;
 309         phar_archive_data *phar;
 310         phar_entry_info *entry = NULL;
 311         uint host_len;
 312 
 313         if ((resource = phar_parse_url(wrapper, path, mode, options TSRMLS_CC)) == NULL) {
 314                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar url \"%s\" is unknown", path);
 315                 return NULL;
 316         }
 317 
 318         /* we must have at the very least phar://alias.phar/ */
 319         if (!resource->scheme || !resource->host || !resource->path) {
 320                 if (resource->host && !resource->path) {
 321                         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);
 322                         php_url_free(resource);
 323                         return NULL;
 324                 }
 325                 php_url_free(resource);
 326                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\", must have at least phar://%s/", path, path);
 327                 return NULL;
 328         }
 329 
 330         if (strcasecmp("phar", resource->scheme)) {
 331                 php_url_free(resource);
 332                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar url \"%s\"", path);
 333                 return NULL;
 334         }
 335 
 336         host_len = strlen(resource->host);
 337         phar_request_initialize(TSRMLS_C);
 338         internal_file = resource->path + 1; /* strip leading "/" */
 339 
 340         if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) {
 341                 if (error) {
 342                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", error);
 343                         efree(error);
 344                 } else {
 345                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar file \"%s\" is unknown", resource->host);
 346                 }
 347                 php_url_free(resource);
 348                 return NULL;
 349         }
 350 
 351         if (error) {
 352                 efree(error);
 353         }
 354 
 355         if (*internal_file == '\0') {
 356                 /* root directory requested */
 357                 internal_file = estrndup(internal_file - 1, 1);
 358                 ret = phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC);
 359                 php_url_free(resource);
 360                 return ret;
 361         }
 362 
 363         if (!phar->manifest.arBuckets) {
 364                 php_url_free(resource);
 365                 return NULL;
 366         }
 367 
 368         if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, strlen(internal_file), (void**)&entry) && !entry->is_dir) {
 369                 php_url_free(resource);
 370                 return NULL;
 371         } else if (entry && entry->is_dir) {
 372                 if (entry->is_mounted) {
 373                         php_url_free(resource);
 374                         return php_stream_opendir(entry->tmp, options, context);
 375                 }
 376                 internal_file = estrdup(internal_file);
 377                 php_url_free(resource);
 378                 return phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC);
 379         } else {
 380                 int i_len = strlen(internal_file);
 381 
 382                 /* search for directory */
 383                 zend_hash_internal_pointer_reset(&phar->manifest);
 384                 while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) {
 385                         if (HASH_KEY_NON_EXISTENT != 
 386                                         zend_hash_get_current_key_ex(
 387                                                 &phar->manifest, &str_key, &keylen, &unused, 0, NULL)) {
 388                                 if (keylen > (uint)i_len && 0 == memcmp(str_key, internal_file, i_len)) {
 389                                         /* directory found */
 390                                         internal_file = estrndup(internal_file,
 391                                                         i_len);
 392                                         php_url_free(resource);
 393                                         return phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC);
 394                                 }
 395                         }
 396 
 397                         if (SUCCESS != zend_hash_move_forward(&phar->manifest)) {
 398                                 break;
 399                         }
 400                 }
 401         }
 402 
 403         php_url_free(resource);
 404         return NULL;
 405 }
 406 /* }}} */
 407 
 408 /**
 409  * Make a new directory within a phar archive
 410  */
 411 int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mode, int options, php_stream_context *context TSRMLS_DC) /* {{{ */
 412 {
 413         phar_entry_info entry, *e;
 414         phar_archive_data *phar = NULL;
 415         char *error, *arch, *entry2;
 416         int arch_len, entry_len;
 417         php_url *resource = NULL;
 418         uint host_len;
 419 
 420         /* pre-readonly check, we need to know if this is a data phar */
 421         if (FAILURE == phar_split_fname(url_from, strlen(url_from), &arch, &arch_len, &entry2, &entry_len, 2, 2 TSRMLS_CC)) {
 422                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\", no phar archive specified", url_from);
 423                 return 0;
 424         }
 425 
 426         if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
 427                 phar = NULL;
 428         }
 429 
 430         efree(arch);
 431         efree(entry2);
 432 
 433         if (PHAR_G(readonly) && (!phar || !phar->is_data)) {
 434                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\", write operations disabled", url_from);
 435                 return 0;
 436         }
 437 
 438         if ((resource = phar_parse_url(wrapper, url_from, "w", options TSRMLS_CC)) == NULL) {
 439                 return 0;
 440         }
 441 
 442         /* we must have at the very least phar://alias.phar/internalfile.php */
 443         if (!resource->scheme || !resource->host || !resource->path) {
 444                 php_url_free(resource);
 445                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url_from);
 446                 return 0;
 447         }
 448 
 449         if (strcasecmp("phar", resource->scheme)) {
 450                 php_url_free(resource);
 451                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url_from);
 452                 return 0;
 453         }
 454 
 455         host_len = strlen(resource->host);
 456 
 457         if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) {
 458                 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);
 459                 efree(error);
 460                 php_url_free(resource);
 461                 return 0;
 462         }
 463 
 464         if ((e = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 2, &error, 1 TSRMLS_CC))) {
 465                 /* directory exists, or is a subdirectory of an existing file */
 466                 if (e->is_temp_dir) {
 467                         efree(e->filename);
 468                         efree(e);
 469                 }
 470                 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);
 471                 php_url_free(resource);
 472                 return 0;
 473         }
 474 
 475         if (error) {
 476                 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);
 477                 efree(error);
 478                 php_url_free(resource);
 479                 return 0;
 480         }
 481 
 482         if (phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 0, &error, 1 TSRMLS_CC)) {
 483                 /* entry exists as a file */
 484                 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);
 485                 php_url_free(resource);
 486                 return 0;
 487         }
 488 
 489         if (error) {
 490                 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);
 491                 efree(error);
 492                 php_url_free(resource);
 493                 return 0;
 494         }
 495 
 496         memset((void *) &entry, 0, sizeof(phar_entry_info));
 497 
 498         /* strip leading "/" */
 499         if (phar->is_zip) {
 500                 entry.is_zip = 1;
 501         }
 502 
 503         entry.filename = estrdup(resource->path + 1);
 504 
 505         if (phar->is_tar) {
 506                 entry.is_tar = 1;
 507                 entry.tar_type = TAR_DIR;
 508         }
 509 
 510         entry.filename_len = strlen(resource->path + 1);
 511         php_url_free(resource);
 512         entry.is_dir = 1;
 513         entry.phar = phar;
 514         entry.is_modified = 1;
 515         entry.is_crc_checked = 1;
 516         entry.flags = PHAR_ENT_PERM_DEF_DIR;
 517         entry.old_flags = PHAR_ENT_PERM_DEF_DIR;
 518 
 519         if (SUCCESS != zend_hash_add(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
 520                 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);
 521                 efree(error);
 522                 efree(entry.filename);
 523                 return 0;
 524         }
 525 
 526         phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
 527 
 528         if (error) {
 529                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", entry.filename, phar->fname, error);
 530                 zend_hash_del(&phar->manifest, entry.filename, entry.filename_len);
 531                 efree(error);
 532                 return 0;
 533         }
 534 
 535         phar_add_virtual_dirs(phar, entry.filename, entry.filename_len TSRMLS_CC);
 536         return 1;
 537 }
 538 /* }}} */
 539 
 540 /**
 541  * Remove a directory within a phar archive
 542  */
 543 int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context TSRMLS_DC) /* {{{ */
 544 {
 545         phar_entry_info *entry;
 546         phar_archive_data *phar = NULL;
 547         char *error, *arch, *entry2;
 548         int arch_len, entry_len;
 549         php_url *resource = NULL;
 550         uint host_len;
 551         char *str_key;
 552         uint key_len;
 553         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 TSRMLS_CC)) {
 558                 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);
 559                 return 0;
 560         }
 561 
 562         if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
 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 TSRMLS_CC, "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 TSRMLS_CC)) == 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 TSRMLS_CC, "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 TSRMLS_CC, "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 TSRMLS_CC)) {
 594                 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);
 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 TSRMLS_CC))) {
 603                 if (error) {
 604                         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);
 605                         efree(error);
 606                 } else {
 607                         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);
 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_ex(&phar->manifest, &str_key, &key_len, &unused, 0, NULL);
 616                         zend_hash_move_forward(&phar->manifest)
 617                 ) {
 618                         if (key_len > path_len && 
 619                                 memcmp(str_key, resource->path+1, path_len) == 0 && 
 620                                 IS_SLASH(str_key[path_len])) {
 621                                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "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_ex(&phar->virtual_dirs, &str_key, &key_len, &unused, 0, NULL);
 633                         zend_hash_move_forward(&phar->virtual_dirs)) {
 634         
 635                         if (key_len > path_len && 
 636                                 memcmp(str_key, resource->path+1, path_len) == 0 && 
 637                                 IS_SLASH(str_key[path_len])) {
 638                                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "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_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 TSRMLS_CC);
 657 
 658                 if (error) {
 659                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "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] */