Return to stream.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / phar |
1.1 ! misho 1: /* ! 2: +----------------------------------------------------------------------+ ! 3: | phar:// stream wrapper support | ! 4: +----------------------------------------------------------------------+ ! 5: | Copyright (c) 2005-2012 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_STREAM 1 ! 21: #include "phar_internal.h" ! 22: #include "stream.h" ! 23: #include "dirstream.h" ! 24: ! 25: php_stream_ops phar_ops = { ! 26: phar_stream_write, /* write */ ! 27: phar_stream_read, /* read */ ! 28: phar_stream_close, /* close */ ! 29: phar_stream_flush, /* flush */ ! 30: "phar stream", ! 31: phar_stream_seek, /* seek */ ! 32: NULL, /* cast */ ! 33: phar_stream_stat, /* stat */ ! 34: NULL, /* set option */ ! 35: }; ! 36: ! 37: php_stream_wrapper_ops phar_stream_wops = { ! 38: phar_wrapper_open_url, ! 39: NULL, /* phar_wrapper_close */ ! 40: NULL, /* phar_wrapper_stat, */ ! 41: phar_wrapper_stat, /* stat_url */ ! 42: phar_wrapper_open_dir, /* opendir */ ! 43: "phar", ! 44: phar_wrapper_unlink, /* unlink */ ! 45: phar_wrapper_rename, /* rename */ ! 46: phar_wrapper_mkdir, /* create directory */ ! 47: phar_wrapper_rmdir, /* remove directory */ ! 48: }; ! 49: ! 50: php_stream_wrapper php_stream_phar_wrapper = { ! 51: &phar_stream_wops, ! 52: NULL, ! 53: 0 /* is_url */ ! 54: }; ! 55: ! 56: /** ! 57: * Open a phar file for streams API ! 58: */ ! 59: php_url* phar_parse_url(php_stream_wrapper *wrapper, char *filename, char *mode, int options TSRMLS_DC) /* {{{ */ ! 60: { ! 61: php_url *resource; ! 62: char *arch = NULL, *entry = NULL, *error; ! 63: int arch_len, entry_len; ! 64: ! 65: if (strlen(filename) < 7 || strncasecmp(filename, "phar://", 7)) { ! 66: return NULL; ! 67: } ! 68: if (mode[0] == 'a') { ! 69: if (!(options & PHP_STREAM_URL_STAT_QUIET)) { ! 70: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: open mode append not supported"); ! 71: } ! 72: return NULL; ! 73: } ! 74: if (phar_split_fname(filename, strlen(filename), &arch, &arch_len, &entry, &entry_len, 2, (mode[0] == 'w' ? 2 : 0) TSRMLS_CC) == FAILURE) { ! 75: if (!(options & PHP_STREAM_URL_STAT_QUIET)) { ! 76: if (arch && !entry) { ! 77: 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)", filename, arch); ! 78: arch = NULL; ! 79: } else { ! 80: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url or non-existent phar \"%s\"", filename); ! 81: } ! 82: } ! 83: return NULL; ! 84: } ! 85: resource = ecalloc(1, sizeof(php_url)); ! 86: resource->scheme = estrndup("phar", 4); ! 87: resource->host = arch; ! 88: ! 89: resource->path = entry; ! 90: #if MBO_0 ! 91: if (resource) { ! 92: fprintf(stderr, "Alias: %s\n", alias); ! 93: fprintf(stderr, "Scheme: %s\n", resource->scheme); ! 94: /* fprintf(stderr, "User: %s\n", resource->user);*/ ! 95: /* fprintf(stderr, "Pass: %s\n", resource->pass ? "***" : NULL);*/ ! 96: fprintf(stderr, "Host: %s\n", resource->host); ! 97: /* fprintf(stderr, "Port: %d\n", resource->port);*/ ! 98: fprintf(stderr, "Path: %s\n", resource->path); ! 99: /* fprintf(stderr, "Query: %s\n", resource->query);*/ ! 100: /* fprintf(stderr, "Fragment: %s\n", resource->fragment);*/ ! 101: } ! 102: #endif ! 103: if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) { ! 104: phar_archive_data **pphar = NULL, *phar; ! 105: ! 106: if (PHAR_GLOBALS->request_init && PHAR_GLOBALS->phar_fname_map.arBuckets && FAILURE == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **)&pphar)) { ! 107: pphar = NULL; ! 108: } ! 109: if (PHAR_G(readonly) && (!pphar || !(*pphar)->is_data)) { ! 110: if (!(options & PHP_STREAM_URL_STAT_QUIET)) { ! 111: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: write operations disabled by the php.ini setting phar.readonly"); ! 112: } ! 113: php_url_free(resource); ! 114: return NULL; ! 115: } ! 116: if (phar_open_or_create_filename(resource->host, arch_len, NULL, 0, 0, options, &phar, &error TSRMLS_CC) == FAILURE) ! 117: { ! 118: if (error) { ! 119: if (!(options & PHP_STREAM_URL_STAT_QUIET)) { ! 120: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", error); ! 121: } ! 122: efree(error); ! 123: } ! 124: php_url_free(resource); ! 125: return NULL; ! 126: } ! 127: if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) { ! 128: if (error) { ! 129: spprintf(&error, 0, "Cannot open cached phar '%s' as writeable, copy on write failed", resource->host); ! 130: if (!(options & PHP_STREAM_URL_STAT_QUIET)) { ! 131: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", error); ! 132: } ! 133: efree(error); ! 134: } ! 135: php_url_free(resource); ! 136: return NULL; ! 137: } ! 138: } else { ! 139: if (phar_open_from_filename(resource->host, arch_len, NULL, 0, options, NULL, &error TSRMLS_CC) == FAILURE) ! 140: { ! 141: if (error) { ! 142: if (!(options & PHP_STREAM_URL_STAT_QUIET)) { ! 143: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", error); ! 144: } ! 145: efree(error); ! 146: } ! 147: php_url_free(resource); ! 148: return NULL; ! 149: } ! 150: } ! 151: return resource; ! 152: } ! 153: /* }}} */ ! 154: ! 155: /** ! 156: * used for fopen('phar://...') and company ! 157: */ ! 158: static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) /* {{{ */ ! 159: { ! 160: phar_archive_data *phar; ! 161: phar_entry_data *idata; ! 162: char *internal_file; ! 163: char *error; ! 164: HashTable *pharcontext; ! 165: php_url *resource = NULL; ! 166: php_stream *fpf; ! 167: zval **pzoption, *metadata; ! 168: uint host_len; ! 169: ! 170: if ((resource = phar_parse_url(wrapper, path, mode, options TSRMLS_CC)) == NULL) { ! 171: return NULL; ! 172: } ! 173: ! 174: /* we must have at the very least phar://alias.phar/internalfile.php */ ! 175: if (!resource->scheme || !resource->host || !resource->path) { ! 176: php_url_free(resource); ! 177: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", path); ! 178: return NULL; ! 179: } ! 180: ! 181: if (strcasecmp("phar", resource->scheme)) { ! 182: php_url_free(resource); ! 183: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", path); ! 184: return NULL; ! 185: } ! 186: ! 187: host_len = strlen(resource->host); ! 188: phar_request_initialize(TSRMLS_C); ! 189: ! 190: /* strip leading "/" */ ! 191: internal_file = estrdup(resource->path + 1); ! 192: if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) { ! 193: if (NULL == (idata = phar_get_or_create_entry_data(resource->host, host_len, internal_file, strlen(internal_file), mode, 0, &error, 1 TSRMLS_CC))) { ! 194: if (error) { ! 195: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", error); ! 196: efree(error); ! 197: } else { ! 198: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: file \"%s\" could not be created in phar \"%s\"", internal_file, resource->host); ! 199: } ! 200: efree(internal_file); ! 201: php_url_free(resource); ! 202: return NULL; ! 203: } ! 204: if (error) { ! 205: efree(error); ! 206: } ! 207: fpf = php_stream_alloc(&phar_ops, idata, NULL, mode); ! 208: php_url_free(resource); ! 209: efree(internal_file); ! 210: #if PHP_MAJOR_VERSION >= 6 ! 211: if (context && context->options && phar_find_key(HASH_OF(context->options), "phar", sizeof("phar"), (void**)&pzoption TSRMLS_CC)) { ! 212: #else ! 213: if (context && context->options && zend_hash_find(HASH_OF(context->options), "phar", sizeof("phar"), (void**)&pzoption) == SUCCESS) { ! 214: #endif ! 215: pharcontext = HASH_OF(*pzoption); ! 216: if (idata->internal_file->uncompressed_filesize == 0 ! 217: && idata->internal_file->compressed_filesize == 0 ! 218: #if PHP_MAJOR_VERSION >= 6 ! 219: && phar_find_key(pharcontext, "compress", sizeof("compress"), (void**)&pzoption TSRMLS_CC) ! 220: #else ! 221: && zend_hash_find(pharcontext, "compress", sizeof("compress"), (void**)&pzoption) == SUCCESS ! 222: #endif ! 223: && Z_TYPE_PP(pzoption) == IS_LONG ! 224: && (Z_LVAL_PP(pzoption) & ~PHAR_ENT_COMPRESSION_MASK) == 0 ! 225: ) { ! 226: idata->internal_file->flags &= ~PHAR_ENT_COMPRESSION_MASK; ! 227: idata->internal_file->flags |= Z_LVAL_PP(pzoption); ! 228: } ! 229: #if PHP_MAJOR_VERSION >= 6 ! 230: if (phar_find_key(pharcontext, "metadata", sizeof("metadata"), (void**)&pzoption TSRMLS_CC)) { ! 231: #else ! 232: if (zend_hash_find(pharcontext, "metadata", sizeof("metadata"), (void**)&pzoption) == SUCCESS) { ! 233: #endif ! 234: if (idata->internal_file->metadata) { ! 235: zval_ptr_dtor(&idata->internal_file->metadata); ! 236: idata->internal_file->metadata = NULL; ! 237: } ! 238: ! 239: MAKE_STD_ZVAL(idata->internal_file->metadata); ! 240: metadata = *pzoption; ! 241: ZVAL_ZVAL(idata->internal_file->metadata, metadata, 1, 0); ! 242: idata->phar->is_modified = 1; ! 243: } ! 244: } ! 245: if (opened_path) { ! 246: spprintf(opened_path, MAXPATHLEN, "phar://%s/%s", idata->phar->fname, idata->internal_file->filename); ! 247: } ! 248: return fpf; ! 249: } else { ! 250: if (!*internal_file && (options & STREAM_OPEN_FOR_INCLUDE)) { ! 251: /* retrieve the stub */ ! 252: if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, NULL TSRMLS_CC)) { ! 253: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "file %s is not a valid phar archive", resource->host); ! 254: efree(internal_file); ! 255: php_url_free(resource); ! 256: return NULL; ! 257: } ! 258: if (phar->is_tar || phar->is_zip) { ! 259: if ((FAILURE == phar_get_entry_data(&idata, resource->host, host_len, ".phar/stub.php", sizeof(".phar/stub.php")-1, "r", 0, &error, 0 TSRMLS_CC)) || !idata) { ! 260: goto idata_error; ! 261: } ! 262: efree(internal_file); ! 263: if (opened_path) { ! 264: spprintf(opened_path, MAXPATHLEN, "%s", phar->fname); ! 265: } ! 266: php_url_free(resource); ! 267: goto phar_stub; ! 268: } else { ! 269: phar_entry_info *entry; ! 270: ! 271: entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info)); ! 272: entry->is_temp_dir = 1; ! 273: entry->filename = estrndup("", 0); ! 274: entry->filename_len = 0; ! 275: entry->phar = phar; ! 276: entry->offset = entry->offset_abs = 0; ! 277: entry->compressed_filesize = entry->uncompressed_filesize = phar->halt_offset; ! 278: entry->is_crc_checked = 1; ! 279: ! 280: idata = (phar_entry_data *) ecalloc(1, sizeof(phar_entry_data)); ! 281: idata->fp = phar_get_pharfp(phar TSRMLS_CC); ! 282: idata->phar = phar; ! 283: idata->internal_file = entry; ! 284: if (!phar->is_persistent) { ! 285: ++(entry->phar->refcount); ! 286: } ! 287: ++(entry->fp_refcount); ! 288: php_url_free(resource); ! 289: if (opened_path) { ! 290: spprintf(opened_path, MAXPATHLEN, "%s", phar->fname); ! 291: } ! 292: efree(internal_file); ! 293: goto phar_stub; ! 294: } ! 295: } ! 296: /* read-only access is allowed to magic files in .phar directory */ ! 297: if ((FAILURE == phar_get_entry_data(&idata, resource->host, host_len, internal_file, strlen(internal_file), "r", 0, &error, 0 TSRMLS_CC)) || !idata) { ! 298: idata_error: ! 299: if (error) { ! 300: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", error); ! 301: efree(error); ! 302: } else { ! 303: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: \"%s\" is not a file in phar \"%s\"", internal_file, resource->host); ! 304: } ! 305: efree(internal_file); ! 306: php_url_free(resource); ! 307: return NULL; ! 308: } ! 309: } ! 310: php_url_free(resource); ! 311: #if MBO_0 ! 312: fprintf(stderr, "Pharname: %s\n", idata->phar->filename); ! 313: fprintf(stderr, "Filename: %s\n", internal_file); ! 314: fprintf(stderr, "Entry: %s\n", idata->internal_file->filename); ! 315: fprintf(stderr, "Size: %u\n", idata->internal_file->uncompressed_filesize); ! 316: fprintf(stderr, "Compressed: %u\n", idata->internal_file->flags); ! 317: fprintf(stderr, "Offset: %u\n", idata->internal_file->offset_within_phar); ! 318: fprintf(stderr, "Cached: %s\n", idata->internal_file->filedata ? "yes" : "no"); ! 319: #endif ! 320: ! 321: /* check length, crc32 */ ! 322: if (!idata->internal_file->is_crc_checked && phar_postprocess_file(idata, idata->internal_file->crc32, &error, 2 TSRMLS_CC) != SUCCESS) { ! 323: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", error); ! 324: efree(error); ! 325: phar_entry_delref(idata TSRMLS_CC); ! 326: efree(internal_file); ! 327: return NULL; ! 328: } ! 329: ! 330: if (!PHAR_G(cwd_init) && options & STREAM_OPEN_FOR_INCLUDE) { ! 331: char *entry = idata->internal_file->filename, *cwd; ! 332: ! 333: PHAR_G(cwd_init) = 1; ! 334: if ((idata->phar->is_tar || idata->phar->is_zip) && idata->internal_file->filename_len == sizeof(".phar/stub.php")-1 && !strncmp(idata->internal_file->filename, ".phar/stub.php", sizeof(".phar/stub.php")-1)) { ! 335: /* we're executing the stub, which doesn't count as a file */ ! 336: PHAR_G(cwd_init) = 0; ! 337: } else if ((cwd = strrchr(entry, '/'))) { ! 338: PHAR_G(cwd_len) = cwd - entry; ! 339: PHAR_G(cwd) = estrndup(entry, PHAR_G(cwd_len)); ! 340: } else { ! 341: /* root directory */ ! 342: PHAR_G(cwd_len) = 0; ! 343: PHAR_G(cwd) = NULL; ! 344: } ! 345: } ! 346: if (opened_path) { ! 347: spprintf(opened_path, MAXPATHLEN, "phar://%s/%s", idata->phar->fname, idata->internal_file->filename); ! 348: } ! 349: efree(internal_file); ! 350: phar_stub: ! 351: fpf = php_stream_alloc(&phar_ops, idata, NULL, mode); ! 352: return fpf; ! 353: } ! 354: /* }}} */ ! 355: ! 356: /** ! 357: * Used for fclose($fp) where $fp is a phar archive ! 358: */ ! 359: static int phar_stream_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */ ! 360: { ! 361: phar_entry_delref((phar_entry_data *)stream->abstract TSRMLS_CC); ! 362: ! 363: return 0; ! 364: } ! 365: /* }}} */ ! 366: ! 367: /** ! 368: * used for fread($fp) and company on a fopen()ed phar file handle ! 369: */ ! 370: static size_t phar_stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */ ! 371: { ! 372: phar_entry_data *data = (phar_entry_data *)stream->abstract; ! 373: size_t got; ! 374: phar_entry_info *entry; ! 375: ! 376: if (data->internal_file->link) { ! 377: entry = phar_get_link_source(data->internal_file TSRMLS_CC); ! 378: } else { ! 379: entry = data->internal_file; ! 380: } ! 381: ! 382: if (entry->is_deleted) { ! 383: stream->eof = 1; ! 384: return 0; ! 385: } ! 386: ! 387: /* use our proxy position */ ! 388: php_stream_seek(data->fp, data->position + data->zero, SEEK_SET); ! 389: ! 390: got = php_stream_read(data->fp, buf, MIN(count, entry->uncompressed_filesize - data->position)); ! 391: data->position = php_stream_tell(data->fp) - data->zero; ! 392: stream->eof = (data->position == (off_t) entry->uncompressed_filesize); ! 393: ! 394: return got; ! 395: } ! 396: /* }}} */ ! 397: ! 398: /** ! 399: * Used for fseek($fp) on a phar file handle ! 400: */ ! 401: static int phar_stream_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC) /* {{{ */ ! 402: { ! 403: phar_entry_data *data = (phar_entry_data *)stream->abstract; ! 404: phar_entry_info *entry; ! 405: int res; ! 406: off_t temp; ! 407: ! 408: if (data->internal_file->link) { ! 409: entry = phar_get_link_source(data->internal_file TSRMLS_CC); ! 410: } else { ! 411: entry = data->internal_file; ! 412: } ! 413: ! 414: switch (whence) { ! 415: case SEEK_END : ! 416: temp = data->zero + entry->uncompressed_filesize + offset; ! 417: break; ! 418: case SEEK_CUR : ! 419: temp = data->zero + data->position + offset; ! 420: break; ! 421: case SEEK_SET : ! 422: temp = data->zero + offset; ! 423: break; ! 424: default : ! 425: temp = 0; ! 426: } ! 427: if (temp > data->zero + (off_t) entry->uncompressed_filesize) { ! 428: *newoffset = -1; ! 429: return -1; ! 430: } ! 431: if (temp < data->zero) { ! 432: *newoffset = -1; ! 433: return -1; ! 434: } ! 435: res = php_stream_seek(data->fp, temp, SEEK_SET); ! 436: *newoffset = php_stream_tell(data->fp) - data->zero; ! 437: data->position = *newoffset; ! 438: return res; ! 439: } ! 440: /* }}} */ ! 441: ! 442: /** ! 443: * Used for writing to a phar file ! 444: */ ! 445: static size_t phar_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */ ! 446: { ! 447: phar_entry_data *data = (phar_entry_data *) stream->abstract; ! 448: ! 449: php_stream_seek(data->fp, data->position, SEEK_SET); ! 450: if (count != php_stream_write(data->fp, buf, count)) { ! 451: php_stream_wrapper_log_error(stream->wrapper, stream->flags TSRMLS_CC, "phar error: Could not write %d characters to \"%s\" in phar \"%s\"", (int) count, data->internal_file->filename, data->phar->fname); ! 452: return -1; ! 453: } ! 454: data->position = php_stream_tell(data->fp); ! 455: if (data->position > (off_t)data->internal_file->uncompressed_filesize) { ! 456: data->internal_file->uncompressed_filesize = data->position; ! 457: } ! 458: data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize; ! 459: data->internal_file->old_flags = data->internal_file->flags; ! 460: data->internal_file->is_modified = 1; ! 461: return count; ! 462: } ! 463: /* }}} */ ! 464: ! 465: /** ! 466: * Used to save work done on a writeable phar ! 467: */ ! 468: static int phar_stream_flush(php_stream *stream TSRMLS_DC) /* {{{ */ ! 469: { ! 470: char *error; ! 471: int ret; ! 472: if (stream->mode[0] == 'w' || (stream->mode[0] == 'r' && stream->mode[1] == '+')) { ! 473: ret = phar_flush(((phar_entry_data *)stream->abstract)->phar, 0, 0, 0, &error TSRMLS_CC); ! 474: if (error) { ! 475: php_stream_wrapper_log_error(stream->wrapper, REPORT_ERRORS TSRMLS_CC, "%s", error); ! 476: efree(error); ! 477: } ! 478: return ret; ! 479: } else { ! 480: return EOF; ! 481: } ! 482: } ! 483: /* }}} */ ! 484: ! 485: /* {{{ phar_dostat */ ! 486: /** ! 487: * stat an opened phar file handle stream, used by phar_stat() ! 488: */ ! 489: void phar_dostat(phar_archive_data *phar, phar_entry_info *data, php_stream_statbuf *ssb, zend_bool is_temp_dir TSRMLS_DC) ! 490: { ! 491: memset(ssb, 0, sizeof(php_stream_statbuf)); ! 492: ! 493: if (!is_temp_dir && !data->is_dir) { ! 494: ssb->sb.st_size = data->uncompressed_filesize; ! 495: ssb->sb.st_mode = data->flags & PHAR_ENT_PERM_MASK; ! 496: ssb->sb.st_mode |= S_IFREG; /* regular file */ ! 497: /* timestamp is just the timestamp when this was added to the phar */ ! 498: #ifdef NETWARE ! 499: ssb->sb.st_mtime.tv_sec = data->timestamp; ! 500: ssb->sb.st_atime.tv_sec = data->timestamp; ! 501: ssb->sb.st_ctime.tv_sec = data->timestamp; ! 502: #else ! 503: ssb->sb.st_mtime = data->timestamp; ! 504: ssb->sb.st_atime = data->timestamp; ! 505: ssb->sb.st_ctime = data->timestamp; ! 506: #endif ! 507: } else if (!is_temp_dir && data->is_dir) { ! 508: ssb->sb.st_size = 0; ! 509: ssb->sb.st_mode = data->flags & PHAR_ENT_PERM_MASK; ! 510: ssb->sb.st_mode |= S_IFDIR; /* regular directory */ ! 511: /* timestamp is just the timestamp when this was added to the phar */ ! 512: #ifdef NETWARE ! 513: ssb->sb.st_mtime.tv_sec = data->timestamp; ! 514: ssb->sb.st_atime.tv_sec = data->timestamp; ! 515: ssb->sb.st_ctime.tv_sec = data->timestamp; ! 516: #else ! 517: ssb->sb.st_mtime = data->timestamp; ! 518: ssb->sb.st_atime = data->timestamp; ! 519: ssb->sb.st_ctime = data->timestamp; ! 520: #endif ! 521: } else { ! 522: ssb->sb.st_size = 0; ! 523: ssb->sb.st_mode = 0777; ! 524: ssb->sb.st_mode |= S_IFDIR; /* regular directory */ ! 525: #ifdef NETWARE ! 526: ssb->sb.st_mtime.tv_sec = phar->max_timestamp; ! 527: ssb->sb.st_atime.tv_sec = phar->max_timestamp; ! 528: ssb->sb.st_ctime.tv_sec = phar->max_timestamp; ! 529: #else ! 530: ssb->sb.st_mtime = phar->max_timestamp; ! 531: ssb->sb.st_atime = phar->max_timestamp; ! 532: ssb->sb.st_ctime = phar->max_timestamp; ! 533: #endif ! 534: } ! 535: if (!phar->is_writeable) { ! 536: ssb->sb.st_mode = (ssb->sb.st_mode & 0555) | (ssb->sb.st_mode & ~0777); ! 537: } ! 538: ! 539: ssb->sb.st_nlink = 1; ! 540: ssb->sb.st_rdev = -1; ! 541: /* this is only for APC, so use /dev/null device - no chance of conflict there! */ ! 542: ssb->sb.st_dev = 0xc; ! 543: /* generate unique inode number for alias/filename, so no phars will conflict */ ! 544: if (!is_temp_dir) { ! 545: ssb->sb.st_ino = data->inode; ! 546: } ! 547: #ifndef PHP_WIN32 ! 548: ssb->sb.st_blksize = -1; ! 549: ssb->sb.st_blocks = -1; ! 550: #endif ! 551: } ! 552: /* }}}*/ ! 553: ! 554: /** ! 555: * Stat an opened phar file handle ! 556: */ ! 557: static int phar_stream_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC) /* {{{ */ ! 558: { ! 559: phar_entry_data *data = (phar_entry_data *)stream->abstract; ! 560: ! 561: /* If ssb is NULL then someone is misbehaving */ ! 562: if (!ssb) { ! 563: return -1; ! 564: } ! 565: ! 566: phar_dostat(data->phar, data->internal_file, ssb, 0 TSRMLS_CC); ! 567: return 0; ! 568: } ! 569: /* }}} */ ! 570: ! 571: /** ! 572: * Stream wrapper stat implementation of stat() ! 573: */ ! 574: static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags, ! 575: php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC) /* {{{ */ ! 576: { ! 577: php_url *resource = NULL; ! 578: char *internal_file, *error; ! 579: phar_archive_data *phar; ! 580: phar_entry_info *entry; ! 581: uint host_len; ! 582: int internal_file_len; ! 583: ! 584: if ((resource = phar_parse_url(wrapper, url, "r", flags|PHP_STREAM_URL_STAT_QUIET TSRMLS_CC)) == NULL) { ! 585: return FAILURE; ! 586: } ! 587: ! 588: /* we must have at the very least phar://alias.phar/internalfile.php */ ! 589: if (!resource->scheme || !resource->host || !resource->path) { ! 590: php_url_free(resource); ! 591: return FAILURE; ! 592: } ! 593: ! 594: if (strcasecmp("phar", resource->scheme)) { ! 595: php_url_free(resource); ! 596: return FAILURE; ! 597: } ! 598: ! 599: host_len = strlen(resource->host); ! 600: phar_request_initialize(TSRMLS_C); ! 601: ! 602: internal_file = resource->path + 1; /* strip leading "/" */ ! 603: /* find the phar in our trusty global hash indexed by alias (host of phar://blah.phar/file.whatever) */ ! 604: if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) { ! 605: php_url_free(resource); ! 606: if (error) { ! 607: efree(error); ! 608: } ! 609: return FAILURE; ! 610: } ! 611: if (error) { ! 612: efree(error); ! 613: } ! 614: if (*internal_file == '\0') { ! 615: /* root directory requested */ ! 616: phar_dostat(phar, NULL, ssb, 1 TSRMLS_CC); ! 617: php_url_free(resource); ! 618: return SUCCESS; ! 619: } ! 620: if (!phar->manifest.arBuckets) { ! 621: php_url_free(resource); ! 622: return FAILURE; ! 623: } ! 624: internal_file_len = strlen(internal_file); ! 625: /* search through the manifest of files, and if we have an exact match, it's a file */ ! 626: if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, internal_file_len, (void**)&entry)) { ! 627: phar_dostat(phar, entry, ssb, 0 TSRMLS_CC); ! 628: php_url_free(resource); ! 629: return SUCCESS; ! 630: } ! 631: if (zend_hash_exists(&(phar->virtual_dirs), internal_file, internal_file_len)) { ! 632: phar_dostat(phar, NULL, ssb, 1 TSRMLS_CC); ! 633: php_url_free(resource); ! 634: return SUCCESS; ! 635: } ! 636: /* check for mounted directories */ ! 637: if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) { ! 638: phar_zstr key; ! 639: char *str_key; ! 640: ulong unused; ! 641: uint keylen; ! 642: HashPosition pos; ! 643: ! 644: zend_hash_internal_pointer_reset_ex(&phar->mounted_dirs, &pos); ! 645: while (FAILURE != zend_hash_has_more_elements_ex(&phar->mounted_dirs, &pos)) { ! 646: if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, &pos)) { ! 647: break; ! 648: } ! 649: PHAR_STR(key, str_key); ! 650: if ((int)keylen >= internal_file_len || strncmp(str_key, internal_file, keylen)) { ! 651: zend_hash_move_forward_ex(&phar->mounted_dirs, &pos); ! 652: PHAR_STR_FREE(str_key); ! 653: continue; ! 654: } else { ! 655: char *test; ! 656: int test_len; ! 657: php_stream_statbuf ssbi; ! 658: ! 659: if (SUCCESS != zend_hash_find(&phar->manifest, str_key, keylen, (void **) &entry)) { ! 660: PHAR_STR_FREE(str_key); ! 661: goto free_resource; ! 662: } ! 663: PHAR_STR_FREE(str_key); ! 664: if (!entry->tmp || !entry->is_mounted) { ! 665: goto free_resource; ! 666: } ! 667: test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, internal_file + keylen); ! 668: if (SUCCESS != php_stream_stat_path(test, &ssbi)) { ! 669: efree(test); ! 670: zend_hash_move_forward_ex(&phar->mounted_dirs, &pos); ! 671: continue; ! 672: } ! 673: /* mount the file/directory just in time */ ! 674: if (SUCCESS != phar_mount_entry(phar, test, test_len, internal_file, internal_file_len TSRMLS_CC)) { ! 675: efree(test); ! 676: goto free_resource; ! 677: } ! 678: efree(test); ! 679: if (SUCCESS != zend_hash_find(&phar->manifest, internal_file, internal_file_len, (void**)&entry)) { ! 680: goto free_resource; ! 681: } ! 682: phar_dostat(phar, entry, ssb, 0 TSRMLS_CC); ! 683: php_url_free(resource); ! 684: return SUCCESS; ! 685: } ! 686: } ! 687: } ! 688: free_resource: ! 689: php_url_free(resource); ! 690: return FAILURE; ! 691: } ! 692: /* }}} */ ! 693: ! 694: /** ! 695: * Unlink a file within a phar archive ! 696: */ ! 697: static int phar_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC) /* {{{ */ ! 698: { ! 699: php_url *resource; ! 700: char *internal_file, *error; ! 701: int internal_file_len; ! 702: phar_entry_data *idata; ! 703: phar_archive_data **pphar; ! 704: uint host_len; ! 705: ! 706: if ((resource = phar_parse_url(wrapper, url, "rb", options TSRMLS_CC)) == NULL) { ! 707: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: unlink failed"); ! 708: return 0; ! 709: } ! 710: ! 711: /* we must have at the very least phar://alias.phar/internalfile.php */ ! 712: if (!resource->scheme || !resource->host || !resource->path) { ! 713: php_url_free(resource); ! 714: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url); ! 715: return 0; ! 716: } ! 717: ! 718: if (strcasecmp("phar", resource->scheme)) { ! 719: php_url_free(resource); ! 720: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url); ! 721: return 0; ! 722: } ! 723: ! 724: host_len = strlen(resource->host); ! 725: phar_request_initialize(TSRMLS_C); ! 726: ! 727: if (FAILURE == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), resource->host, host_len, (void **) &pphar)) { ! 728: pphar = NULL; ! 729: } ! 730: if (PHAR_G(readonly) && (!pphar || !(*pphar)->is_data)) { ! 731: php_url_free(resource); ! 732: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: write operations disabled by the php.ini setting phar.readonly"); ! 733: return 0; ! 734: } ! 735: ! 736: /* need to copy to strip leading "/", will get touched again */ ! 737: internal_file = estrdup(resource->path + 1); ! 738: internal_file_len = strlen(internal_file); ! 739: if (FAILURE == phar_get_entry_data(&idata, resource->host, host_len, internal_file, internal_file_len, "r", 0, &error, 1 TSRMLS_CC)) { ! 740: /* constraints of fp refcount were not met */ ! 741: if (error) { ! 742: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "unlink of \"%s\" failed: %s", url, error); ! 743: efree(error); ! 744: } else { ! 745: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "unlink of \"%s\" failed, file does not exist", url); ! 746: } ! 747: efree(internal_file); ! 748: php_url_free(resource); ! 749: return 0; ! 750: } ! 751: if (error) { ! 752: efree(error); ! 753: } ! 754: if (idata->internal_file->fp_refcount > 1) { ! 755: /* more than just our fp resource is open for this file */ ! 756: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: \"%s\" in phar \"%s\", has open file pointers, cannot unlink", internal_file, resource->host); ! 757: efree(internal_file); ! 758: php_url_free(resource); ! 759: phar_entry_delref(idata TSRMLS_CC); ! 760: return 0; ! 761: } ! 762: php_url_free(resource); ! 763: efree(internal_file); ! 764: phar_entry_remove(idata, &error TSRMLS_CC); ! 765: if (error) { ! 766: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", error); ! 767: efree(error); ! 768: } ! 769: return 1; ! 770: } ! 771: /* }}} */ ! 772: ! 773: static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC) /* {{{ */ ! 774: { ! 775: php_url *resource_from, *resource_to; ! 776: char *error; ! 777: phar_archive_data *phar, *pfrom, *pto; ! 778: phar_entry_info *entry; ! 779: uint host_len; ! 780: int is_dir = 0; ! 781: int is_modified = 0; ! 782: ! 783: error = NULL; ! 784: ! 785: if ((resource_from = phar_parse_url(wrapper, url_from, "wb", options|PHP_STREAM_URL_STAT_QUIET TSRMLS_CC)) == NULL) { ! 786: php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", url_from, url_to, url_from); ! 787: return 0; ! 788: } ! 789: if (SUCCESS != phar_get_archive(&pfrom, resource_from->host, strlen(resource_from->host), NULL, 0, &error TSRMLS_CC)) { ! 790: pfrom = NULL; ! 791: if (error) { ! 792: efree(error); ! 793: } ! 794: } ! 795: if (PHAR_G(readonly) && (!pfrom || !pfrom->is_data)) { ! 796: php_url_free(resource_from); ! 797: php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: Write operations disabled by the php.ini setting phar.readonly"); ! 798: return 0; ! 799: } ! 800: ! 801: if ((resource_to = phar_parse_url(wrapper, url_to, "wb", options|PHP_STREAM_URL_STAT_QUIET TSRMLS_CC)) == NULL) { ! 802: php_url_free(resource_from); ! 803: php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", url_from, url_to, url_to); ! 804: return 0; ! 805: } ! 806: if (SUCCESS != phar_get_archive(&pto, resource_to->host, strlen(resource_to->host), NULL, 0, &error TSRMLS_CC)) { ! 807: if (error) { ! 808: efree(error); ! 809: } ! 810: pto = NULL; ! 811: } ! 812: if (PHAR_G(readonly) && (!pto || !pto->is_data)) { ! 813: php_url_free(resource_from); ! 814: php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: Write operations disabled by the php.ini setting phar.readonly"); ! 815: return 0; ! 816: } ! 817: ! 818: if (strcmp(resource_from->host, resource_to->host)) { ! 819: php_url_free(resource_from); ! 820: php_url_free(resource_to); ! 821: php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\", not within the same phar archive", url_from, url_to); ! 822: return 0; ! 823: } ! 824: ! 825: /* we must have at the very least phar://alias.phar/internalfile.php */ ! 826: if (!resource_from->scheme || !resource_from->host || !resource_from->path) { ! 827: php_url_free(resource_from); ! 828: php_url_free(resource_to); ! 829: php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid url \"%s\"", url_from, url_to, url_from); ! 830: return 0; ! 831: } ! 832: ! 833: if (!resource_to->scheme || !resource_to->host || !resource_to->path) { ! 834: php_url_free(resource_from); ! 835: php_url_free(resource_to); ! 836: php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid url \"%s\"", url_from, url_to, url_to); ! 837: return 0; ! 838: } ! 839: ! 840: if (strcasecmp("phar", resource_from->scheme)) { ! 841: php_url_free(resource_from); ! 842: php_url_free(resource_to); ! 843: php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": not a phar stream url \"%s\"", url_from, url_to, url_from); ! 844: return 0; ! 845: } ! 846: ! 847: if (strcasecmp("phar", resource_to->scheme)) { ! 848: php_url_free(resource_from); ! 849: php_url_free(resource_to); ! 850: php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": not a phar stream url \"%s\"", url_from, url_to, url_to); ! 851: return 0; ! 852: } ! 853: ! 854: host_len = strlen(resource_from->host); ! 855: ! 856: if (SUCCESS != phar_get_archive(&phar, resource_from->host, host_len, NULL, 0, &error TSRMLS_CC)) { ! 857: php_url_free(resource_from); ! 858: php_url_free(resource_to); ! 859: php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error); ! 860: efree(error); ! 861: return 0; ! 862: } ! 863: ! 864: if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) { ! 865: php_url_free(resource_from); ! 866: php_url_free(resource_to); ! 867: php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": could not make cached phar writeable", url_from, url_to); ! 868: return 0; ! 869: } ! 870: ! 871: if (SUCCESS == zend_hash_find(&(phar->manifest), resource_from->path+1, strlen(resource_from->path)-1, (void **)&entry)) { ! 872: phar_entry_info new, *source; ! 873: ! 874: /* perform rename magic */ ! 875: if (entry->is_deleted) { ! 876: php_url_free(resource_from); ! 877: php_url_free(resource_to); ! 878: php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\" from extracted phar archive, source has been deleted", url_from, url_to); ! 879: return 0; ! 880: } ! 881: /* transfer all data over to the new entry */ ! 882: memcpy((void *) &new, (void *) entry, sizeof(phar_entry_info)); ! 883: /* mark the old one for deletion */ ! 884: entry->is_deleted = 1; ! 885: entry->fp = NULL; ! 886: entry->metadata = 0; ! 887: entry->link = entry->tmp = NULL; ! 888: source = entry; ! 889: ! 890: /* add to the manifest, and then store the pointer to the new guy in entry */ ! 891: zend_hash_add(&(phar->manifest), resource_to->path+1, strlen(resource_to->path)-1, (void **)&new, sizeof(phar_entry_info), (void **) &entry); ! 892: ! 893: entry->filename = estrdup(resource_to->path+1); ! 894: if (FAILURE == phar_copy_entry_fp(source, entry, &error TSRMLS_CC)) { ! 895: php_url_free(resource_from); ! 896: php_url_free(resource_to); ! 897: php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error); ! 898: efree(error); ! 899: zend_hash_del(&(phar->manifest), entry->filename, strlen(entry->filename)); ! 900: return 0; ! 901: } ! 902: is_modified = 1; ! 903: entry->is_modified = 1; ! 904: entry->filename_len = strlen(entry->filename); ! 905: is_dir = entry->is_dir; ! 906: } else { ! 907: is_dir = zend_hash_exists(&(phar->virtual_dirs), resource_from->path+1, strlen(resource_from->path)-1); ! 908: if (!is_dir) { ! 909: /* file does not exist */ ! 910: php_url_free(resource_from); ! 911: php_url_free(resource_to); ! 912: php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\" from extracted phar archive, source does not exist", url_from, url_to); ! 913: return 0; ! 914: ! 915: } ! 916: } ! 917: ! 918: /* Rename directory. Update all nested paths */ ! 919: if (is_dir) { ! 920: int key_type; ! 921: phar_zstr key, new_key; ! 922: char *str_key, *new_str_key; ! 923: uint key_len, new_key_len; ! 924: ulong unused; ! 925: uint from_len = strlen(resource_from->path+1); ! 926: uint to_len = strlen(resource_to->path+1); ! 927: ! 928: for (zend_hash_internal_pointer_reset(&phar->manifest); ! 929: HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->manifest, &key, &key_len, &unused, 0, NULL)) && ! 930: SUCCESS == zend_hash_get_current_data(&phar->manifest, (void **) &entry); ! 931: zend_hash_move_forward(&phar->manifest)) { ! 932: ! 933: PHAR_STR(key, str_key); ! 934: ! 935: if (!entry->is_deleted && ! 936: key_len > from_len && ! 937: memcmp(str_key, resource_from->path+1, from_len) == 0 && ! 938: IS_SLASH(str_key[from_len])) { ! 939: ! 940: new_key_len = key_len + to_len - from_len; ! 941: new_str_key = emalloc(new_key_len+1); ! 942: memcpy(new_str_key, resource_to->path + 1, to_len); ! 943: memcpy(new_str_key + to_len, str_key + from_len, key_len - from_len); ! 944: new_str_key[new_key_len] = 0; ! 945: ! 946: is_modified = 1; ! 947: entry->is_modified = 1; ! 948: efree(entry->filename); ! 949: entry->filename = new_str_key; ! 950: entry->filename_len = new_key_len; ! 951: ! 952: PHAR_ZSTR(new_str_key, new_key); ! 953: #if PHP_VERSION_ID < 50300 ! 954: zend_hash_update_current_key_ex(&phar->manifest, key_type, new_key, new_key_len, 0, NULL); ! 955: #else ! 956: zend_hash_update_current_key_ex(&phar->manifest, key_type, new_key, new_key_len, 0, HASH_UPDATE_KEY_ANYWAY, NULL); ! 957: #endif ! 958: } ! 959: PHAR_STR_FREE(str_key); ! 960: } ! 961: ! 962: for (zend_hash_internal_pointer_reset(&phar->virtual_dirs); ! 963: HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->virtual_dirs, &key, &key_len, &unused, 0, NULL)); ! 964: zend_hash_move_forward(&phar->virtual_dirs)) { ! 965: ! 966: PHAR_STR(key, str_key); ! 967: ! 968: if (key_len >= from_len && ! 969: memcmp(str_key, resource_from->path+1, from_len) == 0 && ! 970: (key_len == from_len || IS_SLASH(str_key[from_len]))) { ! 971: ! 972: new_key_len = key_len + to_len - from_len; ! 973: new_str_key = emalloc(new_key_len+1); ! 974: memcpy(new_str_key, resource_to->path + 1, to_len); ! 975: memcpy(new_str_key + to_len, str_key + from_len, key_len - from_len); ! 976: new_str_key[new_key_len] = 0; ! 977: ! 978: PHAR_ZSTR(new_str_key, new_key); ! 979: #if PHP_VERSION_ID < 50300 ! 980: zend_hash_update_current_key_ex(&phar->virtual_dirs, key_type, new_key, new_key_len, 0, NULL); ! 981: #else ! 982: zend_hash_update_current_key_ex(&phar->virtual_dirs, key_type, new_key, new_key_len, 0, HASH_UPDATE_KEY_ANYWAY, NULL); ! 983: #endif ! 984: efree(new_str_key); ! 985: } ! 986: PHAR_STR_FREE(str_key); ! 987: } ! 988: ! 989: for (zend_hash_internal_pointer_reset(&phar->mounted_dirs); ! 990: HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &key_len, &unused, 0, NULL)) && ! 991: SUCCESS == zend_hash_get_current_data(&phar->mounted_dirs, (void **) &entry); ! 992: zend_hash_move_forward(&phar->mounted_dirs)) { ! 993: ! 994: PHAR_STR(key, str_key); ! 995: ! 996: if (key_len >= from_len && ! 997: memcmp(str_key, resource_from->path+1, from_len) == 0 && ! 998: (key_len == from_len || IS_SLASH(str_key[from_len]))) { ! 999: ! 1000: new_key_len = key_len + to_len - from_len; ! 1001: new_str_key = emalloc(new_key_len+1); ! 1002: memcpy(new_str_key, resource_to->path + 1, to_len); ! 1003: memcpy(new_str_key + to_len, str_key + from_len, key_len - from_len); ! 1004: new_str_key[new_key_len] = 0; ! 1005: ! 1006: PHAR_ZSTR(new_str_key, new_key); ! 1007: #if PHP_VERSION_ID < 50300 ! 1008: zend_hash_update_current_key_ex(&phar->mounted_dirs, key_type, new_key, new_key_len, 0, NULL); ! 1009: #else ! 1010: zend_hash_update_current_key_ex(&phar->mounted_dirs, key_type, new_key, new_key_len, 0, HASH_UPDATE_KEY_ANYWAY, NULL); ! 1011: #endif ! 1012: efree(new_str_key); ! 1013: } ! 1014: PHAR_STR_FREE(str_key); ! 1015: } ! 1016: } ! 1017: ! 1018: if (is_modified) { ! 1019: phar_flush(phar, 0, 0, 0, &error TSRMLS_CC); ! 1020: if (error) { ! 1021: php_url_free(resource_from); ! 1022: php_url_free(resource_to); ! 1023: php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error); ! 1024: efree(error); ! 1025: return 0; ! 1026: } ! 1027: } ! 1028: ! 1029: php_url_free(resource_from); ! 1030: php_url_free(resource_to); ! 1031: ! 1032: return 1; ! 1033: } ! 1034: /* }}} */ ! 1035: ! 1036: /* ! 1037: * Local variables: ! 1038: * tab-width: 4 ! 1039: * c-basic-offset: 4 ! 1040: * End: ! 1041: * vim600: noet sw=4 ts=4 fdm=marker ! 1042: * vim<600: noet sw=4 ts=4 ! 1043: */