Annotation of embedaddon/php/ext/phar/stream.c, revision 1.1
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: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>