Back to index

php5  5.3.10
util.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | phar php single-file executable PHP extension                        |
00004   | utility functions                                                    |
00005   +----------------------------------------------------------------------+
00006   | Copyright (c) 2005-2012 The PHP Group                                |
00007   +----------------------------------------------------------------------+
00008   | This source file is subject to version 3.01 of the PHP license,      |
00009   | that is bundled with this package in the file LICENSE, and is        |
00010   | available through the world-wide-web at the following url:           |
00011   | http://www.php.net/license/3_01.txt.                                 |
00012   | If you did not receive a copy of the PHP license and are unable to   |
00013   | obtain it through the world-wide-web, please send a note to          |
00014   | license@php.net so we can mail you a copy immediately.               |
00015   +----------------------------------------------------------------------+
00016   | Authors: Gregory Beaver <cellog@php.net>                             |
00017   |          Marcus Boerger <helly@php.net>                              |
00018   +----------------------------------------------------------------------+
00019 */
00020 
00021 /* $Id: util.c 321634 2012-01-01 13:15:04Z felipe $ */
00022 
00023 #include "phar_internal.h"
00024 #ifdef PHAR_HASH_OK
00025 #include "ext/hash/php_hash_sha.h"
00026 #endif
00027 
00028 #ifdef PHAR_HAVE_OPENSSL
00029 /* OpenSSL includes */
00030 #include <openssl/evp.h>
00031 #include <openssl/x509.h>
00032 #include <openssl/x509v3.h>
00033 #include <openssl/crypto.h>
00034 #include <openssl/pem.h>
00035 #include <openssl/err.h>
00036 #include <openssl/conf.h>
00037 #include <openssl/rand.h>
00038 #include <openssl/ssl.h>
00039 #include <openssl/pkcs12.h>
00040 #else
00041 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);
00042 #endif
00043 
00044 #if !defined(PHP_VERSION_ID) || PHP_VERSION_ID < 50300
00045 extern php_stream_wrapper php_stream_phar_wrapper;
00046 #endif
00047 
00048 /* for links to relative location, prepend cwd of the entry */
00049 static char *phar_get_link_location(phar_entry_info *entry TSRMLS_DC) /* {{{ */
00050 {
00051        char *p, *ret = NULL;
00052        if (!entry->link) {
00053               return NULL;
00054        }
00055        if (entry->link[0] == '/') {
00056               return estrdup(entry->link + 1);
00057        }
00058        p = strrchr(entry->filename, '/');
00059        if (p) {
00060               *p = '\0';
00061               spprintf(&ret, 0, "%s/%s", entry->filename, entry->link);
00062               return ret;
00063        }
00064        return entry->link;
00065 }
00066 /* }}} */
00067 
00068 phar_entry_info *phar_get_link_source(phar_entry_info *entry TSRMLS_DC) /* {{{ */
00069 {
00070        phar_entry_info *link_entry;
00071        char *link;
00072 
00073        if (!entry->link) {
00074               return entry;
00075        }
00076 
00077        link = phar_get_link_location(entry TSRMLS_CC);
00078        if (SUCCESS == zend_hash_find(&(entry->phar->manifest), entry->link, strlen(entry->link), (void **)&link_entry) ||
00079               SUCCESS == zend_hash_find(&(entry->phar->manifest), link, strlen(link), (void **)&link_entry)) {
00080               if (link != entry->link) {
00081                      efree(link);
00082               }
00083               return phar_get_link_source(link_entry TSRMLS_CC);
00084        } else {
00085               if (link != entry->link) {
00086                      efree(link);
00087               }
00088               return NULL;
00089        }
00090 }
00091 /* }}} */
00092 
00093 /* retrieve a phar_entry_info's current file pointer for reading contents */
00094 php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC) /* {{{ */
00095 {
00096        if (follow_links && entry->link) {
00097               phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
00098 
00099               if (link_entry && link_entry != entry) {
00100                      return phar_get_efp(link_entry, 1 TSRMLS_CC);
00101               }
00102        }
00103 
00104        if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_FP) {
00105               if (!phar_get_entrypfp(entry TSRMLS_CC)) {
00106                      /* re-open just in time for cases where our refcount reached 0 on the phar archive */
00107                      phar_open_archive_fp(entry->phar TSRMLS_CC);
00108               }
00109               return phar_get_entrypfp(entry TSRMLS_CC);
00110        } else if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_UFP) {
00111               return phar_get_entrypufp(entry TSRMLS_CC);
00112        } else if (entry->fp_type == PHAR_MOD) {
00113               return entry->fp;
00114        } else {
00115               /* temporary manifest entry */
00116               if (!entry->fp) {
00117                      entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
00118               }
00119               return entry->fp;
00120        }
00121 }
00122 /* }}} */
00123 
00124 int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC) /* {{{ */
00125 {
00126        php_stream *fp = phar_get_efp(entry, follow_links TSRMLS_CC);
00127        off_t temp, eoffset;
00128 
00129        if (!fp) {
00130               return -1;
00131        }
00132 
00133        if (follow_links) {
00134               phar_entry_info *t;
00135               t = phar_get_link_source(entry TSRMLS_CC);
00136               if (t) {
00137                      entry = t;
00138               }
00139        }
00140 
00141        if (entry->is_dir) {
00142               return 0;
00143        }
00144 
00145        eoffset = phar_get_fp_offset(entry TSRMLS_CC);
00146 
00147        switch (whence) {
00148               case SEEK_END:
00149                      temp = eoffset + entry->uncompressed_filesize + offset;
00150                      break;
00151               case SEEK_CUR:
00152                      temp = eoffset + position + offset;
00153                      break;
00154               case SEEK_SET:
00155                      temp = eoffset + offset;
00156                      break;
00157               default:
00158                      temp = 0;
00159                      break;
00160        }
00161 
00162        if (temp > eoffset + (off_t) entry->uncompressed_filesize) {
00163               return -1;
00164        }
00165 
00166        if (temp < eoffset) {
00167               return -1;
00168        }
00169 
00170        return php_stream_seek(fp, temp, SEEK_SET);
00171 }
00172 /* }}} */
00173 
00174 /* mount an absolute path or uri to a path internal to the phar archive */
00175 int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len, char *path, int path_len TSRMLS_DC) /* {{{ */
00176 {
00177        phar_entry_info entry = {0};
00178        php_stream_statbuf ssb;
00179        int is_phar;
00180        const char *err;
00181 
00182        if (phar_path_check(&path, &path_len, &err) > pcr_is_ok) {
00183               return FAILURE;
00184        }
00185 
00186        if (path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) {
00187               /* no creating magic phar files by mounting them */
00188               return FAILURE;
00189        }
00190 
00191        is_phar = (filename_len > 7 && !memcmp(filename, "phar://", 7));
00192 
00193        entry.phar = phar;
00194        entry.filename = estrndup(path, path_len);
00195 #ifdef PHP_WIN32
00196        phar_unixify_path_separators(entry.filename, path_len);
00197 #endif
00198        entry.filename_len = path_len;
00199        if (is_phar) {
00200               entry.tmp = estrndup(filename, filename_len);
00201        } else {
00202               entry.tmp = expand_filepath(filename, NULL TSRMLS_CC);
00203               if (!entry.tmp) {
00204                      entry.tmp = estrndup(filename, filename_len);
00205               }
00206        }
00207 #if PHP_API_VERSION < 20100412
00208        if (PG(safe_mode) && !is_phar && (!php_checkuid(entry.tmp, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
00209               efree(entry.tmp);
00210               efree(entry.filename);
00211               return FAILURE;
00212        }
00213 #endif
00214 
00215        filename_len = strlen(entry.tmp);
00216        filename = entry.tmp;
00217 
00218        /* only check openbasedir for files, not for phar streams */
00219        if (!is_phar && php_check_open_basedir(filename TSRMLS_CC)) {
00220               efree(entry.tmp);
00221               efree(entry.filename);
00222               return FAILURE;
00223        }
00224 
00225        entry.is_mounted = 1;
00226        entry.is_crc_checked = 1;
00227        entry.fp_type = PHAR_TMP;
00228 
00229        if (SUCCESS != php_stream_stat_path(filename, &ssb)) {
00230               efree(entry.tmp);
00231               efree(entry.filename);
00232               return FAILURE;
00233        }
00234 
00235        if (ssb.sb.st_mode & S_IFDIR) {
00236               entry.is_dir = 1;
00237               if (SUCCESS != zend_hash_add(&phar->mounted_dirs, entry.filename, path_len, (void *)&(entry.filename), sizeof(char *), NULL)) {
00238                      /* directory already mounted */
00239                      efree(entry.tmp);
00240                      efree(entry.filename);
00241                      return FAILURE;
00242               }
00243        } else {
00244               entry.is_dir = 0;
00245               entry.uncompressed_filesize = entry.compressed_filesize = ssb.sb.st_size;
00246        }
00247 
00248        entry.flags = ssb.sb.st_mode;
00249 
00250        if (SUCCESS == zend_hash_add(&phar->manifest, entry.filename, path_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
00251               return SUCCESS;
00252        }
00253 
00254        efree(entry.tmp);
00255        efree(entry.filename);
00256        return FAILURE;
00257 }
00258 /* }}} */
00259 
00260 char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_data **pphar TSRMLS_DC) /* {{{ */
00261 {
00262 #if PHP_VERSION_ID >= 50300
00263        char *path, *fname, *arch, *entry, *ret, *test;
00264        int arch_len, entry_len, fname_len, ret_len;
00265        phar_archive_data *phar;
00266 
00267        if (pphar) {
00268               *pphar = NULL;
00269        } else {
00270               pphar = &phar;
00271        }
00272 
00273        if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) {
00274               return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
00275        }
00276 
00277        fname = zend_get_executed_filename(TSRMLS_C);
00278        fname_len = strlen(fname);
00279 
00280        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))) {
00281               arch = estrndup(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len));
00282               arch_len = PHAR_G(last_phar_name_len);
00283               phar = PHAR_G(last_phar);
00284               goto splitted;
00285        }
00286 
00287        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)) {
00288               return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
00289        }
00290 
00291        efree(entry);
00292 
00293        if (*filename == '.') {
00294               int try_len;
00295 
00296               if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
00297                      efree(arch);
00298                      return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
00299               }
00300 splitted:
00301               if (pphar) {
00302                      *pphar = phar;
00303               }
00304 
00305               try_len = filename_len;
00306               test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC);
00307 
00308               if (*test == '/') {
00309                      if (zend_hash_exists(&(phar->manifest), test + 1, try_len - 1)) {
00310                             spprintf(&ret, 0, "phar://%s%s", arch, test);
00311                             efree(arch);
00312                             efree(test);
00313                             return ret;
00314                      }
00315               } else {
00316                      if (zend_hash_exists(&(phar->manifest), test, try_len)) {
00317                             spprintf(&ret, 0, "phar://%s/%s", arch, test);
00318                             efree(arch);
00319                             efree(test);
00320                             return ret;
00321                      }
00322               }
00323               efree(test);
00324        }
00325 
00326        spprintf(&path, MAXPATHLEN, "phar://%s/%s%c%s", arch, PHAR_G(cwd), DEFAULT_DIR_SEPARATOR, PG(include_path));
00327        efree(arch);
00328        ret = php_resolve_path(filename, filename_len, path TSRMLS_CC);
00329        efree(path);
00330 
00331        if (ret && strlen(ret) > 8 && !strncmp(ret, "phar://", 7)) {
00332               ret_len = strlen(ret);
00333               /* found phar:// */
00334 
00335               if (SUCCESS != phar_split_fname(ret, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
00336                      return ret;
00337               }
00338 
00339               zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
00340 
00341               if (!pphar && PHAR_G(manifest_cached)) {
00342                      zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar);
00343               }
00344 
00345               efree(arch);
00346               efree(entry);
00347        }
00348 
00349        return ret;
00350 #else /* PHP 5.2 */
00351        char resolved_path[MAXPATHLEN];
00352        char trypath[MAXPATHLEN];
00353        char *ptr, *end, *path = PG(include_path);
00354        php_stream_wrapper *wrapper;
00355        const char *p;
00356        int n = 0;
00357        char *fname, *arch, *entry, *ret, *test;
00358        int arch_len, entry_len;
00359        phar_archive_data *phar = NULL;
00360 
00361        if (!filename) {
00362               return NULL;
00363        }
00364 
00365        if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) {
00366               goto doit;
00367        }
00368 
00369        fname = zend_get_executed_filename(TSRMLS_C);
00370 
00371        if (SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
00372               goto doit;
00373        }
00374 
00375        efree(entry);
00376 
00377        if (*filename == '.') {
00378               int try_len;
00379 
00380               if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
00381                      efree(arch);
00382                      goto doit;
00383               }
00384 
00385               try_len = filename_len;
00386               test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC);
00387 
00388               if (*test == '/') {
00389                      if (zend_hash_exists(&(phar->manifest), test + 1, try_len - 1)) {
00390                             spprintf(&ret, 0, "phar://%s%s", arch, test);
00391                             efree(arch);
00392                             efree(test);
00393                             return ret;
00394                      }
00395               } else {
00396                      if (zend_hash_exists(&(phar->manifest), test, try_len)) {
00397                             spprintf(&ret, 0, "phar://%s/%s", arch, test);
00398                             efree(arch);
00399                             efree(test);
00400                             return ret;
00401                      }
00402               }
00403 
00404               efree(test);
00405        }
00406 
00407        efree(arch);
00408 doit:
00409        if (*filename == '.' || IS_ABSOLUTE_PATH(filename, filename_len) || !path || !*path) {
00410               if (tsrm_realpath(filename, resolved_path TSRMLS_CC)) {
00411                      return estrdup(resolved_path);
00412               } else {
00413                      return NULL;
00414               }
00415        }
00416 
00417        /* test for stream wrappers and return */
00418        for (p = filename; p - filename < filename_len && (isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'); ++p, ++n);
00419 
00420        if (n < filename_len - 3 && (*p == ':') && (!strncmp("//", p+1, 2) || ( filename_len > 4 && !memcmp("data", filename, 4)))) {
00421               /* found stream wrapper, this is an absolute path until stream wrappers implement realpath */
00422               return estrndup(filename, filename_len);
00423        }
00424 
00425        ptr = (char *) path;
00426        while (ptr && *ptr) {
00427               int len, is_stream_wrapper = 0, maybe_stream = 1;
00428 
00429               end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
00430 #ifndef PHP_WIN32
00431               /* search for stream wrapper */
00432               if (end - ptr  <= 1) {
00433                      maybe_stream = 0;
00434                      goto not_stream;
00435               }
00436 
00437               for (p = ptr, n = 0; p < end && (isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'); ++p, ++n);
00438 
00439               if (n == end - ptr && *p && !strncmp("//", p+1, 2)) {
00440                      is_stream_wrapper = 1;
00441                      /* seek to real end of include_path portion */
00442                      end = strchr(end + 1, DEFAULT_DIR_SEPARATOR);
00443               } else {
00444                      maybe_stream = 0;
00445               }
00446 not_stream:
00447 #endif
00448               if (end) {
00449                      if ((end-ptr) + 1 + filename_len + 1 >= MAXPATHLEN) {
00450                             ptr = end + 1;
00451                             continue;
00452                      }
00453 
00454                      memcpy(trypath, ptr, end-ptr);
00455                      len = end-ptr;
00456                      trypath[end-ptr] = '/';
00457                      memcpy(trypath+(end-ptr)+1, filename, filename_len+1);
00458                      ptr = end+1;
00459               } else {
00460                      len = strlen(ptr);
00461 
00462                      if (len + 1 + filename_len + 1 >= MAXPATHLEN) {
00463                             break;
00464                      }
00465 
00466                      memcpy(trypath, ptr, len);
00467                      trypath[len] = '/';
00468                      memcpy(trypath+len+1, filename, filename_len+1);
00469                      ptr = NULL;
00470               }
00471 
00472               if (!is_stream_wrapper && maybe_stream) {
00473                      /* search for stream wrapper */
00474                      for (p = trypath, n = 0; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; ++p, ++n);
00475               }
00476 
00477               if (is_stream_wrapper || (n < len - 3 && (*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) || !memcmp("data", trypath, 4)))) {
00478                      char *actual;
00479 
00480                      wrapper = php_stream_locate_url_wrapper(trypath, &actual, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
00481                      if (wrapper == &php_plain_files_wrapper) {
00482                             strlcpy(trypath, actual, sizeof(trypath));
00483                      } else if (!wrapper) {
00484                             /* if wrapper is NULL, there was a mal-formed include_path stream wrapper, so skip this ptr */
00485                             continue;
00486                      } else {
00487                             if (wrapper->wops->url_stat) {
00488                                    php_stream_statbuf ssb;
00489 
00490                                    if (SUCCESS == wrapper->wops->url_stat(wrapper, trypath, 0, &ssb, NULL TSRMLS_CC)) {
00491                                           if (wrapper == &php_stream_phar_wrapper) {
00492                                                  char *arch, *entry;
00493                                                  int arch_len, entry_len, ret_len;
00494 
00495                                                  ret_len = strlen(trypath);
00496                                                  /* found phar:// */
00497 
00498                                                  if (SUCCESS != phar_split_fname(trypath, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
00499                                                         return estrndup(trypath, ret_len);
00500                                                  }
00501 
00502                                                  zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
00503 
00504                                                  if (!pphar && PHAR_G(manifest_cached)) {
00505                                                         zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar);
00506                                                  }
00507 
00508                                                  efree(arch);
00509                                                  efree(entry);
00510 
00511                                                  return estrndup(trypath, ret_len);
00512                                           }
00513                                           return estrdup(trypath);
00514                                    }
00515                             }
00516                             continue;
00517                      }
00518               }
00519 
00520               if (tsrm_realpath(trypath, resolved_path TSRMLS_CC)) {
00521                      return estrdup(resolved_path);
00522               }
00523        } /* end provided path */
00524 
00525        /* check in calling scripts' current working directory as a fall back case */
00526        if (zend_is_executing(TSRMLS_C)) {
00527               char *exec_fname = zend_get_executed_filename(TSRMLS_C);
00528               int exec_fname_length = strlen(exec_fname);
00529               const char *p;
00530               int n = 0;
00531 
00532               while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
00533               if (exec_fname && exec_fname[0] != '[' && 
00534                      exec_fname_length > 0 && 
00535                      exec_fname_length + 1 + filename_len + 1 < MAXPATHLEN) {
00536                      memcpy(trypath, exec_fname, exec_fname_length + 1);
00537                      memcpy(trypath+exec_fname_length + 1, filename, filename_len+1);
00538 
00539                      /* search for stream wrapper */
00540                      for (p = trypath; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; ++p, ++n);
00541 
00542                      if (n < exec_fname_length - 3 && (*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) || !memcmp("data", trypath, 4))) {
00543                             char *actual;
00544 
00545                             wrapper = php_stream_locate_url_wrapper(trypath, &actual, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
00546 
00547                             if (wrapper == &php_plain_files_wrapper) {
00548                                    /* this should never technically happen, but we'll leave it here for completeness */
00549                                    strlcpy(trypath, actual, sizeof(trypath));
00550                             } else if (!wrapper) {
00551                                    /* if wrapper is NULL, there was a malformed include_path stream wrapper
00552                                       this also should be impossible */
00553                                    return NULL;
00554                             } else {
00555                                    return estrdup(trypath);
00556                             }
00557                      }
00558 
00559                      if (tsrm_realpath(trypath, resolved_path TSRMLS_CC)) {
00560                             return estrdup(resolved_path);
00561                      }
00562               }
00563        }
00564 
00565        return NULL;
00566 #endif /* PHP 5.2 */
00567 }
00568 /* }}} */
00569 
00578 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) /* {{{ */
00579 {
00580        phar_archive_data *phar;
00581        phar_entry_info *entry;
00582        int for_write  = mode[0] != 'r' || mode[1] == '+';
00583        int for_append = mode[0] == 'a';
00584        int for_create = mode[0] != 'r';
00585        int for_trunc  = mode[0] == 'w';
00586 
00587        if (!ret) {
00588               return FAILURE;
00589        }
00590 
00591        *ret = NULL;
00592 
00593        if (error) {
00594               *error = NULL;
00595        }
00596 
00597        if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
00598               return FAILURE;
00599        }
00600 
00601        if (for_write && PHAR_G(readonly) && !phar->is_data) {
00602               if (error) {
00603                      spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, disabled by ini setting", path, fname);
00604               }
00605               return FAILURE;
00606        }
00607 
00608        if (!path_len) {
00609               if (error) {
00610                      spprintf(error, 4096, "phar error: file \"\" in phar \"%s\" cannot be empty", fname);
00611               }
00612               return FAILURE;
00613        }
00614 really_get_entry:
00615        if (allow_dir) {
00616               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) {
00617                      if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
00618                             return SUCCESS;
00619                      }
00620                      return FAILURE;
00621               }
00622        } else {
00623               if ((entry = phar_get_entry_info(phar, path, path_len, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error, security TSRMLS_CC)) == NULL) {
00624                      if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
00625                             return SUCCESS;
00626                      }
00627                      return FAILURE;
00628               }
00629        }
00630 
00631        if (for_write && phar->is_persistent) {
00632               if (FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
00633                      if (error) {
00634                             spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, could not make cached phar writeable", path, fname);
00635                      }
00636                      return FAILURE;
00637               } else {
00638                      goto really_get_entry;
00639               }
00640        }
00641 
00642        if (entry->is_modified && !for_write) {
00643               if (error) {
00644                      spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for reading, writable file pointers are open", path, fname);
00645               }
00646               return FAILURE;
00647        }
00648 
00649        if (entry->fp_refcount && for_write) {
00650               if (error) {
00651                      spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, readable file pointers are open", path, fname);
00652               }
00653               return FAILURE;
00654        }
00655 
00656        if (entry->is_deleted) {
00657               if (!for_create) {
00658                      return FAILURE;
00659               }
00660               entry->is_deleted = 0;
00661        }
00662 
00663        if (entry->is_dir) {
00664               *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
00665               (*ret)->position = 0;
00666               (*ret)->fp = NULL;
00667               (*ret)->phar = phar;
00668               (*ret)->for_write = for_write;
00669               (*ret)->internal_file = entry;
00670               (*ret)->is_zip = entry->is_zip;
00671               (*ret)->is_tar = entry->is_tar;
00672 
00673               if (!phar->is_persistent) {
00674                      ++(entry->phar->refcount);
00675                      ++(entry->fp_refcount);
00676               }
00677 
00678               return SUCCESS;
00679        }
00680 
00681        if (entry->fp_type == PHAR_MOD) {
00682               if (for_trunc) {
00683                      if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) {
00684                             return FAILURE;
00685                      }
00686               } else if (for_append) {
00687                      phar_seek_efp(entry, 0, SEEK_END, 0, 0 TSRMLS_CC);
00688               }
00689        } else {
00690               if (for_write) {
00691                      if (entry->link) {
00692                             efree(entry->link);
00693                             entry->link = NULL;
00694                             entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
00695                      }
00696 
00697                      if (for_trunc) {
00698                             if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) {
00699                                    return FAILURE;
00700                             }
00701                      } else {
00702                             if (FAILURE == phar_separate_entry_fp(entry, error TSRMLS_CC)) {
00703                                    return FAILURE;
00704                             }
00705                      }
00706               } else {
00707                      if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
00708                             return FAILURE;
00709                      }
00710               }
00711        }
00712 
00713        *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
00714        (*ret)->position = 0;
00715        (*ret)->phar = phar;
00716        (*ret)->for_write = for_write;
00717        (*ret)->internal_file = entry;
00718        (*ret)->is_zip = entry->is_zip;
00719        (*ret)->is_tar = entry->is_tar;
00720        (*ret)->fp = phar_get_efp(entry, 1 TSRMLS_CC);
00721        if (entry->link) {
00722               (*ret)->zero = phar_get_fp_offset(phar_get_link_source(entry TSRMLS_CC) TSRMLS_CC);
00723        } else {
00724               (*ret)->zero = phar_get_fp_offset(entry TSRMLS_CC);
00725        }
00726 
00727        if (!phar->is_persistent) {
00728               ++(entry->fp_refcount);
00729               ++(entry->phar->refcount);
00730        }
00731 
00732        return SUCCESS;
00733 }
00734 /* }}} */
00735 
00739 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) /* {{{ */
00740 {
00741        phar_archive_data *phar;
00742        phar_entry_info *entry, etemp;
00743        phar_entry_data *ret;
00744        const char *pcr_error;
00745        char is_dir;
00746 
00747 #ifdef PHP_WIN32
00748        phar_unixify_path_separators(path, path_len);
00749 #endif
00750 
00751        is_dir = (path_len && path[path_len - 1] == '/') ? 1 : 0;
00752 
00753        if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
00754               return NULL;
00755        }
00756 
00757        if (FAILURE == phar_get_entry_data(&ret, fname, fname_len, path, path_len, mode, allow_dir, error, security TSRMLS_CC)) {
00758               return NULL;
00759        } else if (ret) {
00760               return ret;
00761        }
00762 
00763        if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
00764               if (error) {
00765                      spprintf(error, 0, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
00766               }
00767               return NULL;
00768        }
00769 
00770        if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
00771               if (error) {
00772                      spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be created, could not make cached phar writeable", path, fname);
00773               }
00774               return NULL;
00775        }
00776 
00777        /* create a new phar data holder */
00778        ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
00779 
00780        /* create an entry, this is a new file */
00781        memset(&etemp, 0, sizeof(phar_entry_info));
00782        etemp.filename_len = path_len;
00783        etemp.fp_type = PHAR_MOD;
00784        etemp.fp = php_stream_fopen_tmpfile();
00785 
00786        if (!etemp.fp) {
00787               if (error) {
00788                      spprintf(error, 0, "phar error: unable to create temporary file");
00789               }
00790               efree(ret);
00791               return NULL;
00792        }
00793 
00794        etemp.fp_refcount = 1;
00795 
00796        if (allow_dir == 2) {
00797               etemp.is_dir = 1;
00798               etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_DIR;
00799        } else {
00800               etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_FILE;
00801        }
00802        if (is_dir) {
00803               etemp.filename_len--; /* strip trailing / */
00804               path_len--;
00805        }
00806 
00807        phar_add_virtual_dirs(phar, path, path_len TSRMLS_CC);
00808        etemp.is_modified = 1;
00809        etemp.timestamp = time(0);
00810        etemp.is_crc_checked = 1;
00811        etemp.phar = phar;
00812        etemp.filename = estrndup(path, path_len);
00813        etemp.is_zip = phar->is_zip;
00814 
00815        if (phar->is_tar) {
00816               etemp.is_tar = phar->is_tar;
00817               etemp.tar_type = etemp.is_dir ? TAR_DIR : TAR_FILE;
00818        }
00819 
00820        if (FAILURE == zend_hash_add(&phar->manifest, etemp.filename, path_len, (void*)&etemp, sizeof(phar_entry_info), (void **) &entry)) {
00821               php_stream_close(etemp.fp);
00822               if (error) {
00823                      spprintf(error, 0, "phar error: unable to add new entry \"%s\" to phar \"%s\"", etemp.filename, phar->fname);
00824               }
00825               efree(ret);
00826               efree(etemp.filename);
00827               return NULL;
00828        }
00829 
00830        if (!entry) {
00831               php_stream_close(etemp.fp);
00832               efree(etemp.filename);
00833               efree(ret);
00834               return NULL;
00835        }
00836 
00837        ++(phar->refcount);
00838        ret->phar = phar;
00839        ret->fp = entry->fp;
00840        ret->position = ret->zero = 0;
00841        ret->for_write = 1;
00842        ret->is_zip = entry->is_zip;
00843        ret->is_tar = entry->is_tar;
00844        ret->internal_file = entry;
00845 
00846        return ret;
00847 }
00848 /* }}} */
00849 
00850 /* initialize a phar_archive_data's read-only fp for existing phar data */
00851 int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC) /* {{{ */
00852 {
00853        if (phar_get_pharfp(phar TSRMLS_CC)) {
00854               return SUCCESS;
00855        }
00856 #if PHP_API_VERSION < 20100412
00857        if (PG(safe_mode) && (!php_checkuid(phar->fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
00858               return FAILURE;
00859        }
00860 #endif
00861 
00862        if (php_check_open_basedir(phar->fname TSRMLS_CC)) {
00863               return FAILURE;
00864        }
00865 
00866        phar_set_pharfp(phar, php_stream_open_wrapper(phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL) TSRMLS_CC);
00867 
00868        if (!phar_get_pharfp(phar TSRMLS_CC)) {
00869               return FAILURE;
00870        }
00871 
00872        return SUCCESS;
00873 }
00874 /* }}} */
00875 
00876 /* copy file data from an existing to a new phar_entry_info that is not in the manifest */
00877 int phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error TSRMLS_DC) /* {{{ */
00878 {
00879        phar_entry_info *link;
00880 
00881        if (FAILURE == phar_open_entry_fp(source, error, 1 TSRMLS_CC)) {
00882               return FAILURE;
00883        }
00884 
00885        if (dest->link) {
00886               efree(dest->link);
00887               dest->link = NULL;
00888               dest->tar_type = (dest->is_tar ? TAR_FILE : '\0');
00889        }
00890 
00891        dest->fp_type = PHAR_MOD;
00892        dest->offset = 0;
00893        dest->is_modified = 1;
00894        dest->fp = php_stream_fopen_tmpfile();
00895        phar_seek_efp(source, 0, SEEK_SET, 0, 1 TSRMLS_CC);
00896        link = phar_get_link_source(source TSRMLS_CC);
00897 
00898        if (!link) {
00899               link = source;
00900        }
00901 
00902        if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), dest->fp, link->uncompressed_filesize, NULL)) {
00903               php_stream_close(dest->fp);
00904               dest->fp_type = PHAR_FP;
00905               if (error) {
00906                      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);
00907               }
00908               return FAILURE;
00909        }
00910 
00911        return SUCCESS;
00912 }
00913 /* }}} */
00914 
00915 /* open and decompress a compressed phar entry
00916  */
00917 int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TSRMLS_DC) /* {{{ */
00918 {
00919        php_stream_filter *filter;
00920        phar_archive_data *phar = entry->phar;
00921        char *filtername;
00922        off_t loc;
00923        php_stream *ufp;
00924        phar_entry_data dummy;
00925 
00926        if (follow_links && entry->link) {
00927               phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
00928               if (link_entry && link_entry != entry) {
00929                      return phar_open_entry_fp(link_entry, error, 1 TSRMLS_CC);
00930               }
00931        }
00932 
00933        if (entry->is_modified) {
00934               return SUCCESS;
00935        }
00936 
00937        if (entry->fp_type == PHAR_TMP) {
00938               if (!entry->fp) {
00939                      entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
00940               }
00941               return SUCCESS;
00942        }
00943 
00944        if (entry->fp_type != PHAR_FP) {
00945               /* either newly created or already modified */
00946               return SUCCESS;
00947        }
00948 
00949        if (!phar_get_pharfp(phar TSRMLS_CC)) {
00950               if (FAILURE == phar_open_archive_fp(phar TSRMLS_CC)) {
00951                      spprintf(error, 4096, "phar error: Cannot open phar archive \"%s\" for reading", phar->fname);
00952                      return FAILURE;
00953               }
00954        }
00955 
00956        if ((entry->old_flags && !(entry->old_flags & PHAR_ENT_COMPRESSION_MASK)) || !(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
00957               dummy.internal_file = entry;
00958               dummy.phar = phar;
00959               dummy.zero = entry->offset;
00960               dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
00961               if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
00962                      return FAILURE;
00963               }
00964               return SUCCESS;
00965        }
00966 
00967        if (!phar_get_entrypufp(entry TSRMLS_CC)) {
00968               phar_set_entrypufp(entry, php_stream_fopen_tmpfile() TSRMLS_CC);
00969               if (!phar_get_entrypufp(entry TSRMLS_CC)) {
00970                      spprintf(error, 4096, "phar error: Cannot open temporary file for decompressing phar archive \"%s\" file \"%s\"", phar->fname, entry->filename);
00971                      return FAILURE;
00972               }
00973        }
00974 
00975        dummy.internal_file = entry;
00976        dummy.phar = phar;
00977        dummy.zero = entry->offset;
00978        dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
00979        if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
00980               return FAILURE;
00981        }
00982 
00983        ufp = phar_get_entrypufp(entry TSRMLS_CC);
00984 
00985        if ((filtername = phar_decompress_filter(entry, 0)) != NULL) {
00986               filter = php_stream_filter_create(filtername, NULL, 0 TSRMLS_CC);
00987        } else {
00988               filter = NULL;
00989        }
00990 
00991        if (!filter) {
00992               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);
00993               return FAILURE;
00994        }
00995 
00996        /* now we can safely use proper decompression */
00997        /* save the new offset location within ufp */
00998        php_stream_seek(ufp, 0, SEEK_END);
00999        loc = php_stream_tell(ufp);
01000        php_stream_filter_append(&ufp->writefilters, filter);
01001        php_stream_seek(phar_get_entrypfp(entry TSRMLS_CC), phar_get_fp_offset(entry TSRMLS_CC), SEEK_SET);
01002 
01003        if (entry->uncompressed_filesize) {
01004               if (SUCCESS != phar_stream_copy_to_stream(phar_get_entrypfp(entry TSRMLS_CC), ufp, entry->compressed_filesize, NULL)) {
01005                      spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
01006                      php_stream_filter_remove(filter, 1 TSRMLS_CC);
01007                      return FAILURE;
01008               }
01009        }
01010 
01011        php_stream_filter_flush(filter, 1);
01012        php_stream_flush(ufp);
01013        php_stream_filter_remove(filter, 1 TSRMLS_CC);
01014 
01015        if (php_stream_tell(ufp) - loc != (off_t) entry->uncompressed_filesize) {
01016               spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
01017               return FAILURE;
01018        }
01019 
01020        entry->old_flags = entry->flags;
01021 
01022        /* this is now the new location of the file contents within this fp */
01023        phar_set_fp_type(entry, PHAR_UFP, loc TSRMLS_CC);
01024        dummy.zero = entry->offset;
01025        dummy.fp = ufp;
01026        if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 0 TSRMLS_CC)) {
01027               return FAILURE;
01028        }
01029        return SUCCESS;
01030 }
01031 /* }}} */
01032 
01033 #if defined(PHP_VERSION_ID) && PHP_VERSION_ID < 50202
01034 typedef struct {
01035        char        *data;
01036        size_t      fpos;
01037        size_t      fsize;
01038        size_t      smax;
01039        int         mode;
01040        php_stream  **owner_ptr;
01041 } php_stream_memory_data;
01042 #endif
01043 
01044 int phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
01045 {
01046        if (entry->fp_type == PHAR_MOD) {
01047               /* already newly created, truncate */
01048 #if PHP_VERSION_ID >= 50202
01049               php_stream_truncate_set_size(entry->fp, 0);
01050 #else
01051               if (php_stream_is(entry->fp, PHP_STREAM_IS_TEMP)) {
01052                      if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_MEMORY)) {
01053                             php_stream *inner = *(php_stream**)entry->fp->abstract;
01054                             php_stream_memory_data *memfp = (php_stream_memory_data*)inner->abstract;
01055                             memfp->fpos = 0;
01056                             memfp->fsize = 0;
01057                      } else if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_STDIO)) {
01058                             php_stream_truncate_set_size(*(php_stream**)entry->fp->abstract, 0);
01059                      } else {
01060                             if (error) {
01061                                    spprintf(error, 0, "phar error: file \"%s\" cannot be opened for writing, no truncate support", phar->fname);
01062                             }
01063                             return FAILURE;
01064                      }
01065               } else if (php_stream_is(entry->fp, PHP_STREAM_IS_STDIO)) {
01066                      php_stream_truncate_set_size(entry->fp, 0);
01067               } else {
01068                      if (error) {
01069                             spprintf(error, 0, "phar error: file \"%s\" cannot be opened for writing, no truncate support", phar->fname);
01070                      }
01071                      return FAILURE;
01072               }
01073 #endif
01074               entry->old_flags = entry->flags;
01075               entry->is_modified = 1;
01076               phar->is_modified = 1;
01077               /* reset file size */
01078               entry->uncompressed_filesize = 0;
01079               entry->compressed_filesize = 0;
01080               entry->crc32 = 0;
01081               entry->flags = PHAR_ENT_PERM_DEF_FILE;
01082               entry->fp_type = PHAR_MOD;
01083               entry->offset = 0;
01084               return SUCCESS;
01085        }
01086 
01087        if (error) {
01088               *error = NULL;
01089        }
01090 
01091        /* open a new temp file for writing */
01092        if (entry->link) {
01093               efree(entry->link);
01094               entry->link = NULL;
01095               entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
01096        }
01097 
01098        entry->fp = php_stream_fopen_tmpfile();
01099 
01100        if (!entry->fp) {
01101               if (error) {
01102                      spprintf(error, 0, "phar error: unable to create temporary file");
01103               }
01104               return FAILURE;
01105        }
01106 
01107        entry->old_flags = entry->flags;
01108        entry->is_modified = 1;
01109        phar->is_modified = 1;
01110        /* reset file size */
01111        entry->uncompressed_filesize = 0;
01112        entry->compressed_filesize = 0;
01113        entry->crc32 = 0;
01114        entry->flags = PHAR_ENT_PERM_DEF_FILE;
01115        entry->fp_type = PHAR_MOD;
01116        entry->offset = 0;
01117        return SUCCESS;
01118 }
01119 /* }}} */
01120 
01121 int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
01122 {
01123        php_stream *fp;
01124        phar_entry_info *link;
01125 
01126        if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
01127               return FAILURE;
01128        }
01129 
01130        if (entry->fp_type == PHAR_MOD) {
01131               return SUCCESS;
01132        }
01133 
01134        fp = php_stream_fopen_tmpfile();
01135        phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC);
01136        link = phar_get_link_source(entry TSRMLS_CC);
01137 
01138        if (!link) {
01139               link = entry;
01140        }
01141 
01142        if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), fp, link->uncompressed_filesize, NULL)) {
01143               if (error) {
01144                      spprintf(error, 4096, "phar error: cannot separate entry file \"%s\" contents in phar archive \"%s\" for write access", entry->filename, entry->phar->fname);
01145               }
01146               return FAILURE;
01147        }
01148 
01149        if (entry->link) {
01150               efree(entry->link);
01151               entry->link = NULL;
01152               entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
01153        }
01154 
01155        entry->offset = 0;
01156        entry->fp = fp;
01157        entry->fp_type = PHAR_MOD;
01158        entry->is_modified = 1;
01159        return SUCCESS;
01160 }
01161 /* }}} */
01162 
01166 phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
01167 {
01168        if (error) {
01169               *error = NULL;
01170        }
01171        /* seek to start of internal file and read it */
01172        if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
01173               return NULL;
01174        }
01175        if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) {
01176               spprintf(error, 4096, "phar error: cannot seek to start of file \"%s\" in phar \"%s\"", entry->filename, phar->fname);
01177               return NULL;
01178        }
01179        return entry;
01180 }
01181 /* }}} */
01182 
01183 int phar_free_alias(phar_archive_data *phar, char *alias, int alias_len TSRMLS_DC) /* {{{ */
01184 {
01185        if (phar->refcount || phar->is_persistent) {
01186               return FAILURE;
01187        }
01188 
01189        /* this archive has no open references, so emit an E_STRICT and remove it */
01190        if (zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
01191               return FAILURE;
01192        }
01193 
01194        /* invalidate phar cache */
01195        PHAR_G(last_phar) = NULL;
01196        PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
01197 
01198        return SUCCESS;
01199 }
01200 /* }}} */
01201 
01206 int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, char *alias, int alias_len, char **error TSRMLS_DC) /* {{{ */
01207 {
01208        phar_archive_data *fd, **fd_ptr;
01209        char *my_realpath, *save;
01210        int save_len;
01211        ulong fhash, ahash = 0;
01212 
01213        phar_request_initialize(TSRMLS_C);
01214 
01215        if (error) {
01216               *error = NULL;
01217        }
01218 
01219        *archive = NULL;
01220 
01221        if (PHAR_G(last_phar) && fname_len == PHAR_G(last_phar_name_len) && !memcmp(fname, PHAR_G(last_phar_name), fname_len)) {
01222               *archive = PHAR_G(last_phar);
01223               if (alias && alias_len) {
01224 
01225                      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))) {
01226                             if (error) {
01227                                    spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, PHAR_G(last_phar)->fname, fname);
01228                             }
01229                             *archive = NULL;
01230                             return FAILURE;
01231                      }
01232 
01233                      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)) {
01234                             zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len);
01235                      }
01236 
01237                      zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&(*archive), sizeof(phar_archive_data*), NULL);
01238                      PHAR_G(last_alias) = alias;
01239                      PHAR_G(last_alias_len) = alias_len;
01240               }
01241 
01242               return SUCCESS;
01243        }
01244 
01245        if (alias && alias_len && PHAR_G(last_phar) && alias_len == PHAR_G(last_alias_len) && !memcmp(alias, PHAR_G(last_alias), alias_len)) {
01246               fd = PHAR_G(last_phar);
01247               fd_ptr = &fd;
01248               goto alias_success;
01249        }
01250 
01251        if (alias && alias_len) {
01252               ahash = zend_inline_hash_func(alias, alias_len);
01253               if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void**)&fd_ptr)) {
01254 alias_success:
01255                      if (fname && (fname_len != (*fd_ptr)->fname_len || strncmp(fname, (*fd_ptr)->fname, fname_len))) {
01256                             if (error) {
01257                                    spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
01258                             }
01259                             if (SUCCESS == phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
01260                                    efree(*error);
01261                                    *error = NULL;
01262                             }
01263                             return FAILURE;
01264                      }
01265 
01266                      *archive = *fd_ptr;
01267                      fd = *fd_ptr;
01268                      PHAR_G(last_phar) = fd;
01269                      PHAR_G(last_phar_name) = fd->fname;
01270                      PHAR_G(last_phar_name_len) = fd->fname_len;
01271                      PHAR_G(last_alias) = alias;
01272                      PHAR_G(last_alias_len) = alias_len;
01273 
01274                      return SUCCESS;
01275               }
01276 
01277               if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, alias, alias_len, ahash, (void **)&fd_ptr)) {
01278                      goto alias_success;
01279               }
01280        }
01281 
01282        fhash = zend_inline_hash_func(fname, fname_len);
01283        my_realpath = NULL;
01284        save = fname;
01285        save_len = fname_len;
01286 
01287        if (fname && fname_len) {
01288               if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
01289                      *archive = *fd_ptr;
01290                      fd = *fd_ptr;
01291 
01292                      if (alias && alias_len) {
01293                             if (!fd->is_temporary_alias && (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len))) {
01294                                    if (error) {
01295                                           spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
01296                                    }
01297                                    return FAILURE;
01298                             }
01299 
01300                             if (fd->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len, (void**)&fd_ptr)) {
01301                                    zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len);
01302                             }
01303 
01304                             zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
01305                      }
01306 
01307                      PHAR_G(last_phar) = fd;
01308                      PHAR_G(last_phar_name) = fd->fname;
01309                      PHAR_G(last_phar_name_len) = fd->fname_len;
01310                      PHAR_G(last_alias) = fd->alias;
01311                      PHAR_G(last_alias_len) = fd->alias_len;
01312 
01313                      return SUCCESS;
01314               }
01315 
01316               if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
01317                      *archive = *fd_ptr;
01318                      fd = *fd_ptr;
01319 
01320                      /* this could be problematic - alias should never be different from manifest alias
01321                         for cached phars */
01322                      if (!fd->is_temporary_alias && alias && alias_len) {
01323                             if (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len)) {
01324                                    if (error) {
01325                                           spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
01326                                    }
01327                                    return FAILURE;
01328                             }
01329                      }
01330 
01331                      PHAR_G(last_phar) = fd;
01332                      PHAR_G(last_phar_name) = fd->fname;
01333                      PHAR_G(last_phar_name_len) = fd->fname_len;
01334                      PHAR_G(last_alias) = fd->alias;
01335                      PHAR_G(last_alias_len) = fd->alias_len;
01336 
01337                      return SUCCESS;
01338               }
01339 
01340               if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), save, save_len, fhash, (void**)&fd_ptr)) {
01341                      fd = *archive = *fd_ptr;
01342 
01343                      PHAR_G(last_phar) = fd;
01344                      PHAR_G(last_phar_name) = fd->fname;
01345                      PHAR_G(last_phar_name_len) = fd->fname_len;
01346                      PHAR_G(last_alias) = fd->alias;
01347                      PHAR_G(last_alias_len) = fd->alias_len;
01348 
01349                      return SUCCESS;
01350               }
01351 
01352               if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, save, save_len, fhash, (void**)&fd_ptr)) {
01353                      fd = *archive = *fd_ptr;
01354 
01355                      PHAR_G(last_phar) = fd;
01356                      PHAR_G(last_phar_name) = fd->fname;
01357                      PHAR_G(last_phar_name_len) = fd->fname_len;
01358                      PHAR_G(last_alias) = fd->alias;
01359                      PHAR_G(last_alias_len) = fd->alias_len;
01360 
01361                      return SUCCESS;
01362               }
01363 
01364               /* not found, try converting \ to / */
01365               my_realpath = expand_filepath(fname, my_realpath TSRMLS_CC);
01366 
01367               if (my_realpath) {
01368                      fname_len = strlen(my_realpath);
01369                      fname = my_realpath;
01370               } else {
01371                      return FAILURE;
01372               }
01373 #ifdef PHP_WIN32
01374               phar_unixify_path_separators(fname, fname_len);
01375 #endif
01376               fhash = zend_inline_hash_func(fname, fname_len);
01377 
01378               if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
01379 realpath_success:
01380                      *archive = *fd_ptr;
01381                      fd = *fd_ptr;
01382 
01383                      if (alias && alias_len) {
01384                             zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
01385                      }
01386 
01387                      efree(my_realpath);
01388 
01389                      PHAR_G(last_phar) = fd;
01390                      PHAR_G(last_phar_name) = fd->fname;
01391                      PHAR_G(last_phar_name_len) = fd->fname_len;
01392                      PHAR_G(last_alias) = fd->alias;
01393                      PHAR_G(last_alias_len) = fd->alias_len;
01394 
01395                      return SUCCESS;
01396               }
01397 
01398               if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
01399                      goto realpath_success;
01400               }
01401 
01402               efree(my_realpath);
01403        }
01404 
01405        return FAILURE;
01406 }
01407 /* }}} */
01408 
01412 char * phar_compress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
01413 {
01414        switch (entry->flags & PHAR_ENT_COMPRESSION_MASK) {
01415        case PHAR_ENT_COMPRESSED_GZ:
01416               return "zlib.deflate";
01417        case PHAR_ENT_COMPRESSED_BZ2:
01418               return "bzip2.compress";
01419        default:
01420               return return_unknown ? "unknown" : NULL;
01421        }
01422 }
01423 /* }}} */
01424 
01428 char * phar_decompress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
01429 {
01430        php_uint32 flags;
01431 
01432        if (entry->is_modified) {
01433               flags = entry->old_flags;
01434        } else {
01435               flags = entry->flags;
01436        }
01437 
01438        switch (flags & PHAR_ENT_COMPRESSION_MASK) {
01439               case PHAR_ENT_COMPRESSED_GZ:
01440                      return "zlib.inflate";
01441               case PHAR_ENT_COMPRESSED_BZ2:
01442                      return "bzip2.decompress";
01443               default:
01444                      return return_unknown ? "unknown" : NULL;
01445        }
01446 }
01447 /* }}} */
01448 
01452 phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len, char **error, int security TSRMLS_DC) /* {{{ */
01453 {
01454        return phar_get_entry_info_dir(phar, path, path_len, 0, error, security TSRMLS_CC);
01455 }
01456 /* }}} */
01462 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) /* {{{ */
01463 {
01464        const char *pcr_error;
01465        phar_entry_info *entry;
01466        int is_dir;
01467 
01468 #ifdef PHP_WIN32
01469        phar_unixify_path_separators(path, path_len);
01470 #endif
01471 
01472        is_dir = (path_len && (path[path_len - 1] == '/')) ? 1 : 0;
01473 
01474        if (error) {
01475               *error = NULL;
01476        }
01477 
01478        if (security && path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) {
01479               if (error) {
01480                      spprintf(error, 4096, "phar error: cannot directly access magic \".phar\" directory or files within it");
01481               }
01482               return NULL;
01483        }
01484 
01485        if (!path_len && !dir) {
01486               if (error) {
01487                      spprintf(error, 4096, "phar error: invalid path \"%s\" must not be empty", path);
01488               }
01489               return NULL;
01490        }
01491 
01492        if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
01493               if (error) {
01494                      spprintf(error, 4096, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
01495               }
01496               return NULL;
01497        }
01498 
01499        if (!phar->manifest.arBuckets) {
01500               return NULL;
01501        }
01502 
01503        if (is_dir) {
01504               if (!path_len || path_len == 1) {
01505                      return NULL;
01506               }
01507               path_len--;
01508        }
01509 
01510        if (SUCCESS == zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
01511               if (entry->is_deleted) {
01512                      /* entry is deleted, but has not been flushed to disk yet */
01513                      return NULL;
01514               }
01515               if (entry->is_dir && !dir) {
01516                      if (error) {
01517                             spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
01518                      }
01519                      return NULL;
01520               }
01521               if (!entry->is_dir && dir == 2) {
01522                      /* user requested a directory, we must return one */
01523                      if (error) {
01524                             spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
01525                      }
01526                      return NULL;
01527               }
01528               return entry;
01529        }
01530 
01531        if (dir) {
01532               if (zend_hash_exists(&phar->virtual_dirs, path, path_len)) {
01533                      /* a file or directory exists in a sub-directory of this path */
01534                      entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info));
01535                      /* this next line tells PharFileInfo->__destruct() to efree the filename */
01536                      entry->is_temp_dir = entry->is_dir = 1;
01537                      entry->filename = (char *) estrndup(path, path_len + 1);
01538                      entry->filename_len = path_len;
01539                      entry->phar = phar;
01540                      return entry;
01541               }
01542        }
01543 
01544        if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) {
01545               phar_zstr key;
01546               char *str_key;
01547               ulong unused;
01548               uint keylen;
01549 
01550               zend_hash_internal_pointer_reset(&phar->mounted_dirs);
01551               while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) {
01552                      if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, NULL)) {
01553                             break;
01554                      }
01555 
01556                      PHAR_STR(key, str_key);
01557 
01558                      if ((int)keylen >= path_len || strncmp(str_key, path, keylen)) {
01559                             PHAR_STR_FREE(str_key);
01560                             continue;
01561                      } else {
01562                             char *test;
01563                             int test_len;
01564                             php_stream_statbuf ssb;
01565 
01566                             if (SUCCESS != zend_hash_find(&phar->manifest, str_key, keylen, (void **) &entry)) {
01567                                    if (error) {
01568                                           spprintf(error, 4096, "phar internal error: mounted path \"%s\" could not be retrieved from manifest", str_key);
01569                                    }
01570                                    PHAR_STR_FREE(str_key);
01571                                    return NULL;
01572                             }
01573 
01574                             if (!entry->tmp || !entry->is_mounted) {
01575                                    if (error) {
01576                                           spprintf(error, 4096, "phar internal error: mounted path \"%s\" is not properly initialized as a mounted path", str_key);
01577                                    }
01578                                    PHAR_STR_FREE(str_key);
01579                                    return NULL;
01580                             }
01581                             PHAR_STR_FREE(str_key);
01582 
01583                             test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, path + keylen);
01584 
01585                             if (SUCCESS != php_stream_stat_path(test, &ssb)) {
01586                                    efree(test);
01587                                    return NULL;
01588                             }
01589 
01590                             if (ssb.sb.st_mode & S_IFDIR && !dir) {
01591                                    efree(test);
01592                                    if (error) {
01593                                           spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
01594                                    }
01595                                    return NULL;
01596                             }
01597 
01598                             if ((ssb.sb.st_mode & S_IFDIR) == 0 && dir) {
01599                                    efree(test);
01600                                    /* user requested a directory, we must return one */
01601                                    if (error) {
01602                                           spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
01603                                    }
01604                                    return NULL;
01605                             }
01606 
01607                             /* mount the file just in time */
01608                             if (SUCCESS != phar_mount_entry(phar, test, test_len, path, path_len TSRMLS_CC)) {
01609                                    efree(test);
01610                                    if (error) {
01611                                           spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be mounted", path, test);
01612                                    }
01613                                    return NULL;
01614                             }
01615 
01616                             efree(test);
01617 
01618                             if (SUCCESS != zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
01619                                    if (error) {
01620                                           spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be retrieved after being mounted", path, test);
01621                                    }
01622                                    return NULL;
01623                             }
01624                             return entry;
01625                      }
01626               }
01627        }
01628 
01629        return NULL;
01630 }
01631 /* }}} */
01632 
01633 static const char hexChars[] = "0123456789ABCDEF";
01634 
01635 static int phar_hex_str(const char *digest, size_t digest_len, char **signature TSRMLS_DC) /* {{{ */
01636 {
01637        int pos = -1;
01638        size_t len = 0;
01639 
01640        *signature = (char*)safe_pemalloc(digest_len, 2, 1, PHAR_G(persist));
01641 
01642        for (; len < digest_len; ++len) {
01643               (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] >> 4];
01644               (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] & 0x0F];
01645        }
01646        (*signature)[++pos] = '\0';
01647        return pos;
01648 }
01649 /* }}} */
01650 
01651 #ifndef PHAR_HAVE_OPENSSL
01652 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) /* {{{ */
01653 {
01654        zend_fcall_info fci;
01655        zend_fcall_info_cache fcc;
01656        zval *zdata, *zsig, *zkey, *retval_ptr, **zp[3], *openssl;
01657 
01658        MAKE_STD_ZVAL(zdata);
01659        MAKE_STD_ZVAL(openssl);
01660        ZVAL_STRINGL(openssl, is_sign ? "openssl_sign" : "openssl_verify", is_sign ? sizeof("openssl_sign")-1 : sizeof("openssl_verify")-1, 1);
01661        MAKE_STD_ZVAL(zsig);
01662        ZVAL_STRINGL(zsig, *signature, *signature_len, 1);
01663        MAKE_STD_ZVAL(zkey);
01664        ZVAL_STRINGL(zkey, key, key_len, 1);
01665        zp[0] = &zdata;
01666        zp[1] = &zsig;
01667        zp[2] = &zkey;
01668 
01669        php_stream_rewind(fp);
01670        Z_TYPE_P(zdata) = IS_STRING;
01671        Z_STRLEN_P(zdata) = end;
01672 
01673 #if PHP_MAJOR_VERSION > 5
01674        if (end != (off_t) php_stream_copy_to_mem(fp, (void **) &(Z_STRVAL_P(zdata)), (size_t) end, 0)) {
01675 #else
01676        if (end != (off_t) php_stream_copy_to_mem(fp, &(Z_STRVAL_P(zdata)), (size_t) end, 0)) {
01677 #endif
01678               zval_dtor(zdata);
01679               zval_dtor(zsig);
01680               zval_dtor(zkey);
01681               zval_dtor(openssl);
01682               efree(openssl);
01683               efree(zdata);
01684               efree(zkey);
01685               efree(zsig);
01686               return FAILURE;
01687        }
01688 
01689 #if PHP_VERSION_ID < 50300
01690        if (FAILURE == zend_fcall_info_init(openssl, &fci, &fcc TSRMLS_CC)) {
01691 #else
01692        if (FAILURE == zend_fcall_info_init(openssl, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) {
01693 #endif
01694               zval_dtor(zdata);
01695               zval_dtor(zsig);
01696               zval_dtor(zkey);
01697               zval_dtor(openssl);
01698               efree(openssl);
01699               efree(zdata);
01700               efree(zkey);
01701               efree(zsig);
01702               return FAILURE;
01703        }
01704 
01705        fci.param_count = 3;
01706        fci.params = zp;
01707 #if PHP_VERSION_ID < 50300
01708        ++(zdata->refcount);
01709        if (!is_sign) {
01710               ++(zsig->refcount);
01711        }
01712        ++(zkey->refcount);
01713 #else
01714        Z_ADDREF_P(zdata);
01715        if (is_sign) {
01716               Z_SET_ISREF_P(zsig);
01717        } else {
01718               Z_ADDREF_P(zsig);
01719        }
01720        Z_ADDREF_P(zkey);
01721 #endif
01722        fci.retval_ptr_ptr = &retval_ptr;
01723 
01724        if (FAILURE == zend_call_function(&fci, &fcc TSRMLS_CC)) {
01725               zval_dtor(zdata);
01726               zval_dtor(zsig);
01727               zval_dtor(zkey);
01728               zval_dtor(openssl);
01729               efree(openssl);
01730               efree(zdata);
01731               efree(zkey);
01732               efree(zsig);
01733               return FAILURE;
01734        }
01735 
01736        zval_dtor(openssl);
01737        efree(openssl);
01738 #if PHP_VERSION_ID < 50300
01739        --(zdata->refcount);
01740        if (!is_sign) {
01741               --(zsig->refcount);
01742        }
01743        --(zkey->refcount);
01744 #else
01745        Z_DELREF_P(zdata);
01746        if (is_sign) {
01747               Z_UNSET_ISREF_P(zsig);
01748        } else {
01749               Z_DELREF_P(zsig);
01750        }
01751        Z_DELREF_P(zkey);
01752 #endif
01753        zval_dtor(zdata);
01754        efree(zdata);
01755        zval_dtor(zkey);
01756        efree(zkey);
01757 
01758        switch (Z_TYPE_P(retval_ptr)) {
01759               default:
01760               case IS_LONG:
01761                      zval_dtor(zsig);
01762                      efree(zsig);
01763                      if (1 == Z_LVAL_P(retval_ptr)) {
01764                             efree(retval_ptr);
01765                             return SUCCESS;
01766                      }
01767                      efree(retval_ptr);
01768                      return FAILURE;
01769               case IS_BOOL:
01770                      efree(retval_ptr);
01771                      if (Z_BVAL_P(retval_ptr)) {
01772                             *signature = estrndup(Z_STRVAL_P(zsig), Z_STRLEN_P(zsig));
01773                             *signature_len = Z_STRLEN_P(zsig);
01774                             zval_dtor(zsig);
01775                             efree(zsig);
01776                             return SUCCESS;
01777                      }
01778                      zval_dtor(zsig);
01779                      efree(zsig);
01780                      return FAILURE;
01781        }
01782 }
01783 /* }}} */
01784 #endif /* #ifndef PHAR_HAVE_OPENSSL */
01785 
01786 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) /* {{{ */
01787 {
01788        int read_size, len;
01789        off_t read_len;
01790        unsigned char buf[1024];
01791 
01792        php_stream_rewind(fp);
01793 
01794        switch (sig_type) {
01795               case PHAR_SIG_OPENSSL: {
01796 #ifdef PHAR_HAVE_OPENSSL
01797                      BIO *in;
01798                      EVP_PKEY *key;
01799                      EVP_MD *mdtype = (EVP_MD *) EVP_sha1();
01800                      EVP_MD_CTX md_ctx;
01801 #else
01802                      int tempsig;
01803 #endif
01804                      php_uint32 pubkey_len;
01805                      char *pubkey = NULL, *pfile;
01806                      php_stream *pfp;
01807 #ifndef PHAR_HAVE_OPENSSL
01808                      if (!zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
01809                             if (error) {
01810                                    spprintf(error, 0, "openssl not loaded");
01811                             }
01812                             return FAILURE;
01813                      }
01814 #endif
01815                      /* use __FILE__ . '.pubkey' for public key file */
01816                      spprintf(&pfile, 0, "%s.pubkey", fname);
01817                      pfp = php_stream_open_wrapper(pfile, "rb", 0, NULL);
01818                      efree(pfile);
01819 
01820 #if PHP_MAJOR_VERSION > 5
01821                      if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, (void **) &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) {
01822 #else
01823                      if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) {
01824 #endif
01825                             if (pfp) {
01826                                    php_stream_close(pfp);
01827                             }
01828                             if (error) {
01829                                    spprintf(error, 0, "openssl public key could not be read");
01830                             }
01831                             return FAILURE;
01832                      }
01833 
01834                      php_stream_close(pfp);
01835 #ifndef PHAR_HAVE_OPENSSL
01836                      tempsig = sig_len;
01837 
01838                      if (FAILURE == phar_call_openssl_signverify(0, fp, end_of_phar, pubkey, pubkey_len, &sig, &tempsig TSRMLS_CC)) {
01839                             if (pubkey) {
01840                                    efree(pubkey);
01841                             }
01842 
01843                             if (error) {
01844                                    spprintf(error, 0, "openssl signature could not be verified");
01845                             }
01846 
01847                             return FAILURE;
01848                      }
01849 
01850                      if (pubkey) {
01851                             efree(pubkey);
01852                      }
01853 
01854                      sig_len = tempsig;
01855 #else
01856                      in = BIO_new_mem_buf(pubkey, pubkey_len);
01857 
01858                      if (NULL == in) {
01859                             efree(pubkey);
01860                             if (error) {
01861                                    spprintf(error, 0, "openssl signature could not be processed");
01862                             }
01863                             return FAILURE;
01864                      }
01865 
01866                      key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL);
01867                      BIO_free(in);
01868                      efree(pubkey);
01869 
01870                      if (NULL == key) {
01871                             if (error) {
01872                                    spprintf(error, 0, "openssl signature could not be processed");
01873                             }
01874                             return FAILURE;
01875                      }
01876 
01877                      EVP_VerifyInit(&md_ctx, mdtype);
01878                      read_len = end_of_phar;
01879 
01880                      if (read_len > sizeof(buf)) {
01881                             read_size = sizeof(buf);
01882                      } else {
01883                             read_size = (int)read_len;
01884                      }
01885 
01886                      php_stream_seek(fp, 0, SEEK_SET);
01887 
01888                      while (read_size && (len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
01889                             EVP_VerifyUpdate (&md_ctx, buf, len);
01890                             read_len -= (off_t)len;
01891 
01892                             if (read_len < read_size) {
01893                                    read_size = (int)read_len;
01894                             }
01895                      }
01896 
01897                      if (EVP_VerifyFinal(&md_ctx, (unsigned char *)sig, sig_len, key) != 1) {
01898                             /* 1: signature verified, 0: signature does not match, -1: failed signature operation */
01899                             EVP_MD_CTX_cleanup(&md_ctx);
01900 
01901                             if (error) {
01902                                    spprintf(error, 0, "broken openssl signature");
01903                             }
01904 
01905                             return FAILURE;
01906                      }
01907 
01908                      EVP_MD_CTX_cleanup(&md_ctx);
01909 #endif
01910 
01911                      *signature_len = phar_hex_str((const char*)sig, sig_len, signature TSRMLS_CC);
01912               }
01913               break;
01914 #ifdef PHAR_HASH_OK
01915               case PHAR_SIG_SHA512: {
01916                      unsigned char digest[64];
01917                      PHP_SHA512_CTX context;
01918 
01919                      PHP_SHA512Init(&context);
01920                      read_len = end_of_phar;
01921 
01922                      if (read_len > sizeof(buf)) {
01923                             read_size = sizeof(buf);
01924                      } else {
01925                             read_size = (int)read_len;
01926                      }
01927 
01928                      while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
01929                             PHP_SHA512Update(&context, buf, len);
01930                             read_len -= (off_t)len;
01931                             if (read_len < read_size) {
01932                                    read_size = (int)read_len;
01933                             }
01934                      }
01935 
01936                      PHP_SHA512Final(digest, &context);
01937 
01938                      if (memcmp(digest, sig, sizeof(digest))) {
01939                             if (error) {
01940                                    spprintf(error, 0, "broken signature");
01941                             }
01942                             return FAILURE;
01943                      }
01944 
01945                      *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
01946                      break;
01947               }
01948               case PHAR_SIG_SHA256: {
01949                      unsigned char digest[32];
01950                      PHP_SHA256_CTX context;
01951 
01952                      PHP_SHA256Init(&context);
01953                      read_len = end_of_phar;
01954 
01955                      if (read_len > sizeof(buf)) {
01956                             read_size = sizeof(buf);
01957                      } else {
01958                             read_size = (int)read_len;
01959                      }
01960 
01961                      while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
01962                             PHP_SHA256Update(&context, buf, len);
01963                             read_len -= (off_t)len;
01964                             if (read_len < read_size) {
01965                                    read_size = (int)read_len;
01966                             }
01967                      }
01968 
01969                      PHP_SHA256Final(digest, &context);
01970 
01971                      if (memcmp(digest, sig, sizeof(digest))) {
01972                             if (error) {
01973                                    spprintf(error, 0, "broken signature");
01974                             }
01975                             return FAILURE;
01976                      }
01977 
01978                      *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
01979                      break;
01980               }
01981 #else
01982               case PHAR_SIG_SHA512:
01983               case PHAR_SIG_SHA256:
01984                      if (error) {
01985                             spprintf(error, 0, "unsupported signature");
01986                      }
01987                      return FAILURE;
01988 #endif
01989               case PHAR_SIG_SHA1: {
01990                      unsigned char digest[20];
01991                      PHP_SHA1_CTX  context;
01992 
01993                      PHP_SHA1Init(&context);
01994                      read_len = end_of_phar;
01995 
01996                      if (read_len > sizeof(buf)) {
01997                             read_size = sizeof(buf);
01998                      } else {
01999                             read_size = (int)read_len;
02000                      }
02001 
02002                      while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
02003                             PHP_SHA1Update(&context, buf, len);
02004                             read_len -= (off_t)len;
02005                             if (read_len < read_size) {
02006                                    read_size = (int)read_len;
02007                             }
02008                      }
02009 
02010                      PHP_SHA1Final(digest, &context);
02011 
02012                      if (memcmp(digest, sig, sizeof(digest))) {
02013                             if (error) {
02014                                    spprintf(error, 0, "broken signature");
02015                             }
02016                             return FAILURE;
02017                      }
02018 
02019                      *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
02020                      break;
02021               }
02022               case PHAR_SIG_MD5: {
02023                      unsigned char digest[16];
02024                      PHP_MD5_CTX   context;
02025 
02026                      PHP_MD5Init(&context);
02027                      read_len = end_of_phar;
02028 
02029                      if (read_len > sizeof(buf)) {
02030                             read_size = sizeof(buf);
02031                      } else {
02032                             read_size = (int)read_len;
02033                      }
02034 
02035                      while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
02036                             PHP_MD5Update(&context, buf, len);
02037                             read_len -= (off_t)len;
02038                             if (read_len < read_size) {
02039                                    read_size = (int)read_len;
02040                             }
02041                      }
02042 
02043                      PHP_MD5Final(digest, &context);
02044 
02045                      if (memcmp(digest, sig, sizeof(digest))) {
02046                             if (error) {
02047                                    spprintf(error, 0, "broken signature");
02048                             }
02049                             return FAILURE;
02050                      }
02051 
02052                      *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
02053                      break;
02054               }
02055               default:
02056                      if (error) {
02057                             spprintf(error, 0, "broken or unsupported signature");
02058                      }
02059                      return FAILURE;
02060        }
02061        return SUCCESS;
02062 }
02063 /* }}} */
02064 
02065 int phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, int *signature_length, char **error TSRMLS_DC) /* {{{ */
02066 {
02067        unsigned char buf[1024];
02068        int sig_len;
02069 
02070        php_stream_rewind(fp);
02071 
02072        if (phar->signature) {
02073               efree(phar->signature);
02074               phar->signature = NULL;
02075        }
02076 
02077        switch(phar->sig_flags) {
02078 #ifdef PHAR_HASH_OK
02079               case PHAR_SIG_SHA512: {
02080                      unsigned char digest[64];
02081                      PHP_SHA512_CTX context;
02082 
02083                      PHP_SHA512Init(&context);
02084 
02085                      while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
02086                             PHP_SHA512Update(&context, buf, sig_len);
02087                      }
02088 
02089                      PHP_SHA512Final(digest, &context);
02090                      *signature = estrndup((char *) digest, 64);
02091                      *signature_length = 64;
02092                      break;
02093               }
02094               case PHAR_SIG_SHA256: {
02095                      unsigned char digest[32];
02096                      PHP_SHA256_CTX  context;
02097 
02098                      PHP_SHA256Init(&context);
02099 
02100                      while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
02101                             PHP_SHA256Update(&context, buf, sig_len);
02102                      }
02103 
02104                      PHP_SHA256Final(digest, &context);
02105                      *signature = estrndup((char *) digest, 32);
02106                      *signature_length = 32;
02107                      break;
02108               }
02109 #else
02110               case PHAR_SIG_SHA512:
02111               case PHAR_SIG_SHA256:
02112                      if (error) {
02113                             spprintf(error, 0, "unable to write to phar \"%s\" with requested hash type", phar->fname);
02114                      }
02115 
02116                      return FAILURE;
02117 #endif
02118               case PHAR_SIG_OPENSSL: {
02119                      int siglen;
02120                      unsigned char *sigbuf;
02121 #ifdef PHAR_HAVE_OPENSSL
02122                      BIO *in;
02123                      EVP_PKEY *key;
02124                      EVP_MD *mdtype = (EVP_MD *) EVP_sha1();
02125                      EVP_MD_CTX md_ctx;
02126 
02127                      in = BIO_new_mem_buf(PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len));
02128 
02129                      if (in == NULL) {
02130                             if (error) {
02131                                    spprintf(error, 0, "unable to write to phar \"%s\" with requested openssl signature", phar->fname);
02132                             }
02133                             return FAILURE;
02134                      }
02135 
02136                      key = PEM_read_bio_PrivateKey(in, NULL,NULL, "");
02137                      BIO_free(in);
02138 
02139                      if (!key) {
02140                             if (error) {
02141                                    spprintf(error, 0, "unable to process private key");
02142                             }
02143                             return FAILURE;
02144                      }
02145 
02146                      siglen = EVP_PKEY_size(key);
02147                      sigbuf = emalloc(siglen + 1);
02148                      EVP_SignInit(&md_ctx, mdtype);
02149 
02150                      while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
02151                             EVP_SignUpdate(&md_ctx, buf, sig_len);
02152                      }
02153 
02154                      if (!EVP_SignFinal (&md_ctx, sigbuf,(unsigned int *)&siglen, key)) {
02155                             efree(sigbuf);
02156                             if (error) {
02157                                    spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
02158                             }
02159                             return FAILURE;
02160                      }
02161 
02162                      sigbuf[siglen] = '\0';
02163                      EVP_MD_CTX_cleanup(&md_ctx);
02164 #else
02165                      sigbuf = NULL;
02166                      siglen = 0;
02167                      php_stream_seek(fp, 0, SEEK_END);
02168 
02169                      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)) {
02170                             if (error) {
02171                                    spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
02172                             }
02173                             return FAILURE;
02174                      }
02175 #endif
02176                      *signature = (char *) sigbuf;
02177                      *signature_length = siglen;
02178               }
02179               break;
02180               default:
02181                      phar->sig_flags = PHAR_SIG_SHA1;
02182               case PHAR_SIG_SHA1: {
02183                      unsigned char digest[20];
02184                      PHP_SHA1_CTX  context;
02185 
02186                      PHP_SHA1Init(&context);
02187 
02188                      while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
02189                             PHP_SHA1Update(&context, buf, sig_len);
02190                      }
02191 
02192                      PHP_SHA1Final(digest, &context);
02193                      *signature = estrndup((char *) digest, 20);
02194                      *signature_length = 20;
02195                      break;
02196               }
02197               case PHAR_SIG_MD5: {
02198                      unsigned char digest[16];
02199                      PHP_MD5_CTX   context;
02200 
02201                      PHP_MD5Init(&context);
02202 
02203                      while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
02204                             PHP_MD5Update(&context, buf, sig_len);
02205                      }
02206 
02207                      PHP_MD5Final(digest, &context);
02208                      *signature = estrndup((char *) digest, 16);
02209                      *signature_length = 16;
02210                      break;
02211               }
02212        }
02213 
02214        phar->sig_len = phar_hex_str((const char *)*signature, *signature_length, &phar->signature TSRMLS_CC);
02215        return SUCCESS;
02216 }
02217 /* }}} */
02218 
02219 void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC) /* {{{ */
02220 {
02221        char *s;
02222 
02223        while ((s = zend_memrchr(filename, '/', filename_len))) {
02224               filename_len = s - filename;
02225               if (FAILURE == zend_hash_add_empty_element(&phar->virtual_dirs, filename, filename_len)) {
02226                      break;
02227               }
02228        }
02229 }
02230 /* }}} */
02231 
02232 static int phar_update_cached_entry(void *data, void *argument) /* {{{ */
02233 {
02234        phar_entry_info *entry = (phar_entry_info *)data;
02235        TSRMLS_FETCH();
02236 
02237        entry->phar = (phar_archive_data *)argument;
02238 
02239        if (entry->link) {
02240               entry->link = estrdup(entry->link);
02241        }
02242 
02243        if (entry->tmp) {
02244               entry->tmp = estrdup(entry->tmp);
02245        }
02246 
02247        entry->metadata_str.c = 0;
02248        entry->filename = estrndup(entry->filename, entry->filename_len);
02249        entry->is_persistent = 0;
02250 
02251        if (entry->metadata) {
02252               if (entry->metadata_len) {
02253                      char *buf = estrndup((char *) entry->metadata, entry->metadata_len);
02254                      /* assume success, we would have failed before */
02255                      phar_parse_metadata((char **) &buf, &entry->metadata, entry->metadata_len TSRMLS_CC);
02256                      efree(buf);
02257               } else {
02258                      zval *t;
02259 
02260                      t = entry->metadata;
02261                      ALLOC_ZVAL(entry->metadata);
02262                      *entry->metadata = *t;
02263                      zval_copy_ctor(entry->metadata);
02264 #if PHP_VERSION_ID < 50300
02265                      entry->metadata->refcount = 1;
02266 #else
02267                      Z_SET_REFCOUNT_P(entry->metadata, 1);
02268 #endif
02269                      entry->metadata_str.c = NULL;
02270                      entry->metadata_str.len = 0;
02271               }
02272        }
02273        return ZEND_HASH_APPLY_KEEP;
02274 }
02275 /* }}} */
02276 
02277 static void phar_copy_cached_phar(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
02278 {
02279        phar_archive_data *phar;
02280        HashTable newmanifest;
02281        char *fname;
02282        phar_archive_object **objphar;
02283 
02284        phar = (phar_archive_data *) emalloc(sizeof(phar_archive_data));
02285        *phar = **pphar;
02286        phar->is_persistent = 0;
02287        fname = phar->fname;
02288        phar->fname = estrndup(phar->fname, phar->fname_len);
02289        phar->ext = phar->fname + (phar->ext - fname);
02290 
02291        if (phar->alias) {
02292               phar->alias = estrndup(phar->alias, phar->alias_len);
02293        }
02294 
02295        if (phar->signature) {
02296               phar->signature = estrdup(phar->signature);
02297        }
02298 
02299        if (phar->metadata) {
02300               /* assume success, we would have failed before */
02301               if (phar->metadata_len) {
02302                      char *buf = estrndup((char *) phar->metadata, phar->metadata_len);
02303                      phar_parse_metadata(&buf, &phar->metadata, phar->metadata_len TSRMLS_CC);
02304                      efree(buf);
02305               } else {
02306                      zval *t;
02307 
02308                      t = phar->metadata;
02309                      ALLOC_ZVAL(phar->metadata);
02310                      *phar->metadata = *t;
02311                      zval_copy_ctor(phar->metadata);
02312 #if PHP_VERSION_ID < 50300
02313                      phar->metadata->refcount = 1;
02314 #else
02315                      Z_SET_REFCOUNT_P(phar->metadata, 1);
02316 #endif
02317               }
02318        }
02319 
02320        zend_hash_init(&newmanifest, sizeof(phar_entry_info),
02321               zend_get_hash_value, destroy_phar_manifest_entry, 0);
02322        zend_hash_copy(&newmanifest, &(*pphar)->manifest, NULL, NULL, sizeof(phar_entry_info));
02323        zend_hash_apply_with_argument(&newmanifest, (apply_func_arg_t) phar_update_cached_entry, (void *)phar TSRMLS_CC);
02324        phar->manifest = newmanifest;
02325        zend_hash_init(&phar->mounted_dirs, sizeof(char *),
02326               zend_get_hash_value, NULL, 0);
02327        zend_hash_init(&phar->virtual_dirs, sizeof(char *),
02328               zend_get_hash_value, NULL, 0);
02329        zend_hash_copy(&phar->virtual_dirs, &(*pphar)->virtual_dirs, NULL, NULL, sizeof(void *));
02330        *pphar = phar;
02331 
02332        /* now, scan the list of persistent Phar objects referencing this phar and update the pointers */
02333        for (zend_hash_internal_pointer_reset(&PHAR_GLOBALS->phar_persist_map);
02334        SUCCESS == zend_hash_get_current_data(&PHAR_GLOBALS->phar_persist_map, (void **) &objphar);
02335        zend_hash_move_forward(&PHAR_GLOBALS->phar_persist_map)) {
02336               if (objphar[0]->arc.archive->fname_len == phar->fname_len && !memcmp(objphar[0]->arc.archive->fname, phar->fname, phar->fname_len)) {
02337                      objphar[0]->arc.archive = phar;
02338               }
02339        }
02340 }
02341 /* }}} */
02342 
02343 int phar_copy_on_write(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
02344 {
02345        phar_archive_data **newpphar, *newphar = NULL;
02346 
02347        if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len, (void *)&newphar, sizeof(phar_archive_data *), (void **)&newpphar)) {
02348               return FAILURE;
02349        }
02350 
02351        *newpphar = *pphar;
02352        phar_copy_cached_phar(newpphar TSRMLS_CC);
02353        /* invalidate phar cache */
02354        PHAR_G(last_phar) = NULL;
02355        PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
02356 
02357        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)) {
02358               zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len);
02359               return FAILURE;
02360        }
02361 
02362        *pphar = *newpphar;
02363        return SUCCESS;
02364 }
02365 /* }}} */
02366 
02367 /*
02368  * Local variables:
02369  * tab-width: 4
02370  * c-basic-offset: 4
02371  * End:
02372  * vim600: noet sw=4 ts=4 fdm=marker
02373  * vim<600: noet sw=4 ts=4
02374  */