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