Return to util.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / phar |
1.1 ! misho 1: /* ! 2: +----------------------------------------------------------------------+ ! 3: | phar php single-file executable PHP extension | ! 4: | utility functions | ! 5: +----------------------------------------------------------------------+ ! 6: | Copyright (c) 2005-2012 The PHP Group | ! 7: +----------------------------------------------------------------------+ ! 8: | This source file is subject to version 3.01 of the PHP license, | ! 9: | that is bundled with this package in the file LICENSE, and is | ! 10: | available through the world-wide-web at the following url: | ! 11: | http://www.php.net/license/3_01.txt. | ! 12: | If you did not receive a copy of the PHP license and are unable to | ! 13: | obtain it through the world-wide-web, please send a note to | ! 14: | license@php.net so we can mail you a copy immediately. | ! 15: +----------------------------------------------------------------------+ ! 16: | Authors: Gregory Beaver <cellog@php.net> | ! 17: | Marcus Boerger <helly@php.net> | ! 18: +----------------------------------------------------------------------+ ! 19: */ ! 20: ! 21: /* $Id: util.c 321634 2012-01-01 13:15:04Z felipe $ */ ! 22: ! 23: #include "phar_internal.h" ! 24: #ifdef PHAR_HASH_OK ! 25: #include "ext/hash/php_hash_sha.h" ! 26: #endif ! 27: ! 28: #ifdef PHAR_HAVE_OPENSSL ! 29: /* OpenSSL includes */ ! 30: #include <openssl/evp.h> ! 31: #include <openssl/x509.h> ! 32: #include <openssl/x509v3.h> ! 33: #include <openssl/crypto.h> ! 34: #include <openssl/pem.h> ! 35: #include <openssl/err.h> ! 36: #include <openssl/conf.h> ! 37: #include <openssl/rand.h> ! 38: #include <openssl/ssl.h> ! 39: #include <openssl/pkcs12.h> ! 40: #else ! 41: static int phar_call_openssl_signverify(int is_sign, php_stream *fp, off_t end, char *key, int key_len, char **signature, int *signature_len TSRMLS_DC); ! 42: #endif ! 43: ! 44: #if !defined(PHP_VERSION_ID) || PHP_VERSION_ID < 50300 ! 45: extern php_stream_wrapper php_stream_phar_wrapper; ! 46: #endif ! 47: ! 48: /* for links to relative location, prepend cwd of the entry */ ! 49: static char *phar_get_link_location(phar_entry_info *entry TSRMLS_DC) /* {{{ */ ! 50: { ! 51: char *p, *ret = NULL; ! 52: if (!entry->link) { ! 53: return NULL; ! 54: } ! 55: if (entry->link[0] == '/') { ! 56: return estrdup(entry->link + 1); ! 57: } ! 58: p = strrchr(entry->filename, '/'); ! 59: if (p) { ! 60: *p = '\0'; ! 61: spprintf(&ret, 0, "%s/%s", entry->filename, entry->link); ! 62: return ret; ! 63: } ! 64: return entry->link; ! 65: } ! 66: /* }}} */ ! 67: ! 68: phar_entry_info *phar_get_link_source(phar_entry_info *entry TSRMLS_DC) /* {{{ */ ! 69: { ! 70: phar_entry_info *link_entry; ! 71: char *link; ! 72: ! 73: if (!entry->link) { ! 74: return entry; ! 75: } ! 76: ! 77: link = phar_get_link_location(entry TSRMLS_CC); ! 78: if (SUCCESS == zend_hash_find(&(entry->phar->manifest), entry->link, strlen(entry->link), (void **)&link_entry) || ! 79: SUCCESS == zend_hash_find(&(entry->phar->manifest), link, strlen(link), (void **)&link_entry)) { ! 80: if (link != entry->link) { ! 81: efree(link); ! 82: } ! 83: return phar_get_link_source(link_entry TSRMLS_CC); ! 84: } else { ! 85: if (link != entry->link) { ! 86: efree(link); ! 87: } ! 88: return NULL; ! 89: } ! 90: } ! 91: /* }}} */ ! 92: ! 93: /* retrieve a phar_entry_info's current file pointer for reading contents */ ! 94: php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC) /* {{{ */ ! 95: { ! 96: if (follow_links && entry->link) { ! 97: phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC); ! 98: ! 99: if (link_entry && link_entry != entry) { ! 100: return phar_get_efp(link_entry, 1 TSRMLS_CC); ! 101: } ! 102: } ! 103: ! 104: if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_FP) { ! 105: if (!phar_get_entrypfp(entry TSRMLS_CC)) { ! 106: /* re-open just in time for cases where our refcount reached 0 on the phar archive */ ! 107: phar_open_archive_fp(entry->phar TSRMLS_CC); ! 108: } ! 109: return phar_get_entrypfp(entry TSRMLS_CC); ! 110: } else if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_UFP) { ! 111: return phar_get_entrypufp(entry TSRMLS_CC); ! 112: } else if (entry->fp_type == PHAR_MOD) { ! 113: return entry->fp; ! 114: } else { ! 115: /* temporary manifest entry */ ! 116: if (!entry->fp) { ! 117: entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL); ! 118: } ! 119: return entry->fp; ! 120: } ! 121: } ! 122: /* }}} */ ! 123: ! 124: int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC) /* {{{ */ ! 125: { ! 126: php_stream *fp = phar_get_efp(entry, follow_links TSRMLS_CC); ! 127: off_t temp, eoffset; ! 128: ! 129: if (!fp) { ! 130: return -1; ! 131: } ! 132: ! 133: if (follow_links) { ! 134: phar_entry_info *t; ! 135: t = phar_get_link_source(entry TSRMLS_CC); ! 136: if (t) { ! 137: entry = t; ! 138: } ! 139: } ! 140: ! 141: if (entry->is_dir) { ! 142: return 0; ! 143: } ! 144: ! 145: eoffset = phar_get_fp_offset(entry TSRMLS_CC); ! 146: ! 147: switch (whence) { ! 148: case SEEK_END: ! 149: temp = eoffset + entry->uncompressed_filesize + offset; ! 150: break; ! 151: case SEEK_CUR: ! 152: temp = eoffset + position + offset; ! 153: break; ! 154: case SEEK_SET: ! 155: temp = eoffset + offset; ! 156: break; ! 157: default: ! 158: temp = 0; ! 159: break; ! 160: } ! 161: ! 162: if (temp > eoffset + (off_t) entry->uncompressed_filesize) { ! 163: return -1; ! 164: } ! 165: ! 166: if (temp < eoffset) { ! 167: return -1; ! 168: } ! 169: ! 170: return php_stream_seek(fp, temp, SEEK_SET); ! 171: } ! 172: /* }}} */ ! 173: ! 174: /* mount an absolute path or uri to a path internal to the phar archive */ ! 175: int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len, char *path, int path_len TSRMLS_DC) /* {{{ */ ! 176: { ! 177: phar_entry_info entry = {0}; ! 178: php_stream_statbuf ssb; ! 179: int is_phar; ! 180: const char *err; ! 181: ! 182: if (phar_path_check(&path, &path_len, &err) > pcr_is_ok) { ! 183: return FAILURE; ! 184: } ! 185: ! 186: if (path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) { ! 187: /* no creating magic phar files by mounting them */ ! 188: return FAILURE; ! 189: } ! 190: ! 191: is_phar = (filename_len > 7 && !memcmp(filename, "phar://", 7)); ! 192: ! 193: entry.phar = phar; ! 194: entry.filename = estrndup(path, path_len); ! 195: #ifdef PHP_WIN32 ! 196: phar_unixify_path_separators(entry.filename, path_len); ! 197: #endif ! 198: entry.filename_len = path_len; ! 199: if (is_phar) { ! 200: entry.tmp = estrndup(filename, filename_len); ! 201: } else { ! 202: entry.tmp = expand_filepath(filename, NULL TSRMLS_CC); ! 203: if (!entry.tmp) { ! 204: entry.tmp = estrndup(filename, filename_len); ! 205: } ! 206: } ! 207: #if PHP_API_VERSION < 20100412 ! 208: if (PG(safe_mode) && !is_phar && (!php_checkuid(entry.tmp, NULL, CHECKUID_CHECK_FILE_AND_DIR))) { ! 209: efree(entry.tmp); ! 210: efree(entry.filename); ! 211: return FAILURE; ! 212: } ! 213: #endif ! 214: ! 215: filename_len = strlen(entry.tmp); ! 216: filename = entry.tmp; ! 217: ! 218: /* only check openbasedir for files, not for phar streams */ ! 219: if (!is_phar && php_check_open_basedir(filename TSRMLS_CC)) { ! 220: efree(entry.tmp); ! 221: efree(entry.filename); ! 222: return FAILURE; ! 223: } ! 224: ! 225: entry.is_mounted = 1; ! 226: entry.is_crc_checked = 1; ! 227: entry.fp_type = PHAR_TMP; ! 228: ! 229: if (SUCCESS != php_stream_stat_path(filename, &ssb)) { ! 230: efree(entry.tmp); ! 231: efree(entry.filename); ! 232: return FAILURE; ! 233: } ! 234: ! 235: if (ssb.sb.st_mode & S_IFDIR) { ! 236: entry.is_dir = 1; ! 237: if (SUCCESS != zend_hash_add(&phar->mounted_dirs, entry.filename, path_len, (void *)&(entry.filename), sizeof(char *), NULL)) { ! 238: /* directory already mounted */ ! 239: efree(entry.tmp); ! 240: efree(entry.filename); ! 241: return FAILURE; ! 242: } ! 243: } else { ! 244: entry.is_dir = 0; ! 245: entry.uncompressed_filesize = entry.compressed_filesize = ssb.sb.st_size; ! 246: } ! 247: ! 248: entry.flags = ssb.sb.st_mode; ! 249: ! 250: if (SUCCESS == zend_hash_add(&phar->manifest, entry.filename, path_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { ! 251: return SUCCESS; ! 252: } ! 253: ! 254: efree(entry.tmp); ! 255: efree(entry.filename); ! 256: return FAILURE; ! 257: } ! 258: /* }}} */ ! 259: ! 260: char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_data **pphar TSRMLS_DC) /* {{{ */ ! 261: { ! 262: #if PHP_VERSION_ID >= 50300 ! 263: char *path, *fname, *arch, *entry, *ret, *test; ! 264: int arch_len, entry_len, fname_len, ret_len; ! 265: phar_archive_data *phar; ! 266: ! 267: if (pphar) { ! 268: *pphar = NULL; ! 269: } else { ! 270: pphar = &phar; ! 271: } ! 272: ! 273: if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) { ! 274: return phar_save_resolve_path(filename, filename_len TSRMLS_CC); ! 275: } ! 276: ! 277: fname = zend_get_executed_filename(TSRMLS_C); ! 278: fname_len = strlen(fname); ! 279: ! 280: if (PHAR_G(last_phar) && !memcmp(fname, "phar://", 7) && fname_len - 7 >= PHAR_G(last_phar_name_len) && !memcmp(fname + 7, PHAR_G(last_phar_name), PHAR_G(last_phar_name_len))) { ! 281: arch = estrndup(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len)); ! 282: arch_len = PHAR_G(last_phar_name_len); ! 283: phar = PHAR_G(last_phar); ! 284: goto splitted; ! 285: } ! 286: ! 287: if (fname_len < 7 || memcmp(fname, "phar://", 7) || SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) { ! 288: return phar_save_resolve_path(filename, filename_len TSRMLS_CC); ! 289: } ! 290: ! 291: efree(entry); ! 292: ! 293: if (*filename == '.') { ! 294: int try_len; ! 295: ! 296: if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) { ! 297: efree(arch); ! 298: return phar_save_resolve_path(filename, filename_len TSRMLS_CC); ! 299: } ! 300: splitted: ! 301: if (pphar) { ! 302: *pphar = phar; ! 303: } ! 304: ! 305: try_len = filename_len; ! 306: test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC); ! 307: ! 308: if (*test == '/') { ! 309: if (zend_hash_exists(&(phar->manifest), test + 1, try_len - 1)) { ! 310: spprintf(&ret, 0, "phar://%s%s", arch, test); ! 311: efree(arch); ! 312: efree(test); ! 313: return ret; ! 314: } ! 315: } else { ! 316: if (zend_hash_exists(&(phar->manifest), test, try_len)) { ! 317: spprintf(&ret, 0, "phar://%s/%s", arch, test); ! 318: efree(arch); ! 319: efree(test); ! 320: return ret; ! 321: } ! 322: } ! 323: efree(test); ! 324: } ! 325: ! 326: spprintf(&path, MAXPATHLEN, "phar://%s/%s%c%s", arch, PHAR_G(cwd), DEFAULT_DIR_SEPARATOR, PG(include_path)); ! 327: efree(arch); ! 328: ret = php_resolve_path(filename, filename_len, path TSRMLS_CC); ! 329: efree(path); ! 330: ! 331: if (ret && strlen(ret) > 8 && !strncmp(ret, "phar://", 7)) { ! 332: ret_len = strlen(ret); ! 333: /* found phar:// */ ! 334: ! 335: if (SUCCESS != phar_split_fname(ret, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) { ! 336: return ret; ! 337: } ! 338: ! 339: zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar); ! 340: ! 341: if (!pphar && PHAR_G(manifest_cached)) { ! 342: zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar); ! 343: } ! 344: ! 345: efree(arch); ! 346: efree(entry); ! 347: } ! 348: ! 349: return ret; ! 350: #else /* PHP 5.2 */ ! 351: char resolved_path[MAXPATHLEN]; ! 352: char trypath[MAXPATHLEN]; ! 353: char *ptr, *end, *path = PG(include_path); ! 354: php_stream_wrapper *wrapper; ! 355: const char *p; ! 356: int n = 0; ! 357: char *fname, *arch, *entry, *ret, *test; ! 358: int arch_len, entry_len; ! 359: phar_archive_data *phar = NULL; ! 360: ! 361: if (!filename) { ! 362: return NULL; ! 363: } ! 364: ! 365: if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) { ! 366: goto doit; ! 367: } ! 368: ! 369: fname = zend_get_executed_filename(TSRMLS_C); ! 370: ! 371: if (SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) { ! 372: goto doit; ! 373: } ! 374: ! 375: efree(entry); ! 376: ! 377: if (*filename == '.') { ! 378: int try_len; ! 379: ! 380: if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) { ! 381: efree(arch); ! 382: goto doit; ! 383: } ! 384: ! 385: try_len = filename_len; ! 386: test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC); ! 387: ! 388: if (*test == '/') { ! 389: if (zend_hash_exists(&(phar->manifest), test + 1, try_len - 1)) { ! 390: spprintf(&ret, 0, "phar://%s%s", arch, test); ! 391: efree(arch); ! 392: efree(test); ! 393: return ret; ! 394: } ! 395: } else { ! 396: if (zend_hash_exists(&(phar->manifest), test, try_len)) { ! 397: spprintf(&ret, 0, "phar://%s/%s", arch, test); ! 398: efree(arch); ! 399: efree(test); ! 400: return ret; ! 401: } ! 402: } ! 403: ! 404: efree(test); ! 405: } ! 406: ! 407: efree(arch); ! 408: doit: ! 409: if (*filename == '.' || IS_ABSOLUTE_PATH(filename, filename_len) || !path || !*path) { ! 410: if (tsrm_realpath(filename, resolved_path TSRMLS_CC)) { ! 411: return estrdup(resolved_path); ! 412: } else { ! 413: return NULL; ! 414: } ! 415: } ! 416: ! 417: /* test for stream wrappers and return */ ! 418: for (p = filename; p - filename < filename_len && (isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'); ++p, ++n); ! 419: ! 420: if (n < filename_len - 3 && (*p == ':') && (!strncmp("//", p+1, 2) || ( filename_len > 4 && !memcmp("data", filename, 4)))) { ! 421: /* found stream wrapper, this is an absolute path until stream wrappers implement realpath */ ! 422: return estrndup(filename, filename_len); ! 423: } ! 424: ! 425: ptr = (char *) path; ! 426: while (ptr && *ptr) { ! 427: int len, is_stream_wrapper = 0, maybe_stream = 1; ! 428: ! 429: end = strchr(ptr, DEFAULT_DIR_SEPARATOR); ! 430: #ifndef PHP_WIN32 ! 431: /* search for stream wrapper */ ! 432: if (end - ptr <= 1) { ! 433: maybe_stream = 0; ! 434: goto not_stream; ! 435: } ! 436: ! 437: for (p = ptr, n = 0; p < end && (isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'); ++p, ++n); ! 438: ! 439: if (n == end - ptr && *p && !strncmp("//", p+1, 2)) { ! 440: is_stream_wrapper = 1; ! 441: /* seek to real end of include_path portion */ ! 442: end = strchr(end + 1, DEFAULT_DIR_SEPARATOR); ! 443: } else { ! 444: maybe_stream = 0; ! 445: } ! 446: not_stream: ! 447: #endif ! 448: if (end) { ! 449: if ((end-ptr) + 1 + filename_len + 1 >= MAXPATHLEN) { ! 450: ptr = end + 1; ! 451: continue; ! 452: } ! 453: ! 454: memcpy(trypath, ptr, end-ptr); ! 455: len = end-ptr; ! 456: trypath[end-ptr] = '/'; ! 457: memcpy(trypath+(end-ptr)+1, filename, filename_len+1); ! 458: ptr = end+1; ! 459: } else { ! 460: len = strlen(ptr); ! 461: ! 462: if (len + 1 + filename_len + 1 >= MAXPATHLEN) { ! 463: break; ! 464: } ! 465: ! 466: memcpy(trypath, ptr, len); ! 467: trypath[len] = '/'; ! 468: memcpy(trypath+len+1, filename, filename_len+1); ! 469: ptr = NULL; ! 470: } ! 471: ! 472: if (!is_stream_wrapper && maybe_stream) { ! 473: /* search for stream wrapper */ ! 474: for (p = trypath, n = 0; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; ++p, ++n); ! 475: } ! 476: ! 477: if (is_stream_wrapper || (n < len - 3 && (*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) || !memcmp("data", trypath, 4)))) { ! 478: char *actual; ! 479: ! 480: wrapper = php_stream_locate_url_wrapper(trypath, &actual, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC); ! 481: if (wrapper == &php_plain_files_wrapper) { ! 482: strlcpy(trypath, actual, sizeof(trypath)); ! 483: } else if (!wrapper) { ! 484: /* if wrapper is NULL, there was a mal-formed include_path stream wrapper, so skip this ptr */ ! 485: continue; ! 486: } else { ! 487: if (wrapper->wops->url_stat) { ! 488: php_stream_statbuf ssb; ! 489: ! 490: if (SUCCESS == wrapper->wops->url_stat(wrapper, trypath, 0, &ssb, NULL TSRMLS_CC)) { ! 491: if (wrapper == &php_stream_phar_wrapper) { ! 492: char *arch, *entry; ! 493: int arch_len, entry_len, ret_len; ! 494: ! 495: ret_len = strlen(trypath); ! 496: /* found phar:// */ ! 497: ! 498: if (SUCCESS != phar_split_fname(trypath, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) { ! 499: return estrndup(trypath, ret_len); ! 500: } ! 501: ! 502: zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar); ! 503: ! 504: if (!pphar && PHAR_G(manifest_cached)) { ! 505: zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar); ! 506: } ! 507: ! 508: efree(arch); ! 509: efree(entry); ! 510: ! 511: return estrndup(trypath, ret_len); ! 512: } ! 513: return estrdup(trypath); ! 514: } ! 515: } ! 516: continue; ! 517: } ! 518: } ! 519: ! 520: if (tsrm_realpath(trypath, resolved_path TSRMLS_CC)) { ! 521: return estrdup(resolved_path); ! 522: } ! 523: } /* end provided path */ ! 524: ! 525: /* check in calling scripts' current working directory as a fall back case */ ! 526: if (zend_is_executing(TSRMLS_C)) { ! 527: char *exec_fname = zend_get_executed_filename(TSRMLS_C); ! 528: int exec_fname_length = strlen(exec_fname); ! 529: const char *p; ! 530: int n = 0; ! 531: ! 532: while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length])); ! 533: if (exec_fname && exec_fname[0] != '[' && ! 534: exec_fname_length > 0 && ! 535: exec_fname_length + 1 + filename_len + 1 < MAXPATHLEN) { ! 536: memcpy(trypath, exec_fname, exec_fname_length + 1); ! 537: memcpy(trypath+exec_fname_length + 1, filename, filename_len+1); ! 538: ! 539: /* search for stream wrapper */ ! 540: for (p = trypath; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; ++p, ++n); ! 541: ! 542: if (n < exec_fname_length - 3 && (*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) || !memcmp("data", trypath, 4))) { ! 543: char *actual; ! 544: ! 545: wrapper = php_stream_locate_url_wrapper(trypath, &actual, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC); ! 546: ! 547: if (wrapper == &php_plain_files_wrapper) { ! 548: /* this should never technically happen, but we'll leave it here for completeness */ ! 549: strlcpy(trypath, actual, sizeof(trypath)); ! 550: } else if (!wrapper) { ! 551: /* if wrapper is NULL, there was a malformed include_path stream wrapper ! 552: this also should be impossible */ ! 553: return NULL; ! 554: } else { ! 555: return estrdup(trypath); ! 556: } ! 557: } ! 558: ! 559: if (tsrm_realpath(trypath, resolved_path TSRMLS_CC)) { ! 560: return estrdup(resolved_path); ! 561: } ! 562: } ! 563: } ! 564: ! 565: return NULL; ! 566: #endif /* PHP 5.2 */ ! 567: } ! 568: /* }}} */ ! 569: ! 570: /** ! 571: * Retrieve a copy of the file information on a single file within a phar, or null. ! 572: * This also transfers the open file pointer, if any, to the entry. ! 573: * ! 574: * If the file does not already exist, this will fail. Pre-existing files can be ! 575: * appended, truncated, or read. For read, if the entry is marked unmodified, it is ! 576: * assumed that the file pointer, if present, is opened for reading ! 577: */ ! 578: int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error, int security TSRMLS_DC) /* {{{ */ ! 579: { ! 580: phar_archive_data *phar; ! 581: phar_entry_info *entry; ! 582: int for_write = mode[0] != 'r' || mode[1] == '+'; ! 583: int for_append = mode[0] == 'a'; ! 584: int for_create = mode[0] != 'r'; ! 585: int for_trunc = mode[0] == 'w'; ! 586: ! 587: if (!ret) { ! 588: return FAILURE; ! 589: } ! 590: ! 591: *ret = NULL; ! 592: ! 593: if (error) { ! 594: *error = NULL; ! 595: } ! 596: ! 597: if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) { ! 598: return FAILURE; ! 599: } ! 600: ! 601: if (for_write && PHAR_G(readonly) && !phar->is_data) { ! 602: if (error) { ! 603: spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, disabled by ini setting", path, fname); ! 604: } ! 605: return FAILURE; ! 606: } ! 607: ! 608: if (!path_len) { ! 609: if (error) { ! 610: spprintf(error, 4096, "phar error: file \"\" in phar \"%s\" cannot be empty", fname); ! 611: } ! 612: return FAILURE; ! 613: } ! 614: really_get_entry: ! 615: if (allow_dir) { ! 616: if ((entry = phar_get_entry_info_dir(phar, path, path_len, allow_dir, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error, security TSRMLS_CC)) == NULL) { ! 617: if (for_create && (!PHAR_G(readonly) || phar->is_data)) { ! 618: return SUCCESS; ! 619: } ! 620: return FAILURE; ! 621: } ! 622: } else { ! 623: if ((entry = phar_get_entry_info(phar, path, path_len, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error, security TSRMLS_CC)) == NULL) { ! 624: if (for_create && (!PHAR_G(readonly) || phar->is_data)) { ! 625: return SUCCESS; ! 626: } ! 627: return FAILURE; ! 628: } ! 629: } ! 630: ! 631: if (for_write && phar->is_persistent) { ! 632: if (FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) { ! 633: if (error) { ! 634: spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, could not make cached phar writeable", path, fname); ! 635: } ! 636: return FAILURE; ! 637: } else { ! 638: goto really_get_entry; ! 639: } ! 640: } ! 641: ! 642: if (entry->is_modified && !for_write) { ! 643: if (error) { ! 644: spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for reading, writable file pointers are open", path, fname); ! 645: } ! 646: return FAILURE; ! 647: } ! 648: ! 649: if (entry->fp_refcount && for_write) { ! 650: if (error) { ! 651: spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, readable file pointers are open", path, fname); ! 652: } ! 653: return FAILURE; ! 654: } ! 655: ! 656: if (entry->is_deleted) { ! 657: if (!for_create) { ! 658: return FAILURE; ! 659: } ! 660: entry->is_deleted = 0; ! 661: } ! 662: ! 663: if (entry->is_dir) { ! 664: *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data)); ! 665: (*ret)->position = 0; ! 666: (*ret)->fp = NULL; ! 667: (*ret)->phar = phar; ! 668: (*ret)->for_write = for_write; ! 669: (*ret)->internal_file = entry; ! 670: (*ret)->is_zip = entry->is_zip; ! 671: (*ret)->is_tar = entry->is_tar; ! 672: ! 673: if (!phar->is_persistent) { ! 674: ++(entry->phar->refcount); ! 675: ++(entry->fp_refcount); ! 676: } ! 677: ! 678: return SUCCESS; ! 679: } ! 680: ! 681: if (entry->fp_type == PHAR_MOD) { ! 682: if (for_trunc) { ! 683: if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) { ! 684: return FAILURE; ! 685: } ! 686: } else if (for_append) { ! 687: phar_seek_efp(entry, 0, SEEK_END, 0, 0 TSRMLS_CC); ! 688: } ! 689: } else { ! 690: if (for_write) { ! 691: if (entry->link) { ! 692: efree(entry->link); ! 693: entry->link = NULL; ! 694: entry->tar_type = (entry->is_tar ? TAR_FILE : '\0'); ! 695: } ! 696: ! 697: if (for_trunc) { ! 698: if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) { ! 699: return FAILURE; ! 700: } ! 701: } else { ! 702: if (FAILURE == phar_separate_entry_fp(entry, error TSRMLS_CC)) { ! 703: return FAILURE; ! 704: } ! 705: } ! 706: } else { ! 707: if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) { ! 708: return FAILURE; ! 709: } ! 710: } ! 711: } ! 712: ! 713: *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data)); ! 714: (*ret)->position = 0; ! 715: (*ret)->phar = phar; ! 716: (*ret)->for_write = for_write; ! 717: (*ret)->internal_file = entry; ! 718: (*ret)->is_zip = entry->is_zip; ! 719: (*ret)->is_tar = entry->is_tar; ! 720: (*ret)->fp = phar_get_efp(entry, 1 TSRMLS_CC); ! 721: if (entry->link) { ! 722: (*ret)->zero = phar_get_fp_offset(phar_get_link_source(entry TSRMLS_CC) TSRMLS_CC); ! 723: } else { ! 724: (*ret)->zero = phar_get_fp_offset(entry TSRMLS_CC); ! 725: } ! 726: ! 727: if (!phar->is_persistent) { ! 728: ++(entry->fp_refcount); ! 729: ++(entry->phar->refcount); ! 730: } ! 731: ! 732: return SUCCESS; ! 733: } ! 734: /* }}} */ ! 735: ! 736: /** ! 737: * Create a new dummy file slot within a writeable phar for a newly created file ! 738: */ ! 739: phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error, int security TSRMLS_DC) /* {{{ */ ! 740: { ! 741: phar_archive_data *phar; ! 742: phar_entry_info *entry, etemp; ! 743: phar_entry_data *ret; ! 744: const char *pcr_error; ! 745: char is_dir; ! 746: ! 747: #ifdef PHP_WIN32 ! 748: phar_unixify_path_separators(path, path_len); ! 749: #endif ! 750: ! 751: is_dir = (path_len && path[path_len - 1] == '/') ? 1 : 0; ! 752: ! 753: if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) { ! 754: return NULL; ! 755: } ! 756: ! 757: if (FAILURE == phar_get_entry_data(&ret, fname, fname_len, path, path_len, mode, allow_dir, error, security TSRMLS_CC)) { ! 758: return NULL; ! 759: } else if (ret) { ! 760: return ret; ! 761: } ! 762: ! 763: if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) { ! 764: if (error) { ! 765: spprintf(error, 0, "phar error: invalid path \"%s\" contains %s", path, pcr_error); ! 766: } ! 767: return NULL; ! 768: } ! 769: ! 770: if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) { ! 771: if (error) { ! 772: spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be created, could not make cached phar writeable", path, fname); ! 773: } ! 774: return NULL; ! 775: } ! 776: ! 777: /* create a new phar data holder */ ! 778: ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data)); ! 779: ! 780: /* create an entry, this is a new file */ ! 781: memset(&etemp, 0, sizeof(phar_entry_info)); ! 782: etemp.filename_len = path_len; ! 783: etemp.fp_type = PHAR_MOD; ! 784: etemp.fp = php_stream_fopen_tmpfile(); ! 785: ! 786: if (!etemp.fp) { ! 787: if (error) { ! 788: spprintf(error, 0, "phar error: unable to create temporary file"); ! 789: } ! 790: efree(ret); ! 791: return NULL; ! 792: } ! 793: ! 794: etemp.fp_refcount = 1; ! 795: ! 796: if (allow_dir == 2) { ! 797: etemp.is_dir = 1; ! 798: etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_DIR; ! 799: } else { ! 800: etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_FILE; ! 801: } ! 802: if (is_dir) { ! 803: etemp.filename_len--; /* strip trailing / */ ! 804: path_len--; ! 805: } ! 806: ! 807: phar_add_virtual_dirs(phar, path, path_len TSRMLS_CC); ! 808: etemp.is_modified = 1; ! 809: etemp.timestamp = time(0); ! 810: etemp.is_crc_checked = 1; ! 811: etemp.phar = phar; ! 812: etemp.filename = estrndup(path, path_len); ! 813: etemp.is_zip = phar->is_zip; ! 814: ! 815: if (phar->is_tar) { ! 816: etemp.is_tar = phar->is_tar; ! 817: etemp.tar_type = etemp.is_dir ? TAR_DIR : TAR_FILE; ! 818: } ! 819: ! 820: if (FAILURE == zend_hash_add(&phar->manifest, etemp.filename, path_len, (void*)&etemp, sizeof(phar_entry_info), (void **) &entry)) { ! 821: php_stream_close(etemp.fp); ! 822: if (error) { ! 823: spprintf(error, 0, "phar error: unable to add new entry \"%s\" to phar \"%s\"", etemp.filename, phar->fname); ! 824: } ! 825: efree(ret); ! 826: efree(etemp.filename); ! 827: return NULL; ! 828: } ! 829: ! 830: if (!entry) { ! 831: php_stream_close(etemp.fp); ! 832: efree(etemp.filename); ! 833: efree(ret); ! 834: return NULL; ! 835: } ! 836: ! 837: ++(phar->refcount); ! 838: ret->phar = phar; ! 839: ret->fp = entry->fp; ! 840: ret->position = ret->zero = 0; ! 841: ret->for_write = 1; ! 842: ret->is_zip = entry->is_zip; ! 843: ret->is_tar = entry->is_tar; ! 844: ret->internal_file = entry; ! 845: ! 846: return ret; ! 847: } ! 848: /* }}} */ ! 849: ! 850: /* initialize a phar_archive_data's read-only fp for existing phar data */ ! 851: int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC) /* {{{ */ ! 852: { ! 853: if (phar_get_pharfp(phar TSRMLS_CC)) { ! 854: return SUCCESS; ! 855: } ! 856: #if PHP_API_VERSION < 20100412 ! 857: if (PG(safe_mode) && (!php_checkuid(phar->fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) { ! 858: return FAILURE; ! 859: } ! 860: #endif ! 861: ! 862: if (php_check_open_basedir(phar->fname TSRMLS_CC)) { ! 863: return FAILURE; ! 864: } ! 865: ! 866: phar_set_pharfp(phar, php_stream_open_wrapper(phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL) TSRMLS_CC); ! 867: ! 868: if (!phar_get_pharfp(phar TSRMLS_CC)) { ! 869: return FAILURE; ! 870: } ! 871: ! 872: return SUCCESS; ! 873: } ! 874: /* }}} */ ! 875: ! 876: /* copy file data from an existing to a new phar_entry_info that is not in the manifest */ ! 877: int phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error TSRMLS_DC) /* {{{ */ ! 878: { ! 879: phar_entry_info *link; ! 880: ! 881: if (FAILURE == phar_open_entry_fp(source, error, 1 TSRMLS_CC)) { ! 882: return FAILURE; ! 883: } ! 884: ! 885: if (dest->link) { ! 886: efree(dest->link); ! 887: dest->link = NULL; ! 888: dest->tar_type = (dest->is_tar ? TAR_FILE : '\0'); ! 889: } ! 890: ! 891: dest->fp_type = PHAR_MOD; ! 892: dest->offset = 0; ! 893: dest->is_modified = 1; ! 894: dest->fp = php_stream_fopen_tmpfile(); ! 895: phar_seek_efp(source, 0, SEEK_SET, 0, 1 TSRMLS_CC); ! 896: link = phar_get_link_source(source TSRMLS_CC); ! 897: ! 898: if (!link) { ! 899: link = source; ! 900: } ! 901: ! 902: if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), dest->fp, link->uncompressed_filesize, NULL)) { ! 903: php_stream_close(dest->fp); ! 904: dest->fp_type = PHAR_FP; ! 905: if (error) { ! 906: spprintf(error, 4096, "phar error: unable to copy contents of file \"%s\" to \"%s\" in phar archive \"%s\"", source->filename, dest->filename, source->phar->fname); ! 907: } ! 908: return FAILURE; ! 909: } ! 910: ! 911: return SUCCESS; ! 912: } ! 913: /* }}} */ ! 914: ! 915: /* open and decompress a compressed phar entry ! 916: */ ! 917: int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TSRMLS_DC) /* {{{ */ ! 918: { ! 919: php_stream_filter *filter; ! 920: phar_archive_data *phar = entry->phar; ! 921: char *filtername; ! 922: off_t loc; ! 923: php_stream *ufp; ! 924: phar_entry_data dummy; ! 925: ! 926: if (follow_links && entry->link) { ! 927: phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC); ! 928: if (link_entry && link_entry != entry) { ! 929: return phar_open_entry_fp(link_entry, error, 1 TSRMLS_CC); ! 930: } ! 931: } ! 932: ! 933: if (entry->is_modified) { ! 934: return SUCCESS; ! 935: } ! 936: ! 937: if (entry->fp_type == PHAR_TMP) { ! 938: if (!entry->fp) { ! 939: entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL); ! 940: } ! 941: return SUCCESS; ! 942: } ! 943: ! 944: if (entry->fp_type != PHAR_FP) { ! 945: /* either newly created or already modified */ ! 946: return SUCCESS; ! 947: } ! 948: ! 949: if (!phar_get_pharfp(phar TSRMLS_CC)) { ! 950: if (FAILURE == phar_open_archive_fp(phar TSRMLS_CC)) { ! 951: spprintf(error, 4096, "phar error: Cannot open phar archive \"%s\" for reading", phar->fname); ! 952: return FAILURE; ! 953: } ! 954: } ! 955: ! 956: if ((entry->old_flags && !(entry->old_flags & PHAR_ENT_COMPRESSION_MASK)) || !(entry->flags & PHAR_ENT_COMPRESSION_MASK)) { ! 957: dummy.internal_file = entry; ! 958: dummy.phar = phar; ! 959: dummy.zero = entry->offset; ! 960: dummy.fp = phar_get_pharfp(phar TSRMLS_CC); ! 961: if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) { ! 962: return FAILURE; ! 963: } ! 964: return SUCCESS; ! 965: } ! 966: ! 967: if (!phar_get_entrypufp(entry TSRMLS_CC)) { ! 968: phar_set_entrypufp(entry, php_stream_fopen_tmpfile() TSRMLS_CC); ! 969: if (!phar_get_entrypufp(entry TSRMLS_CC)) { ! 970: spprintf(error, 4096, "phar error: Cannot open temporary file for decompressing phar archive \"%s\" file \"%s\"", phar->fname, entry->filename); ! 971: return FAILURE; ! 972: } ! 973: } ! 974: ! 975: dummy.internal_file = entry; ! 976: dummy.phar = phar; ! 977: dummy.zero = entry->offset; ! 978: dummy.fp = phar_get_pharfp(phar TSRMLS_CC); ! 979: if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) { ! 980: return FAILURE; ! 981: } ! 982: ! 983: ufp = phar_get_entrypufp(entry TSRMLS_CC); ! 984: ! 985: if ((filtername = phar_decompress_filter(entry, 0)) != NULL) { ! 986: filter = php_stream_filter_create(filtername, NULL, 0 TSRMLS_CC); ! 987: } else { ! 988: filter = NULL; ! 989: } ! 990: ! 991: if (!filter) { ! 992: spprintf(error, 4096, "phar error: unable to read phar \"%s\" (cannot create %s filter while decompressing file \"%s\")", phar->fname, phar_decompress_filter(entry, 1), entry->filename); ! 993: return FAILURE; ! 994: } ! 995: ! 996: /* now we can safely use proper decompression */ ! 997: /* save the new offset location within ufp */ ! 998: php_stream_seek(ufp, 0, SEEK_END); ! 999: loc = php_stream_tell(ufp); ! 1000: php_stream_filter_append(&ufp->writefilters, filter); ! 1001: php_stream_seek(phar_get_entrypfp(entry TSRMLS_CC), phar_get_fp_offset(entry TSRMLS_CC), SEEK_SET); ! 1002: ! 1003: if (entry->uncompressed_filesize) { ! 1004: if (SUCCESS != phar_stream_copy_to_stream(phar_get_entrypfp(entry TSRMLS_CC), ufp, entry->compressed_filesize, NULL)) { ! 1005: spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename); ! 1006: php_stream_filter_remove(filter, 1 TSRMLS_CC); ! 1007: return FAILURE; ! 1008: } ! 1009: } ! 1010: ! 1011: php_stream_filter_flush(filter, 1); ! 1012: php_stream_flush(ufp); ! 1013: php_stream_filter_remove(filter, 1 TSRMLS_CC); ! 1014: ! 1015: if (php_stream_tell(ufp) - loc != (off_t) entry->uncompressed_filesize) { ! 1016: spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename); ! 1017: return FAILURE; ! 1018: } ! 1019: ! 1020: entry->old_flags = entry->flags; ! 1021: ! 1022: /* this is now the new location of the file contents within this fp */ ! 1023: phar_set_fp_type(entry, PHAR_UFP, loc TSRMLS_CC); ! 1024: dummy.zero = entry->offset; ! 1025: dummy.fp = ufp; ! 1026: if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 0 TSRMLS_CC)) { ! 1027: return FAILURE; ! 1028: } ! 1029: return SUCCESS; ! 1030: } ! 1031: /* }}} */ ! 1032: ! 1033: #if defined(PHP_VERSION_ID) && PHP_VERSION_ID < 50202 ! 1034: typedef struct { ! 1035: char *data; ! 1036: size_t fpos; ! 1037: size_t fsize; ! 1038: size_t smax; ! 1039: int mode; ! 1040: php_stream **owner_ptr; ! 1041: } php_stream_memory_data; ! 1042: #endif ! 1043: ! 1044: int phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */ ! 1045: { ! 1046: if (entry->fp_type == PHAR_MOD) { ! 1047: /* already newly created, truncate */ ! 1048: #if PHP_VERSION_ID >= 50202 ! 1049: php_stream_truncate_set_size(entry->fp, 0); ! 1050: #else ! 1051: if (php_stream_is(entry->fp, PHP_STREAM_IS_TEMP)) { ! 1052: if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_MEMORY)) { ! 1053: php_stream *inner = *(php_stream**)entry->fp->abstract; ! 1054: php_stream_memory_data *memfp = (php_stream_memory_data*)inner->abstract; ! 1055: memfp->fpos = 0; ! 1056: memfp->fsize = 0; ! 1057: } else if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_STDIO)) { ! 1058: php_stream_truncate_set_size(*(php_stream**)entry->fp->abstract, 0); ! 1059: } else { ! 1060: if (error) { ! 1061: spprintf(error, 0, "phar error: file \"%s\" cannot be opened for writing, no truncate support", phar->fname); ! 1062: } ! 1063: return FAILURE; ! 1064: } ! 1065: } else if (php_stream_is(entry->fp, PHP_STREAM_IS_STDIO)) { ! 1066: php_stream_truncate_set_size(entry->fp, 0); ! 1067: } else { ! 1068: if (error) { ! 1069: spprintf(error, 0, "phar error: file \"%s\" cannot be opened for writing, no truncate support", phar->fname); ! 1070: } ! 1071: return FAILURE; ! 1072: } ! 1073: #endif ! 1074: entry->old_flags = entry->flags; ! 1075: entry->is_modified = 1; ! 1076: phar->is_modified = 1; ! 1077: /* reset file size */ ! 1078: entry->uncompressed_filesize = 0; ! 1079: entry->compressed_filesize = 0; ! 1080: entry->crc32 = 0; ! 1081: entry->flags = PHAR_ENT_PERM_DEF_FILE; ! 1082: entry->fp_type = PHAR_MOD; ! 1083: entry->offset = 0; ! 1084: return SUCCESS; ! 1085: } ! 1086: ! 1087: if (error) { ! 1088: *error = NULL; ! 1089: } ! 1090: ! 1091: /* open a new temp file for writing */ ! 1092: if (entry->link) { ! 1093: efree(entry->link); ! 1094: entry->link = NULL; ! 1095: entry->tar_type = (entry->is_tar ? TAR_FILE : '\0'); ! 1096: } ! 1097: ! 1098: entry->fp = php_stream_fopen_tmpfile(); ! 1099: ! 1100: if (!entry->fp) { ! 1101: if (error) { ! 1102: spprintf(error, 0, "phar error: unable to create temporary file"); ! 1103: } ! 1104: return FAILURE; ! 1105: } ! 1106: ! 1107: entry->old_flags = entry->flags; ! 1108: entry->is_modified = 1; ! 1109: phar->is_modified = 1; ! 1110: /* reset file size */ ! 1111: entry->uncompressed_filesize = 0; ! 1112: entry->compressed_filesize = 0; ! 1113: entry->crc32 = 0; ! 1114: entry->flags = PHAR_ENT_PERM_DEF_FILE; ! 1115: entry->fp_type = PHAR_MOD; ! 1116: entry->offset = 0; ! 1117: return SUCCESS; ! 1118: } ! 1119: /* }}} */ ! 1120: ! 1121: int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */ ! 1122: { ! 1123: php_stream *fp; ! 1124: phar_entry_info *link; ! 1125: ! 1126: if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) { ! 1127: return FAILURE; ! 1128: } ! 1129: ! 1130: if (entry->fp_type == PHAR_MOD) { ! 1131: return SUCCESS; ! 1132: } ! 1133: ! 1134: fp = php_stream_fopen_tmpfile(); ! 1135: phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC); ! 1136: link = phar_get_link_source(entry TSRMLS_CC); ! 1137: ! 1138: if (!link) { ! 1139: link = entry; ! 1140: } ! 1141: ! 1142: if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), fp, link->uncompressed_filesize, NULL)) { ! 1143: if (error) { ! 1144: spprintf(error, 4096, "phar error: cannot separate entry file \"%s\" contents in phar archive \"%s\" for write access", entry->filename, entry->phar->fname); ! 1145: } ! 1146: return FAILURE; ! 1147: } ! 1148: ! 1149: if (entry->link) { ! 1150: efree(entry->link); ! 1151: entry->link = NULL; ! 1152: entry->tar_type = (entry->is_tar ? TAR_FILE : '\0'); ! 1153: } ! 1154: ! 1155: entry->offset = 0; ! 1156: entry->fp = fp; ! 1157: entry->fp_type = PHAR_MOD; ! 1158: entry->is_modified = 1; ! 1159: return SUCCESS; ! 1160: } ! 1161: /* }}} */ ! 1162: ! 1163: /** ! 1164: * helper function to open an internal file's fp just-in-time ! 1165: */ ! 1166: phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */ ! 1167: { ! 1168: if (error) { ! 1169: *error = NULL; ! 1170: } ! 1171: /* seek to start of internal file and read it */ ! 1172: if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) { ! 1173: return NULL; ! 1174: } ! 1175: if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) { ! 1176: spprintf(error, 4096, "phar error: cannot seek to start of file \"%s\" in phar \"%s\"", entry->filename, phar->fname); ! 1177: return NULL; ! 1178: } ! 1179: return entry; ! 1180: } ! 1181: /* }}} */ ! 1182: ! 1183: int phar_free_alias(phar_archive_data *phar, char *alias, int alias_len TSRMLS_DC) /* {{{ */ ! 1184: { ! 1185: if (phar->refcount || phar->is_persistent) { ! 1186: return FAILURE; ! 1187: } ! 1188: ! 1189: /* this archive has no open references, so emit an E_STRICT and remove it */ ! 1190: if (zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) { ! 1191: return FAILURE; ! 1192: } ! 1193: ! 1194: /* invalidate phar cache */ ! 1195: PHAR_G(last_phar) = NULL; ! 1196: PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL; ! 1197: ! 1198: return SUCCESS; ! 1199: } ! 1200: /* }}} */ ! 1201: ! 1202: /** ! 1203: * Looks up a phar archive in the filename map, connecting it to the alias ! 1204: * (if any) or returns null ! 1205: */ ! 1206: int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, char *alias, int alias_len, char **error TSRMLS_DC) /* {{{ */ ! 1207: { ! 1208: phar_archive_data *fd, **fd_ptr; ! 1209: char *my_realpath, *save; ! 1210: int save_len; ! 1211: ulong fhash, ahash = 0; ! 1212: ! 1213: phar_request_initialize(TSRMLS_C); ! 1214: ! 1215: if (error) { ! 1216: *error = NULL; ! 1217: } ! 1218: ! 1219: *archive = NULL; ! 1220: ! 1221: if (PHAR_G(last_phar) && fname_len == PHAR_G(last_phar_name_len) && !memcmp(fname, PHAR_G(last_phar_name), fname_len)) { ! 1222: *archive = PHAR_G(last_phar); ! 1223: if (alias && alias_len) { ! 1224: ! 1225: if (!PHAR_G(last_phar)->is_temporary_alias && (alias_len != PHAR_G(last_phar)->alias_len || memcmp(PHAR_G(last_phar)->alias, alias, alias_len))) { ! 1226: if (error) { ! 1227: spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, PHAR_G(last_phar)->fname, fname); ! 1228: } ! 1229: *archive = NULL; ! 1230: return FAILURE; ! 1231: } ! 1232: ! 1233: if (PHAR_G(last_phar)->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len, (void**)&fd_ptr)) { ! 1234: zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len); ! 1235: } ! 1236: ! 1237: zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&(*archive), sizeof(phar_archive_data*), NULL); ! 1238: PHAR_G(last_alias) = alias; ! 1239: PHAR_G(last_alias_len) = alias_len; ! 1240: } ! 1241: ! 1242: return SUCCESS; ! 1243: } ! 1244: ! 1245: if (alias && alias_len && PHAR_G(last_phar) && alias_len == PHAR_G(last_alias_len) && !memcmp(alias, PHAR_G(last_alias), alias_len)) { ! 1246: fd = PHAR_G(last_phar); ! 1247: fd_ptr = &fd; ! 1248: goto alias_success; ! 1249: } ! 1250: ! 1251: if (alias && alias_len) { ! 1252: ahash = zend_inline_hash_func(alias, alias_len); ! 1253: if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void**)&fd_ptr)) { ! 1254: alias_success: ! 1255: if (fname && (fname_len != (*fd_ptr)->fname_len || strncmp(fname, (*fd_ptr)->fname, fname_len))) { ! 1256: if (error) { ! 1257: spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname); ! 1258: } ! 1259: if (SUCCESS == phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) { ! 1260: efree(*error); ! 1261: *error = NULL; ! 1262: } ! 1263: return FAILURE; ! 1264: } ! 1265: ! 1266: *archive = *fd_ptr; ! 1267: fd = *fd_ptr; ! 1268: PHAR_G(last_phar) = fd; ! 1269: PHAR_G(last_phar_name) = fd->fname; ! 1270: PHAR_G(last_phar_name_len) = fd->fname_len; ! 1271: PHAR_G(last_alias) = alias; ! 1272: PHAR_G(last_alias_len) = alias_len; ! 1273: ! 1274: return SUCCESS; ! 1275: } ! 1276: ! 1277: if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, alias, alias_len, ahash, (void **)&fd_ptr)) { ! 1278: goto alias_success; ! 1279: } ! 1280: } ! 1281: ! 1282: fhash = zend_inline_hash_func(fname, fname_len); ! 1283: my_realpath = NULL; ! 1284: save = fname; ! 1285: save_len = fname_len; ! 1286: ! 1287: if (fname && fname_len) { ! 1288: if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) { ! 1289: *archive = *fd_ptr; ! 1290: fd = *fd_ptr; ! 1291: ! 1292: if (alias && alias_len) { ! 1293: if (!fd->is_temporary_alias && (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len))) { ! 1294: if (error) { ! 1295: spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname); ! 1296: } ! 1297: return FAILURE; ! 1298: } ! 1299: ! 1300: if (fd->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len, (void**)&fd_ptr)) { ! 1301: zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len); ! 1302: } ! 1303: ! 1304: zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL); ! 1305: } ! 1306: ! 1307: PHAR_G(last_phar) = fd; ! 1308: PHAR_G(last_phar_name) = fd->fname; ! 1309: PHAR_G(last_phar_name_len) = fd->fname_len; ! 1310: PHAR_G(last_alias) = fd->alias; ! 1311: PHAR_G(last_alias_len) = fd->alias_len; ! 1312: ! 1313: return SUCCESS; ! 1314: } ! 1315: ! 1316: if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) { ! 1317: *archive = *fd_ptr; ! 1318: fd = *fd_ptr; ! 1319: ! 1320: /* this could be problematic - alias should never be different from manifest alias ! 1321: for cached phars */ ! 1322: if (!fd->is_temporary_alias && alias && alias_len) { ! 1323: if (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len)) { ! 1324: if (error) { ! 1325: spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname); ! 1326: } ! 1327: return FAILURE; ! 1328: } ! 1329: } ! 1330: ! 1331: PHAR_G(last_phar) = fd; ! 1332: PHAR_G(last_phar_name) = fd->fname; ! 1333: PHAR_G(last_phar_name_len) = fd->fname_len; ! 1334: PHAR_G(last_alias) = fd->alias; ! 1335: PHAR_G(last_alias_len) = fd->alias_len; ! 1336: ! 1337: return SUCCESS; ! 1338: } ! 1339: ! 1340: if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), save, save_len, fhash, (void**)&fd_ptr)) { ! 1341: fd = *archive = *fd_ptr; ! 1342: ! 1343: PHAR_G(last_phar) = fd; ! 1344: PHAR_G(last_phar_name) = fd->fname; ! 1345: PHAR_G(last_phar_name_len) = fd->fname_len; ! 1346: PHAR_G(last_alias) = fd->alias; ! 1347: PHAR_G(last_alias_len) = fd->alias_len; ! 1348: ! 1349: return SUCCESS; ! 1350: } ! 1351: ! 1352: if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, save, save_len, fhash, (void**)&fd_ptr)) { ! 1353: fd = *archive = *fd_ptr; ! 1354: ! 1355: PHAR_G(last_phar) = fd; ! 1356: PHAR_G(last_phar_name) = fd->fname; ! 1357: PHAR_G(last_phar_name_len) = fd->fname_len; ! 1358: PHAR_G(last_alias) = fd->alias; ! 1359: PHAR_G(last_alias_len) = fd->alias_len; ! 1360: ! 1361: return SUCCESS; ! 1362: } ! 1363: ! 1364: /* not found, try converting \ to / */ ! 1365: my_realpath = expand_filepath(fname, my_realpath TSRMLS_CC); ! 1366: ! 1367: if (my_realpath) { ! 1368: fname_len = strlen(my_realpath); ! 1369: fname = my_realpath; ! 1370: } else { ! 1371: return FAILURE; ! 1372: } ! 1373: #ifdef PHP_WIN32 ! 1374: phar_unixify_path_separators(fname, fname_len); ! 1375: #endif ! 1376: fhash = zend_inline_hash_func(fname, fname_len); ! 1377: ! 1378: if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) { ! 1379: realpath_success: ! 1380: *archive = *fd_ptr; ! 1381: fd = *fd_ptr; ! 1382: ! 1383: if (alias && alias_len) { ! 1384: zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL); ! 1385: } ! 1386: ! 1387: efree(my_realpath); ! 1388: ! 1389: PHAR_G(last_phar) = fd; ! 1390: PHAR_G(last_phar_name) = fd->fname; ! 1391: PHAR_G(last_phar_name_len) = fd->fname_len; ! 1392: PHAR_G(last_alias) = fd->alias; ! 1393: PHAR_G(last_alias_len) = fd->alias_len; ! 1394: ! 1395: return SUCCESS; ! 1396: } ! 1397: ! 1398: if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) { ! 1399: goto realpath_success; ! 1400: } ! 1401: ! 1402: efree(my_realpath); ! 1403: } ! 1404: ! 1405: return FAILURE; ! 1406: } ! 1407: /* }}} */ ! 1408: ! 1409: /** ! 1410: * Determine which stream compression filter (if any) we need to read this file ! 1411: */ ! 1412: char * phar_compress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */ ! 1413: { ! 1414: switch (entry->flags & PHAR_ENT_COMPRESSION_MASK) { ! 1415: case PHAR_ENT_COMPRESSED_GZ: ! 1416: return "zlib.deflate"; ! 1417: case PHAR_ENT_COMPRESSED_BZ2: ! 1418: return "bzip2.compress"; ! 1419: default: ! 1420: return return_unknown ? "unknown" : NULL; ! 1421: } ! 1422: } ! 1423: /* }}} */ ! 1424: ! 1425: /** ! 1426: * Determine which stream decompression filter (if any) we need to read this file ! 1427: */ ! 1428: char * phar_decompress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */ ! 1429: { ! 1430: php_uint32 flags; ! 1431: ! 1432: if (entry->is_modified) { ! 1433: flags = entry->old_flags; ! 1434: } else { ! 1435: flags = entry->flags; ! 1436: } ! 1437: ! 1438: switch (flags & PHAR_ENT_COMPRESSION_MASK) { ! 1439: case PHAR_ENT_COMPRESSED_GZ: ! 1440: return "zlib.inflate"; ! 1441: case PHAR_ENT_COMPRESSED_BZ2: ! 1442: return "bzip2.decompress"; ! 1443: default: ! 1444: return return_unknown ? "unknown" : NULL; ! 1445: } ! 1446: } ! 1447: /* }}} */ ! 1448: ! 1449: /** ! 1450: * retrieve information on a file contained within a phar, or null if it ain't there ! 1451: */ ! 1452: phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len, char **error, int security TSRMLS_DC) /* {{{ */ ! 1453: { ! 1454: return phar_get_entry_info_dir(phar, path, path_len, 0, error, security TSRMLS_CC); ! 1455: } ! 1456: /* }}} */ ! 1457: /** ! 1458: * retrieve information on a file or directory contained within a phar, or null if none found ! 1459: * allow_dir is 0 for none, 1 for both empty directories in the phar and temp directories, and 2 for only ! 1460: * valid pre-existing empty directory entries ! 1461: */ ! 1462: phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, int path_len, char dir, char **error, int security TSRMLS_DC) /* {{{ */ ! 1463: { ! 1464: const char *pcr_error; ! 1465: phar_entry_info *entry; ! 1466: int is_dir; ! 1467: ! 1468: #ifdef PHP_WIN32 ! 1469: phar_unixify_path_separators(path, path_len); ! 1470: #endif ! 1471: ! 1472: is_dir = (path_len && (path[path_len - 1] == '/')) ? 1 : 0; ! 1473: ! 1474: if (error) { ! 1475: *error = NULL; ! 1476: } ! 1477: ! 1478: if (security && path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) { ! 1479: if (error) { ! 1480: spprintf(error, 4096, "phar error: cannot directly access magic \".phar\" directory or files within it"); ! 1481: } ! 1482: return NULL; ! 1483: } ! 1484: ! 1485: if (!path_len && !dir) { ! 1486: if (error) { ! 1487: spprintf(error, 4096, "phar error: invalid path \"%s\" must not be empty", path); ! 1488: } ! 1489: return NULL; ! 1490: } ! 1491: ! 1492: if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) { ! 1493: if (error) { ! 1494: spprintf(error, 4096, "phar error: invalid path \"%s\" contains %s", path, pcr_error); ! 1495: } ! 1496: return NULL; ! 1497: } ! 1498: ! 1499: if (!phar->manifest.arBuckets) { ! 1500: return NULL; ! 1501: } ! 1502: ! 1503: if (is_dir) { ! 1504: if (!path_len || path_len == 1) { ! 1505: return NULL; ! 1506: } ! 1507: path_len--; ! 1508: } ! 1509: ! 1510: if (SUCCESS == zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) { ! 1511: if (entry->is_deleted) { ! 1512: /* entry is deleted, but has not been flushed to disk yet */ ! 1513: return NULL; ! 1514: } ! 1515: if (entry->is_dir && !dir) { ! 1516: if (error) { ! 1517: spprintf(error, 4096, "phar error: path \"%s\" is a directory", path); ! 1518: } ! 1519: return NULL; ! 1520: } ! 1521: if (!entry->is_dir && dir == 2) { ! 1522: /* user requested a directory, we must return one */ ! 1523: if (error) { ! 1524: spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path); ! 1525: } ! 1526: return NULL; ! 1527: } ! 1528: return entry; ! 1529: } ! 1530: ! 1531: if (dir) { ! 1532: if (zend_hash_exists(&phar->virtual_dirs, path, path_len)) { ! 1533: /* a file or directory exists in a sub-directory of this path */ ! 1534: entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info)); ! 1535: /* this next line tells PharFileInfo->__destruct() to efree the filename */ ! 1536: entry->is_temp_dir = entry->is_dir = 1; ! 1537: entry->filename = (char *) estrndup(path, path_len + 1); ! 1538: entry->filename_len = path_len; ! 1539: entry->phar = phar; ! 1540: return entry; ! 1541: } ! 1542: } ! 1543: ! 1544: if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) { ! 1545: phar_zstr key; ! 1546: char *str_key; ! 1547: ulong unused; ! 1548: uint keylen; ! 1549: ! 1550: zend_hash_internal_pointer_reset(&phar->mounted_dirs); ! 1551: while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) { ! 1552: if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, NULL)) { ! 1553: break; ! 1554: } ! 1555: ! 1556: PHAR_STR(key, str_key); ! 1557: ! 1558: if ((int)keylen >= path_len || strncmp(str_key, path, keylen)) { ! 1559: PHAR_STR_FREE(str_key); ! 1560: continue; ! 1561: } else { ! 1562: char *test; ! 1563: int test_len; ! 1564: php_stream_statbuf ssb; ! 1565: ! 1566: if (SUCCESS != zend_hash_find(&phar->manifest, str_key, keylen, (void **) &entry)) { ! 1567: if (error) { ! 1568: spprintf(error, 4096, "phar internal error: mounted path \"%s\" could not be retrieved from manifest", str_key); ! 1569: } ! 1570: PHAR_STR_FREE(str_key); ! 1571: return NULL; ! 1572: } ! 1573: ! 1574: if (!entry->tmp || !entry->is_mounted) { ! 1575: if (error) { ! 1576: spprintf(error, 4096, "phar internal error: mounted path \"%s\" is not properly initialized as a mounted path", str_key); ! 1577: } ! 1578: PHAR_STR_FREE(str_key); ! 1579: return NULL; ! 1580: } ! 1581: PHAR_STR_FREE(str_key); ! 1582: ! 1583: test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, path + keylen); ! 1584: ! 1585: if (SUCCESS != php_stream_stat_path(test, &ssb)) { ! 1586: efree(test); ! 1587: return NULL; ! 1588: } ! 1589: ! 1590: if (ssb.sb.st_mode & S_IFDIR && !dir) { ! 1591: efree(test); ! 1592: if (error) { ! 1593: spprintf(error, 4096, "phar error: path \"%s\" is a directory", path); ! 1594: } ! 1595: return NULL; ! 1596: } ! 1597: ! 1598: if ((ssb.sb.st_mode & S_IFDIR) == 0 && dir) { ! 1599: efree(test); ! 1600: /* user requested a directory, we must return one */ ! 1601: if (error) { ! 1602: spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path); ! 1603: } ! 1604: return NULL; ! 1605: } ! 1606: ! 1607: /* mount the file just in time */ ! 1608: if (SUCCESS != phar_mount_entry(phar, test, test_len, path, path_len TSRMLS_CC)) { ! 1609: efree(test); ! 1610: if (error) { ! 1611: spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be mounted", path, test); ! 1612: } ! 1613: return NULL; ! 1614: } ! 1615: ! 1616: efree(test); ! 1617: ! 1618: if (SUCCESS != zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) { ! 1619: if (error) { ! 1620: spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be retrieved after being mounted", path, test); ! 1621: } ! 1622: return NULL; ! 1623: } ! 1624: return entry; ! 1625: } ! 1626: } ! 1627: } ! 1628: ! 1629: return NULL; ! 1630: } ! 1631: /* }}} */ ! 1632: ! 1633: static const char hexChars[] = "0123456789ABCDEF"; ! 1634: ! 1635: static int phar_hex_str(const char *digest, size_t digest_len, char **signature TSRMLS_DC) /* {{{ */ ! 1636: { ! 1637: int pos = -1; ! 1638: size_t len = 0; ! 1639: ! 1640: *signature = (char*)safe_pemalloc(digest_len, 2, 1, PHAR_G(persist)); ! 1641: ! 1642: for (; len < digest_len; ++len) { ! 1643: (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] >> 4]; ! 1644: (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] & 0x0F]; ! 1645: } ! 1646: (*signature)[++pos] = '\0'; ! 1647: return pos; ! 1648: } ! 1649: /* }}} */ ! 1650: ! 1651: #ifndef PHAR_HAVE_OPENSSL ! 1652: static int phar_call_openssl_signverify(int is_sign, php_stream *fp, off_t end, char *key, int key_len, char **signature, int *signature_len TSRMLS_DC) /* {{{ */ ! 1653: { ! 1654: zend_fcall_info fci; ! 1655: zend_fcall_info_cache fcc; ! 1656: zval *zdata, *zsig, *zkey, *retval_ptr, **zp[3], *openssl; ! 1657: ! 1658: MAKE_STD_ZVAL(zdata); ! 1659: MAKE_STD_ZVAL(openssl); ! 1660: ZVAL_STRINGL(openssl, is_sign ? "openssl_sign" : "openssl_verify", is_sign ? sizeof("openssl_sign")-1 : sizeof("openssl_verify")-1, 1); ! 1661: MAKE_STD_ZVAL(zsig); ! 1662: ZVAL_STRINGL(zsig, *signature, *signature_len, 1); ! 1663: MAKE_STD_ZVAL(zkey); ! 1664: ZVAL_STRINGL(zkey, key, key_len, 1); ! 1665: zp[0] = &zdata; ! 1666: zp[1] = &zsig; ! 1667: zp[2] = &zkey; ! 1668: ! 1669: php_stream_rewind(fp); ! 1670: Z_TYPE_P(zdata) = IS_STRING; ! 1671: Z_STRLEN_P(zdata) = end; ! 1672: ! 1673: #if PHP_MAJOR_VERSION > 5 ! 1674: if (end != (off_t) php_stream_copy_to_mem(fp, (void **) &(Z_STRVAL_P(zdata)), (size_t) end, 0)) { ! 1675: #else ! 1676: if (end != (off_t) php_stream_copy_to_mem(fp, &(Z_STRVAL_P(zdata)), (size_t) end, 0)) { ! 1677: #endif ! 1678: zval_dtor(zdata); ! 1679: zval_dtor(zsig); ! 1680: zval_dtor(zkey); ! 1681: zval_dtor(openssl); ! 1682: efree(openssl); ! 1683: efree(zdata); ! 1684: efree(zkey); ! 1685: efree(zsig); ! 1686: return FAILURE; ! 1687: } ! 1688: ! 1689: #if PHP_VERSION_ID < 50300 ! 1690: if (FAILURE == zend_fcall_info_init(openssl, &fci, &fcc TSRMLS_CC)) { ! 1691: #else ! 1692: if (FAILURE == zend_fcall_info_init(openssl, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) { ! 1693: #endif ! 1694: zval_dtor(zdata); ! 1695: zval_dtor(zsig); ! 1696: zval_dtor(zkey); ! 1697: zval_dtor(openssl); ! 1698: efree(openssl); ! 1699: efree(zdata); ! 1700: efree(zkey); ! 1701: efree(zsig); ! 1702: return FAILURE; ! 1703: } ! 1704: ! 1705: fci.param_count = 3; ! 1706: fci.params = zp; ! 1707: #if PHP_VERSION_ID < 50300 ! 1708: ++(zdata->refcount); ! 1709: if (!is_sign) { ! 1710: ++(zsig->refcount); ! 1711: } ! 1712: ++(zkey->refcount); ! 1713: #else ! 1714: Z_ADDREF_P(zdata); ! 1715: if (is_sign) { ! 1716: Z_SET_ISREF_P(zsig); ! 1717: } else { ! 1718: Z_ADDREF_P(zsig); ! 1719: } ! 1720: Z_ADDREF_P(zkey); ! 1721: #endif ! 1722: fci.retval_ptr_ptr = &retval_ptr; ! 1723: ! 1724: if (FAILURE == zend_call_function(&fci, &fcc TSRMLS_CC)) { ! 1725: zval_dtor(zdata); ! 1726: zval_dtor(zsig); ! 1727: zval_dtor(zkey); ! 1728: zval_dtor(openssl); ! 1729: efree(openssl); ! 1730: efree(zdata); ! 1731: efree(zkey); ! 1732: efree(zsig); ! 1733: return FAILURE; ! 1734: } ! 1735: ! 1736: zval_dtor(openssl); ! 1737: efree(openssl); ! 1738: #if PHP_VERSION_ID < 50300 ! 1739: --(zdata->refcount); ! 1740: if (!is_sign) { ! 1741: --(zsig->refcount); ! 1742: } ! 1743: --(zkey->refcount); ! 1744: #else ! 1745: Z_DELREF_P(zdata); ! 1746: if (is_sign) { ! 1747: Z_UNSET_ISREF_P(zsig); ! 1748: } else { ! 1749: Z_DELREF_P(zsig); ! 1750: } ! 1751: Z_DELREF_P(zkey); ! 1752: #endif ! 1753: zval_dtor(zdata); ! 1754: efree(zdata); ! 1755: zval_dtor(zkey); ! 1756: efree(zkey); ! 1757: ! 1758: switch (Z_TYPE_P(retval_ptr)) { ! 1759: default: ! 1760: case IS_LONG: ! 1761: zval_dtor(zsig); ! 1762: efree(zsig); ! 1763: if (1 == Z_LVAL_P(retval_ptr)) { ! 1764: efree(retval_ptr); ! 1765: return SUCCESS; ! 1766: } ! 1767: efree(retval_ptr); ! 1768: return FAILURE; ! 1769: case IS_BOOL: ! 1770: efree(retval_ptr); ! 1771: if (Z_BVAL_P(retval_ptr)) { ! 1772: *signature = estrndup(Z_STRVAL_P(zsig), Z_STRLEN_P(zsig)); ! 1773: *signature_len = Z_STRLEN_P(zsig); ! 1774: zval_dtor(zsig); ! 1775: efree(zsig); ! 1776: return SUCCESS; ! 1777: } ! 1778: zval_dtor(zsig); ! 1779: efree(zsig); ! 1780: return FAILURE; ! 1781: } ! 1782: } ! 1783: /* }}} */ ! 1784: #endif /* #ifndef PHAR_HAVE_OPENSSL */ ! 1785: ! 1786: int phar_verify_signature(php_stream *fp, size_t end_of_phar, php_uint32 sig_type, char *sig, int sig_len, char *fname, char **signature, int *signature_len, char **error TSRMLS_DC) /* {{{ */ ! 1787: { ! 1788: int read_size, len; ! 1789: off_t read_len; ! 1790: unsigned char buf[1024]; ! 1791: ! 1792: php_stream_rewind(fp); ! 1793: ! 1794: switch (sig_type) { ! 1795: case PHAR_SIG_OPENSSL: { ! 1796: #ifdef PHAR_HAVE_OPENSSL ! 1797: BIO *in; ! 1798: EVP_PKEY *key; ! 1799: EVP_MD *mdtype = (EVP_MD *) EVP_sha1(); ! 1800: EVP_MD_CTX md_ctx; ! 1801: #else ! 1802: int tempsig; ! 1803: #endif ! 1804: php_uint32 pubkey_len; ! 1805: char *pubkey = NULL, *pfile; ! 1806: php_stream *pfp; ! 1807: #ifndef PHAR_HAVE_OPENSSL ! 1808: if (!zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) { ! 1809: if (error) { ! 1810: spprintf(error, 0, "openssl not loaded"); ! 1811: } ! 1812: return FAILURE; ! 1813: } ! 1814: #endif ! 1815: /* use __FILE__ . '.pubkey' for public key file */ ! 1816: spprintf(&pfile, 0, "%s.pubkey", fname); ! 1817: pfp = php_stream_open_wrapper(pfile, "rb", 0, NULL); ! 1818: efree(pfile); ! 1819: ! 1820: #if PHP_MAJOR_VERSION > 5 ! 1821: if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, (void **) &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) { ! 1822: #else ! 1823: if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) { ! 1824: #endif ! 1825: if (pfp) { ! 1826: php_stream_close(pfp); ! 1827: } ! 1828: if (error) { ! 1829: spprintf(error, 0, "openssl public key could not be read"); ! 1830: } ! 1831: return FAILURE; ! 1832: } ! 1833: ! 1834: php_stream_close(pfp); ! 1835: #ifndef PHAR_HAVE_OPENSSL ! 1836: tempsig = sig_len; ! 1837: ! 1838: if (FAILURE == phar_call_openssl_signverify(0, fp, end_of_phar, pubkey, pubkey_len, &sig, &tempsig TSRMLS_CC)) { ! 1839: if (pubkey) { ! 1840: efree(pubkey); ! 1841: } ! 1842: ! 1843: if (error) { ! 1844: spprintf(error, 0, "openssl signature could not be verified"); ! 1845: } ! 1846: ! 1847: return FAILURE; ! 1848: } ! 1849: ! 1850: if (pubkey) { ! 1851: efree(pubkey); ! 1852: } ! 1853: ! 1854: sig_len = tempsig; ! 1855: #else ! 1856: in = BIO_new_mem_buf(pubkey, pubkey_len); ! 1857: ! 1858: if (NULL == in) { ! 1859: efree(pubkey); ! 1860: if (error) { ! 1861: spprintf(error, 0, "openssl signature could not be processed"); ! 1862: } ! 1863: return FAILURE; ! 1864: } ! 1865: ! 1866: key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL); ! 1867: BIO_free(in); ! 1868: efree(pubkey); ! 1869: ! 1870: if (NULL == key) { ! 1871: if (error) { ! 1872: spprintf(error, 0, "openssl signature could not be processed"); ! 1873: } ! 1874: return FAILURE; ! 1875: } ! 1876: ! 1877: EVP_VerifyInit(&md_ctx, mdtype); ! 1878: read_len = end_of_phar; ! 1879: ! 1880: if (read_len > sizeof(buf)) { ! 1881: read_size = sizeof(buf); ! 1882: } else { ! 1883: read_size = (int)read_len; ! 1884: } ! 1885: ! 1886: php_stream_seek(fp, 0, SEEK_SET); ! 1887: ! 1888: while (read_size && (len = php_stream_read(fp, (char*)buf, read_size)) > 0) { ! 1889: EVP_VerifyUpdate (&md_ctx, buf, len); ! 1890: read_len -= (off_t)len; ! 1891: ! 1892: if (read_len < read_size) { ! 1893: read_size = (int)read_len; ! 1894: } ! 1895: } ! 1896: ! 1897: if (EVP_VerifyFinal(&md_ctx, (unsigned char *)sig, sig_len, key) != 1) { ! 1898: /* 1: signature verified, 0: signature does not match, -1: failed signature operation */ ! 1899: EVP_MD_CTX_cleanup(&md_ctx); ! 1900: ! 1901: if (error) { ! 1902: spprintf(error, 0, "broken openssl signature"); ! 1903: } ! 1904: ! 1905: return FAILURE; ! 1906: } ! 1907: ! 1908: EVP_MD_CTX_cleanup(&md_ctx); ! 1909: #endif ! 1910: ! 1911: *signature_len = phar_hex_str((const char*)sig, sig_len, signature TSRMLS_CC); ! 1912: } ! 1913: break; ! 1914: #ifdef PHAR_HASH_OK ! 1915: case PHAR_SIG_SHA512: { ! 1916: unsigned char digest[64]; ! 1917: PHP_SHA512_CTX context; ! 1918: ! 1919: PHP_SHA512Init(&context); ! 1920: read_len = end_of_phar; ! 1921: ! 1922: if (read_len > sizeof(buf)) { ! 1923: read_size = sizeof(buf); ! 1924: } else { ! 1925: read_size = (int)read_len; ! 1926: } ! 1927: ! 1928: while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) { ! 1929: PHP_SHA512Update(&context, buf, len); ! 1930: read_len -= (off_t)len; ! 1931: if (read_len < read_size) { ! 1932: read_size = (int)read_len; ! 1933: } ! 1934: } ! 1935: ! 1936: PHP_SHA512Final(digest, &context); ! 1937: ! 1938: if (memcmp(digest, sig, sizeof(digest))) { ! 1939: if (error) { ! 1940: spprintf(error, 0, "broken signature"); ! 1941: } ! 1942: return FAILURE; ! 1943: } ! 1944: ! 1945: *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC); ! 1946: break; ! 1947: } ! 1948: case PHAR_SIG_SHA256: { ! 1949: unsigned char digest[32]; ! 1950: PHP_SHA256_CTX context; ! 1951: ! 1952: PHP_SHA256Init(&context); ! 1953: read_len = end_of_phar; ! 1954: ! 1955: if (read_len > sizeof(buf)) { ! 1956: read_size = sizeof(buf); ! 1957: } else { ! 1958: read_size = (int)read_len; ! 1959: } ! 1960: ! 1961: while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) { ! 1962: PHP_SHA256Update(&context, buf, len); ! 1963: read_len -= (off_t)len; ! 1964: if (read_len < read_size) { ! 1965: read_size = (int)read_len; ! 1966: } ! 1967: } ! 1968: ! 1969: PHP_SHA256Final(digest, &context); ! 1970: ! 1971: if (memcmp(digest, sig, sizeof(digest))) { ! 1972: if (error) { ! 1973: spprintf(error, 0, "broken signature"); ! 1974: } ! 1975: return FAILURE; ! 1976: } ! 1977: ! 1978: *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC); ! 1979: break; ! 1980: } ! 1981: #else ! 1982: case PHAR_SIG_SHA512: ! 1983: case PHAR_SIG_SHA256: ! 1984: if (error) { ! 1985: spprintf(error, 0, "unsupported signature"); ! 1986: } ! 1987: return FAILURE; ! 1988: #endif ! 1989: case PHAR_SIG_SHA1: { ! 1990: unsigned char digest[20]; ! 1991: PHP_SHA1_CTX context; ! 1992: ! 1993: PHP_SHA1Init(&context); ! 1994: read_len = end_of_phar; ! 1995: ! 1996: if (read_len > sizeof(buf)) { ! 1997: read_size = sizeof(buf); ! 1998: } else { ! 1999: read_size = (int)read_len; ! 2000: } ! 2001: ! 2002: while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) { ! 2003: PHP_SHA1Update(&context, buf, len); ! 2004: read_len -= (off_t)len; ! 2005: if (read_len < read_size) { ! 2006: read_size = (int)read_len; ! 2007: } ! 2008: } ! 2009: ! 2010: PHP_SHA1Final(digest, &context); ! 2011: ! 2012: if (memcmp(digest, sig, sizeof(digest))) { ! 2013: if (error) { ! 2014: spprintf(error, 0, "broken signature"); ! 2015: } ! 2016: return FAILURE; ! 2017: } ! 2018: ! 2019: *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC); ! 2020: break; ! 2021: } ! 2022: case PHAR_SIG_MD5: { ! 2023: unsigned char digest[16]; ! 2024: PHP_MD5_CTX context; ! 2025: ! 2026: PHP_MD5Init(&context); ! 2027: read_len = end_of_phar; ! 2028: ! 2029: if (read_len > sizeof(buf)) { ! 2030: read_size = sizeof(buf); ! 2031: } else { ! 2032: read_size = (int)read_len; ! 2033: } ! 2034: ! 2035: while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) { ! 2036: PHP_MD5Update(&context, buf, len); ! 2037: read_len -= (off_t)len; ! 2038: if (read_len < read_size) { ! 2039: read_size = (int)read_len; ! 2040: } ! 2041: } ! 2042: ! 2043: PHP_MD5Final(digest, &context); ! 2044: ! 2045: if (memcmp(digest, sig, sizeof(digest))) { ! 2046: if (error) { ! 2047: spprintf(error, 0, "broken signature"); ! 2048: } ! 2049: return FAILURE; ! 2050: } ! 2051: ! 2052: *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC); ! 2053: break; ! 2054: } ! 2055: default: ! 2056: if (error) { ! 2057: spprintf(error, 0, "broken or unsupported signature"); ! 2058: } ! 2059: return FAILURE; ! 2060: } ! 2061: return SUCCESS; ! 2062: } ! 2063: /* }}} */ ! 2064: ! 2065: int phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, int *signature_length, char **error TSRMLS_DC) /* {{{ */ ! 2066: { ! 2067: unsigned char buf[1024]; ! 2068: int sig_len; ! 2069: ! 2070: php_stream_rewind(fp); ! 2071: ! 2072: if (phar->signature) { ! 2073: efree(phar->signature); ! 2074: phar->signature = NULL; ! 2075: } ! 2076: ! 2077: switch(phar->sig_flags) { ! 2078: #ifdef PHAR_HASH_OK ! 2079: case PHAR_SIG_SHA512: { ! 2080: unsigned char digest[64]; ! 2081: PHP_SHA512_CTX context; ! 2082: ! 2083: PHP_SHA512Init(&context); ! 2084: ! 2085: while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) { ! 2086: PHP_SHA512Update(&context, buf, sig_len); ! 2087: } ! 2088: ! 2089: PHP_SHA512Final(digest, &context); ! 2090: *signature = estrndup((char *) digest, 64); ! 2091: *signature_length = 64; ! 2092: break; ! 2093: } ! 2094: case PHAR_SIG_SHA256: { ! 2095: unsigned char digest[32]; ! 2096: PHP_SHA256_CTX context; ! 2097: ! 2098: PHP_SHA256Init(&context); ! 2099: ! 2100: while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) { ! 2101: PHP_SHA256Update(&context, buf, sig_len); ! 2102: } ! 2103: ! 2104: PHP_SHA256Final(digest, &context); ! 2105: *signature = estrndup((char *) digest, 32); ! 2106: *signature_length = 32; ! 2107: break; ! 2108: } ! 2109: #else ! 2110: case PHAR_SIG_SHA512: ! 2111: case PHAR_SIG_SHA256: ! 2112: if (error) { ! 2113: spprintf(error, 0, "unable to write to phar \"%s\" with requested hash type", phar->fname); ! 2114: } ! 2115: ! 2116: return FAILURE; ! 2117: #endif ! 2118: case PHAR_SIG_OPENSSL: { ! 2119: int siglen; ! 2120: unsigned char *sigbuf; ! 2121: #ifdef PHAR_HAVE_OPENSSL ! 2122: BIO *in; ! 2123: EVP_PKEY *key; ! 2124: EVP_MD *mdtype = (EVP_MD *) EVP_sha1(); ! 2125: EVP_MD_CTX md_ctx; ! 2126: ! 2127: in = BIO_new_mem_buf(PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len)); ! 2128: ! 2129: if (in == NULL) { ! 2130: if (error) { ! 2131: spprintf(error, 0, "unable to write to phar \"%s\" with requested openssl signature", phar->fname); ! 2132: } ! 2133: return FAILURE; ! 2134: } ! 2135: ! 2136: key = PEM_read_bio_PrivateKey(in, NULL,NULL, ""); ! 2137: BIO_free(in); ! 2138: ! 2139: if (!key) { ! 2140: if (error) { ! 2141: spprintf(error, 0, "unable to process private key"); ! 2142: } ! 2143: return FAILURE; ! 2144: } ! 2145: ! 2146: siglen = EVP_PKEY_size(key); ! 2147: sigbuf = emalloc(siglen + 1); ! 2148: EVP_SignInit(&md_ctx, mdtype); ! 2149: ! 2150: while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) { ! 2151: EVP_SignUpdate(&md_ctx, buf, sig_len); ! 2152: } ! 2153: ! 2154: if (!EVP_SignFinal (&md_ctx, sigbuf,(unsigned int *)&siglen, key)) { ! 2155: efree(sigbuf); ! 2156: if (error) { ! 2157: spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname); ! 2158: } ! 2159: return FAILURE; ! 2160: } ! 2161: ! 2162: sigbuf[siglen] = '\0'; ! 2163: EVP_MD_CTX_cleanup(&md_ctx); ! 2164: #else ! 2165: sigbuf = NULL; ! 2166: siglen = 0; ! 2167: php_stream_seek(fp, 0, SEEK_END); ! 2168: ! 2169: if (FAILURE == phar_call_openssl_signverify(1, fp, php_stream_tell(fp), PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len), (char **)&sigbuf, &siglen TSRMLS_CC)) { ! 2170: if (error) { ! 2171: spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname); ! 2172: } ! 2173: return FAILURE; ! 2174: } ! 2175: #endif ! 2176: *signature = (char *) sigbuf; ! 2177: *signature_length = siglen; ! 2178: } ! 2179: break; ! 2180: default: ! 2181: phar->sig_flags = PHAR_SIG_SHA1; ! 2182: case PHAR_SIG_SHA1: { ! 2183: unsigned char digest[20]; ! 2184: PHP_SHA1_CTX context; ! 2185: ! 2186: PHP_SHA1Init(&context); ! 2187: ! 2188: while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) { ! 2189: PHP_SHA1Update(&context, buf, sig_len); ! 2190: } ! 2191: ! 2192: PHP_SHA1Final(digest, &context); ! 2193: *signature = estrndup((char *) digest, 20); ! 2194: *signature_length = 20; ! 2195: break; ! 2196: } ! 2197: case PHAR_SIG_MD5: { ! 2198: unsigned char digest[16]; ! 2199: PHP_MD5_CTX context; ! 2200: ! 2201: PHP_MD5Init(&context); ! 2202: ! 2203: while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) { ! 2204: PHP_MD5Update(&context, buf, sig_len); ! 2205: } ! 2206: ! 2207: PHP_MD5Final(digest, &context); ! 2208: *signature = estrndup((char *) digest, 16); ! 2209: *signature_length = 16; ! 2210: break; ! 2211: } ! 2212: } ! 2213: ! 2214: phar->sig_len = phar_hex_str((const char *)*signature, *signature_length, &phar->signature TSRMLS_CC); ! 2215: return SUCCESS; ! 2216: } ! 2217: /* }}} */ ! 2218: ! 2219: void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC) /* {{{ */ ! 2220: { ! 2221: char *s; ! 2222: ! 2223: while ((s = zend_memrchr(filename, '/', filename_len))) { ! 2224: filename_len = s - filename; ! 2225: if (FAILURE == zend_hash_add_empty_element(&phar->virtual_dirs, filename, filename_len)) { ! 2226: break; ! 2227: } ! 2228: } ! 2229: } ! 2230: /* }}} */ ! 2231: ! 2232: static int phar_update_cached_entry(void *data, void *argument) /* {{{ */ ! 2233: { ! 2234: phar_entry_info *entry = (phar_entry_info *)data; ! 2235: TSRMLS_FETCH(); ! 2236: ! 2237: entry->phar = (phar_archive_data *)argument; ! 2238: ! 2239: if (entry->link) { ! 2240: entry->link = estrdup(entry->link); ! 2241: } ! 2242: ! 2243: if (entry->tmp) { ! 2244: entry->tmp = estrdup(entry->tmp); ! 2245: } ! 2246: ! 2247: entry->metadata_str.c = 0; ! 2248: entry->filename = estrndup(entry->filename, entry->filename_len); ! 2249: entry->is_persistent = 0; ! 2250: ! 2251: if (entry->metadata) { ! 2252: if (entry->metadata_len) { ! 2253: char *buf = estrndup((char *) entry->metadata, entry->metadata_len); ! 2254: /* assume success, we would have failed before */ ! 2255: phar_parse_metadata((char **) &buf, &entry->metadata, entry->metadata_len TSRMLS_CC); ! 2256: efree(buf); ! 2257: } else { ! 2258: zval *t; ! 2259: ! 2260: t = entry->metadata; ! 2261: ALLOC_ZVAL(entry->metadata); ! 2262: *entry->metadata = *t; ! 2263: zval_copy_ctor(entry->metadata); ! 2264: #if PHP_VERSION_ID < 50300 ! 2265: entry->metadata->refcount = 1; ! 2266: #else ! 2267: Z_SET_REFCOUNT_P(entry->metadata, 1); ! 2268: #endif ! 2269: entry->metadata_str.c = NULL; ! 2270: entry->metadata_str.len = 0; ! 2271: } ! 2272: } ! 2273: return ZEND_HASH_APPLY_KEEP; ! 2274: } ! 2275: /* }}} */ ! 2276: ! 2277: static void phar_copy_cached_phar(phar_archive_data **pphar TSRMLS_DC) /* {{{ */ ! 2278: { ! 2279: phar_archive_data *phar; ! 2280: HashTable newmanifest; ! 2281: char *fname; ! 2282: phar_archive_object **objphar; ! 2283: ! 2284: phar = (phar_archive_data *) emalloc(sizeof(phar_archive_data)); ! 2285: *phar = **pphar; ! 2286: phar->is_persistent = 0; ! 2287: fname = phar->fname; ! 2288: phar->fname = estrndup(phar->fname, phar->fname_len); ! 2289: phar->ext = phar->fname + (phar->ext - fname); ! 2290: ! 2291: if (phar->alias) { ! 2292: phar->alias = estrndup(phar->alias, phar->alias_len); ! 2293: } ! 2294: ! 2295: if (phar->signature) { ! 2296: phar->signature = estrdup(phar->signature); ! 2297: } ! 2298: ! 2299: if (phar->metadata) { ! 2300: /* assume success, we would have failed before */ ! 2301: if (phar->metadata_len) { ! 2302: char *buf = estrndup((char *) phar->metadata, phar->metadata_len); ! 2303: phar_parse_metadata(&buf, &phar->metadata, phar->metadata_len TSRMLS_CC); ! 2304: efree(buf); ! 2305: } else { ! 2306: zval *t; ! 2307: ! 2308: t = phar->metadata; ! 2309: ALLOC_ZVAL(phar->metadata); ! 2310: *phar->metadata = *t; ! 2311: zval_copy_ctor(phar->metadata); ! 2312: #if PHP_VERSION_ID < 50300 ! 2313: phar->metadata->refcount = 1; ! 2314: #else ! 2315: Z_SET_REFCOUNT_P(phar->metadata, 1); ! 2316: #endif ! 2317: } ! 2318: } ! 2319: ! 2320: zend_hash_init(&newmanifest, sizeof(phar_entry_info), ! 2321: zend_get_hash_value, destroy_phar_manifest_entry, 0); ! 2322: zend_hash_copy(&newmanifest, &(*pphar)->manifest, NULL, NULL, sizeof(phar_entry_info)); ! 2323: zend_hash_apply_with_argument(&newmanifest, (apply_func_arg_t) phar_update_cached_entry, (void *)phar TSRMLS_CC); ! 2324: phar->manifest = newmanifest; ! 2325: zend_hash_init(&phar->mounted_dirs, sizeof(char *), ! 2326: zend_get_hash_value, NULL, 0); ! 2327: zend_hash_init(&phar->virtual_dirs, sizeof(char *), ! 2328: zend_get_hash_value, NULL, 0); ! 2329: zend_hash_copy(&phar->virtual_dirs, &(*pphar)->virtual_dirs, NULL, NULL, sizeof(void *)); ! 2330: *pphar = phar; ! 2331: ! 2332: /* now, scan the list of persistent Phar objects referencing this phar and update the pointers */ ! 2333: for (zend_hash_internal_pointer_reset(&PHAR_GLOBALS->phar_persist_map); ! 2334: SUCCESS == zend_hash_get_current_data(&PHAR_GLOBALS->phar_persist_map, (void **) &objphar); ! 2335: zend_hash_move_forward(&PHAR_GLOBALS->phar_persist_map)) { ! 2336: if (objphar[0]->arc.archive->fname_len == phar->fname_len && !memcmp(objphar[0]->arc.archive->fname, phar->fname, phar->fname_len)) { ! 2337: objphar[0]->arc.archive = phar; ! 2338: } ! 2339: } ! 2340: } ! 2341: /* }}} */ ! 2342: ! 2343: int phar_copy_on_write(phar_archive_data **pphar TSRMLS_DC) /* {{{ */ ! 2344: { ! 2345: phar_archive_data **newpphar, *newphar = NULL; ! 2346: ! 2347: if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len, (void *)&newphar, sizeof(phar_archive_data *), (void **)&newpphar)) { ! 2348: return FAILURE; ! 2349: } ! 2350: ! 2351: *newpphar = *pphar; ! 2352: phar_copy_cached_phar(newpphar TSRMLS_CC); ! 2353: /* invalidate phar cache */ ! 2354: PHAR_G(last_phar) = NULL; ! 2355: PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL; ! 2356: ! 2357: if (newpphar[0]->alias_len && FAILURE == zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), newpphar[0]->alias, newpphar[0]->alias_len, (void*)newpphar, sizeof(phar_archive_data*), NULL)) { ! 2358: zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len); ! 2359: return FAILURE; ! 2360: } ! 2361: ! 2362: *pphar = *newpphar; ! 2363: return SUCCESS; ! 2364: } ! 2365: /* }}} */ ! 2366: ! 2367: /* ! 2368: * Local variables: ! 2369: * tab-width: 4 ! 2370: * c-basic-offset: 4 ! 2371: * End: ! 2372: * vim600: noet sw=4 ts=4 fdm=marker ! 2373: * vim<600: noet sw=4 ts=4 ! 2374: */