PageRenderTime 54ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/ext/phar/util.c

http://github.com/infusion/PHP
C | 2357 lines | 1858 code | 357 blank | 142 comment | 622 complexity | f5639035addd6dd9c4dc8fddeab5eb25 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. +----------------------------------------------------------------------+
  3. | phar php single-file executable PHP extension |
  4. | utility functions |
  5. +----------------------------------------------------------------------+
  6. | Copyright (c) 2005-2011 The PHP Group |
  7. +----------------------------------------------------------------------+
  8. | This source file is subject to version 3.01 of the PHP license, |
  9. | that is bundled with this package in the file LICENSE, and is |
  10. | available through the world-wide-web at the following url: |
  11. | http://www.php.net/license/3_01.txt. |
  12. | If you did not receive a copy of the PHP license and are unable to |
  13. | obtain it through the world-wide-web, please send a note to |
  14. | license@php.net so we can mail you a copy immediately. |
  15. +----------------------------------------------------------------------+
  16. | Authors: Gregory Beaver <cellog@php.net> |
  17. | Marcus Boerger <helly@php.net> |
  18. +----------------------------------------------------------------------+
  19. */
  20. /* $Id: util.c 306941 2011-01-01 02:48:19Z felipe $ */
  21. #include "phar_internal.h"
  22. #ifdef PHAR_HASH_OK
  23. #include "ext/hash/php_hash_sha.h"
  24. #endif
  25. #ifdef PHAR_HAVE_OPENSSL
  26. /* OpenSSL includes */
  27. #include <openssl/evp.h>
  28. #include <openssl/x509.h>
  29. #include <openssl/x509v3.h>
  30. #include <openssl/crypto.h>
  31. #include <openssl/pem.h>
  32. #include <openssl/err.h>
  33. #include <openssl/conf.h>
  34. #include <openssl/rand.h>
  35. #include <openssl/ssl.h>
  36. #include <openssl/pkcs12.h>
  37. #else
  38. 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);
  39. #endif
  40. #if !defined(PHP_VERSION_ID) || PHP_VERSION_ID < 50300
  41. extern php_stream_wrapper php_stream_phar_wrapper;
  42. #endif
  43. /* for links to relative location, prepend cwd of the entry */
  44. static char *phar_get_link_location(phar_entry_info *entry TSRMLS_DC) /* {{{ */
  45. {
  46. char *p, *ret = NULL;
  47. if (!entry->link) {
  48. return NULL;
  49. }
  50. if (entry->link[0] == '/') {
  51. return estrdup(entry->link + 1);
  52. }
  53. p = strrchr(entry->filename, '/');
  54. if (p) {
  55. *p = '\0';
  56. spprintf(&ret, 0, "%s/%s", entry->filename, entry->link);
  57. return ret;
  58. }
  59. return entry->link;
  60. }
  61. /* }}} */
  62. phar_entry_info *phar_get_link_source(phar_entry_info *entry TSRMLS_DC) /* {{{ */
  63. {
  64. phar_entry_info *link_entry;
  65. char *link;
  66. if (!entry->link) {
  67. return entry;
  68. }
  69. link = phar_get_link_location(entry TSRMLS_CC);
  70. if (SUCCESS == zend_hash_find(&(entry->phar->manifest), entry->link, strlen(entry->link), (void **)&link_entry) ||
  71. SUCCESS == zend_hash_find(&(entry->phar->manifest), link, strlen(link), (void **)&link_entry)) {
  72. if (link != entry->link) {
  73. efree(link);
  74. }
  75. return phar_get_link_source(link_entry TSRMLS_CC);
  76. } else {
  77. if (link != entry->link) {
  78. efree(link);
  79. }
  80. return NULL;
  81. }
  82. }
  83. /* }}} */
  84. /* retrieve a phar_entry_info's current file pointer for reading contents */
  85. php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC) /* {{{ */
  86. {
  87. if (follow_links && entry->link) {
  88. phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
  89. if (link_entry && link_entry != entry) {
  90. return phar_get_efp(link_entry, 1 TSRMLS_CC);
  91. }
  92. }
  93. if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_FP) {
  94. if (!phar_get_entrypfp(entry TSRMLS_CC)) {
  95. /* re-open just in time for cases where our refcount reached 0 on the phar archive */
  96. phar_open_archive_fp(entry->phar TSRMLS_CC);
  97. }
  98. return phar_get_entrypfp(entry TSRMLS_CC);
  99. } else if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_UFP) {
  100. return phar_get_entrypufp(entry TSRMLS_CC);
  101. } else if (entry->fp_type == PHAR_MOD) {
  102. return entry->fp;
  103. } else {
  104. /* temporary manifest entry */
  105. if (!entry->fp) {
  106. entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
  107. }
  108. return entry->fp;
  109. }
  110. }
  111. /* }}} */
  112. int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC) /* {{{ */
  113. {
  114. php_stream *fp = phar_get_efp(entry, follow_links TSRMLS_CC);
  115. off_t temp, eoffset;
  116. if (!fp) {
  117. return -1;
  118. }
  119. if (follow_links) {
  120. phar_entry_info *t;
  121. t = phar_get_link_source(entry TSRMLS_CC);
  122. if (t) {
  123. entry = t;
  124. }
  125. }
  126. if (entry->is_dir) {
  127. return 0;
  128. }
  129. eoffset = phar_get_fp_offset(entry TSRMLS_CC);
  130. switch (whence) {
  131. case SEEK_END:
  132. temp = eoffset + entry->uncompressed_filesize + offset;
  133. break;
  134. case SEEK_CUR:
  135. temp = eoffset + position + offset;
  136. break;
  137. case SEEK_SET:
  138. temp = eoffset + offset;
  139. break;
  140. }
  141. if (temp > eoffset + (off_t) entry->uncompressed_filesize) {
  142. return -1;
  143. }
  144. if (temp < eoffset) {
  145. return -1;
  146. }
  147. return php_stream_seek(fp, temp, SEEK_SET);
  148. }
  149. /* }}} */
  150. /* mount an absolute path or uri to a path internal to the phar archive */
  151. int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len, char *path, int path_len TSRMLS_DC) /* {{{ */
  152. {
  153. phar_entry_info entry = {0};
  154. php_stream_statbuf ssb;
  155. int is_phar;
  156. const char *err;
  157. if (phar_path_check(&path, &path_len, &err) > pcr_is_ok) {
  158. return FAILURE;
  159. }
  160. if (path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) {
  161. /* no creating magic phar files by mounting them */
  162. return FAILURE;
  163. }
  164. is_phar = (filename_len > 7 && !memcmp(filename, "phar://", 7));
  165. entry.phar = phar;
  166. entry.filename = estrndup(path, path_len);
  167. #ifdef PHP_WIN32
  168. phar_unixify_path_separators(entry.filename, path_len);
  169. #endif
  170. entry.filename_len = path_len;
  171. if (is_phar) {
  172. entry.tmp = estrndup(filename, filename_len);
  173. } else {
  174. entry.tmp = expand_filepath(filename, NULL TSRMLS_CC);
  175. if (!entry.tmp) {
  176. entry.tmp = estrndup(filename, filename_len);
  177. }
  178. }
  179. filename_len = strlen(entry.tmp);
  180. filename = entry.tmp;
  181. /* only check openbasedir for files, not for phar streams */
  182. if (!is_phar && php_check_open_basedir(filename TSRMLS_CC)) {
  183. efree(entry.tmp);
  184. efree(entry.filename);
  185. return FAILURE;
  186. }
  187. entry.is_mounted = 1;
  188. entry.is_crc_checked = 1;
  189. entry.fp_type = PHAR_TMP;
  190. if (SUCCESS != php_stream_stat_path(filename, &ssb)) {
  191. efree(entry.tmp);
  192. efree(entry.filename);
  193. return FAILURE;
  194. }
  195. if (ssb.sb.st_mode & S_IFDIR) {
  196. entry.is_dir = 1;
  197. if (SUCCESS != zend_hash_add(&phar->mounted_dirs, entry.filename, path_len, (void *)&(entry.filename), sizeof(char *), NULL)) {
  198. /* directory already mounted */
  199. efree(entry.tmp);
  200. efree(entry.filename);
  201. return FAILURE;
  202. }
  203. } else {
  204. entry.is_dir = 0;
  205. entry.uncompressed_filesize = entry.compressed_filesize = ssb.sb.st_size;
  206. }
  207. entry.flags = ssb.sb.st_mode;
  208. if (SUCCESS == zend_hash_add(&phar->manifest, entry.filename, path_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
  209. return SUCCESS;
  210. }
  211. efree(entry.tmp);
  212. efree(entry.filename);
  213. return FAILURE;
  214. }
  215. /* }}} */
  216. char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_data **pphar TSRMLS_DC) /* {{{ */
  217. {
  218. #if PHP_VERSION_ID >= 50300
  219. char *path, *fname, *arch, *entry, *ret, *test;
  220. int arch_len, entry_len, fname_len, ret_len;
  221. phar_archive_data *phar;
  222. if (pphar) {
  223. *pphar = NULL;
  224. } else {
  225. pphar = &phar;
  226. }
  227. if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) {
  228. return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
  229. }
  230. fname = zend_get_executed_filename(TSRMLS_C);
  231. fname_len = strlen(fname);
  232. 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))) {
  233. arch = estrndup(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len));
  234. arch_len = PHAR_G(last_phar_name_len);
  235. phar = PHAR_G(last_phar);
  236. goto splitted;
  237. }
  238. 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)) {
  239. return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
  240. }
  241. efree(entry);
  242. if (*filename == '.') {
  243. int try_len;
  244. if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
  245. efree(arch);
  246. return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
  247. }
  248. splitted:
  249. if (pphar) {
  250. *pphar = phar;
  251. }
  252. try_len = filename_len;
  253. test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC);
  254. if (*test == '/') {
  255. if (zend_hash_exists(&(phar->manifest), test + 1, try_len - 1)) {
  256. spprintf(&ret, 0, "phar://%s%s", arch, test);
  257. efree(arch);
  258. efree(test);
  259. return ret;
  260. }
  261. } else {
  262. if (zend_hash_exists(&(phar->manifest), test, try_len)) {
  263. spprintf(&ret, 0, "phar://%s/%s", arch, test);
  264. efree(arch);
  265. efree(test);
  266. return ret;
  267. }
  268. }
  269. efree(test);
  270. }
  271. spprintf(&path, MAXPATHLEN, "phar://%s/%s%c%s", arch, PHAR_G(cwd), DEFAULT_DIR_SEPARATOR, PG(include_path));
  272. efree(arch);
  273. ret = php_resolve_path(filename, filename_len, path TSRMLS_CC);
  274. efree(path);
  275. if (ret && strlen(ret) > 8 && !strncmp(ret, "phar://", 7)) {
  276. ret_len = strlen(ret);
  277. /* found phar:// */
  278. if (SUCCESS != phar_split_fname(ret, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
  279. return ret;
  280. }
  281. zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
  282. if (!pphar && PHAR_G(manifest_cached)) {
  283. zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar);
  284. }
  285. efree(arch);
  286. efree(entry);
  287. }
  288. return ret;
  289. #else /* PHP 5.2 */
  290. char resolved_path[MAXPATHLEN];
  291. char trypath[MAXPATHLEN];
  292. char *ptr, *end, *path = PG(include_path);
  293. php_stream_wrapper *wrapper;
  294. const char *p;
  295. int n = 0;
  296. char *fname, *arch, *entry, *ret, *test;
  297. int arch_len, entry_len;
  298. phar_archive_data *phar = NULL;
  299. if (!filename) {
  300. return NULL;
  301. }
  302. if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) {
  303. goto doit;
  304. }
  305. fname = zend_get_executed_filename(TSRMLS_C);
  306. if (SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
  307. goto doit;
  308. }
  309. efree(entry);
  310. if (*filename == '.') {
  311. int try_len;
  312. if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
  313. efree(arch);
  314. goto doit;
  315. }
  316. try_len = filename_len;
  317. test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC);
  318. if (*test == '/') {
  319. if (zend_hash_exists(&(phar->manifest), test + 1, try_len - 1)) {
  320. spprintf(&ret, 0, "phar://%s%s", arch, test);
  321. efree(arch);
  322. efree(test);
  323. return ret;
  324. }
  325. } else {
  326. if (zend_hash_exists(&(phar->manifest), test, try_len)) {
  327. spprintf(&ret, 0, "phar://%s/%s", arch, test);
  328. efree(arch);
  329. efree(test);
  330. return ret;
  331. }
  332. }
  333. efree(test);
  334. }
  335. efree(arch);
  336. doit:
  337. if (*filename == '.' || IS_ABSOLUTE_PATH(filename, filename_len) || !path || !*path) {
  338. if (tsrm_realpath(filename, resolved_path TSRMLS_CC)) {
  339. return estrdup(resolved_path);
  340. } else {
  341. return NULL;
  342. }
  343. }
  344. /* test for stream wrappers and return */
  345. for (p = filename; p - filename < filename_len && (isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'); ++p, ++n);
  346. if (n < filename_len - 3 && (*p == ':') && (!strncmp("//", p+1, 2) || ( filename_len > 4 && !memcmp("data", filename, 4)))) {
  347. /* found stream wrapper, this is an absolute path until stream wrappers implement realpath */
  348. return estrndup(filename, filename_len);
  349. }
  350. ptr = (char *) path;
  351. while (ptr && *ptr) {
  352. int len, is_stream_wrapper = 0, maybe_stream = 1;
  353. end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
  354. #ifndef PHP_WIN32
  355. /* search for stream wrapper */
  356. if (end - ptr <= 1) {
  357. maybe_stream = 0;
  358. goto not_stream;
  359. }
  360. for (p = ptr, n = 0; p < end && (isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'); ++p, ++n);
  361. if (n == end - ptr && *p && !strncmp("//", p+1, 2)) {
  362. is_stream_wrapper = 1;
  363. /* seek to real end of include_path portion */
  364. end = strchr(end + 1, DEFAULT_DIR_SEPARATOR);
  365. } else {
  366. maybe_stream = 0;
  367. }
  368. not_stream:
  369. #endif
  370. if (end) {
  371. if ((end-ptr) + 1 + filename_len + 1 >= MAXPATHLEN) {
  372. ptr = end + 1;
  373. continue;
  374. }
  375. memcpy(trypath, ptr, end-ptr);
  376. len = end-ptr;
  377. trypath[end-ptr] = '/';
  378. memcpy(trypath+(end-ptr)+1, filename, filename_len+1);
  379. ptr = end+1;
  380. } else {
  381. len = strlen(ptr);
  382. if (len + 1 + filename_len + 1 >= MAXPATHLEN) {
  383. break;
  384. }
  385. memcpy(trypath, ptr, len);
  386. trypath[len] = '/';
  387. memcpy(trypath+len+1, filename, filename_len+1);
  388. ptr = NULL;
  389. }
  390. if (!is_stream_wrapper && maybe_stream) {
  391. /* search for stream wrapper */
  392. for (p = trypath, n = 0; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; ++p, ++n);
  393. }
  394. if (is_stream_wrapper || (n < len - 3 && (*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) || !memcmp("data", trypath, 4)))) {
  395. char *actual;
  396. wrapper = php_stream_locate_url_wrapper(trypath, &actual, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
  397. if (wrapper == &php_plain_files_wrapper) {
  398. strlcpy(trypath, actual, sizeof(trypath));
  399. } else if (!wrapper) {
  400. /* if wrapper is NULL, there was a mal-formed include_path stream wrapper, so skip this ptr */
  401. continue;
  402. } else {
  403. if (wrapper->wops->url_stat) {
  404. php_stream_statbuf ssb;
  405. if (SUCCESS == wrapper->wops->url_stat(wrapper, trypath, 0, &ssb, NULL TSRMLS_CC)) {
  406. if (wrapper == &php_stream_phar_wrapper) {
  407. char *arch, *entry;
  408. int arch_len, entry_len, ret_len;
  409. ret_len = strlen(trypath);
  410. /* found phar:// */
  411. if (SUCCESS != phar_split_fname(trypath, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
  412. return estrndup(trypath, ret_len);
  413. }
  414. zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
  415. if (!pphar && PHAR_G(manifest_cached)) {
  416. zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar);
  417. }
  418. efree(arch);
  419. efree(entry);
  420. return estrndup(trypath, ret_len);
  421. }
  422. return estrdup(trypath);
  423. }
  424. }
  425. continue;
  426. }
  427. }
  428. if (tsrm_realpath(trypath, resolved_path TSRMLS_CC)) {
  429. return estrdup(resolved_path);
  430. }
  431. } /* end provided path */
  432. /* check in calling scripts' current working directory as a fall back case */
  433. if (zend_is_executing(TSRMLS_C)) {
  434. char *exec_fname = zend_get_executed_filename(TSRMLS_C);
  435. int exec_fname_length = strlen(exec_fname);
  436. const char *p;
  437. int n = 0;
  438. while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
  439. if (exec_fname && exec_fname[0] != '[' &&
  440. exec_fname_length > 0 &&
  441. exec_fname_length + 1 + filename_len + 1 < MAXPATHLEN) {
  442. memcpy(trypath, exec_fname, exec_fname_length + 1);
  443. memcpy(trypath+exec_fname_length + 1, filename, filename_len+1);
  444. /* search for stream wrapper */
  445. for (p = trypath; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; ++p, ++n);
  446. if (n < exec_fname_length - 3 && (*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) || !memcmp("data", trypath, 4))) {
  447. char *actual;
  448. wrapper = php_stream_locate_url_wrapper(trypath, &actual, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
  449. if (wrapper == &php_plain_files_wrapper) {
  450. /* this should never technically happen, but we'll leave it here for completeness */
  451. strlcpy(trypath, actual, sizeof(trypath));
  452. } else if (!wrapper) {
  453. /* if wrapper is NULL, there was a malformed include_path stream wrapper
  454. this also should be impossible */
  455. return NULL;
  456. } else {
  457. return estrdup(trypath);
  458. }
  459. }
  460. if (tsrm_realpath(trypath, resolved_path TSRMLS_CC)) {
  461. return estrdup(resolved_path);
  462. }
  463. }
  464. }
  465. return NULL;
  466. #endif /* PHP 5.2 */
  467. }
  468. /* }}} */
  469. /**
  470. * Retrieve a copy of the file information on a single file within a phar, or null.
  471. * This also transfers the open file pointer, if any, to the entry.
  472. *
  473. * If the file does not already exist, this will fail. Pre-existing files can be
  474. * appended, truncated, or read. For read, if the entry is marked unmodified, it is
  475. * assumed that the file pointer, if present, is opened for reading
  476. */
  477. 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) /* {{{ */
  478. {
  479. phar_archive_data *phar;
  480. phar_entry_info *entry;
  481. int for_write = mode[0] != 'r' || mode[1] == '+';
  482. int for_append = mode[0] == 'a';
  483. int for_create = mode[0] != 'r';
  484. int for_trunc = mode[0] == 'w';
  485. if (!ret) {
  486. return FAILURE;
  487. }
  488. *ret = NULL;
  489. if (error) {
  490. *error = NULL;
  491. }
  492. if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
  493. return FAILURE;
  494. }
  495. if (for_write && PHAR_G(readonly) && !phar->is_data) {
  496. if (error) {
  497. spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, disabled by ini setting", path, fname);
  498. }
  499. return FAILURE;
  500. }
  501. if (!path_len) {
  502. if (error) {
  503. spprintf(error, 4096, "phar error: file \"\" in phar \"%s\" cannot be empty", fname);
  504. }
  505. return FAILURE;
  506. }
  507. really_get_entry:
  508. if (allow_dir) {
  509. 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) {
  510. if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
  511. return SUCCESS;
  512. }
  513. return FAILURE;
  514. }
  515. } else {
  516. if ((entry = phar_get_entry_info(phar, path, path_len, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error, security TSRMLS_CC)) == NULL) {
  517. if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
  518. return SUCCESS;
  519. }
  520. return FAILURE;
  521. }
  522. }
  523. if (for_write && phar->is_persistent) {
  524. if (FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
  525. if (error) {
  526. spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, could not make cached phar writeable", path, fname);
  527. }
  528. return FAILURE;
  529. } else {
  530. goto really_get_entry;
  531. }
  532. }
  533. if (entry->is_modified && !for_write) {
  534. if (error) {
  535. spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for reading, writable file pointers are open", path, fname);
  536. }
  537. return FAILURE;
  538. }
  539. if (entry->fp_refcount && for_write) {
  540. if (error) {
  541. spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, readable file pointers are open", path, fname);
  542. }
  543. return FAILURE;
  544. }
  545. if (entry->is_deleted) {
  546. if (!for_create) {
  547. return FAILURE;
  548. }
  549. entry->is_deleted = 0;
  550. }
  551. if (entry->is_dir) {
  552. *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
  553. (*ret)->position = 0;
  554. (*ret)->fp = NULL;
  555. (*ret)->phar = phar;
  556. (*ret)->for_write = for_write;
  557. (*ret)->internal_file = entry;
  558. (*ret)->is_zip = entry->is_zip;
  559. (*ret)->is_tar = entry->is_tar;
  560. if (!phar->is_persistent) {
  561. ++(entry->phar->refcount);
  562. ++(entry->fp_refcount);
  563. }
  564. return SUCCESS;
  565. }
  566. if (entry->fp_type == PHAR_MOD) {
  567. if (for_trunc) {
  568. if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) {
  569. return FAILURE;
  570. }
  571. } else if (for_append) {
  572. phar_seek_efp(entry, 0, SEEK_END, 0, 0 TSRMLS_CC);
  573. }
  574. } else {
  575. if (for_write) {
  576. if (entry->link) {
  577. efree(entry->link);
  578. entry->link = NULL;
  579. entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
  580. }
  581. if (for_trunc) {
  582. if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) {
  583. return FAILURE;
  584. }
  585. } else {
  586. if (FAILURE == phar_separate_entry_fp(entry, error TSRMLS_CC)) {
  587. return FAILURE;
  588. }
  589. }
  590. } else {
  591. if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
  592. return FAILURE;
  593. }
  594. }
  595. }
  596. *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
  597. (*ret)->position = 0;
  598. (*ret)->phar = phar;
  599. (*ret)->for_write = for_write;
  600. (*ret)->internal_file = entry;
  601. (*ret)->is_zip = entry->is_zip;
  602. (*ret)->is_tar = entry->is_tar;
  603. (*ret)->fp = phar_get_efp(entry, 1 TSRMLS_CC);
  604. if (entry->link) {
  605. (*ret)->zero = phar_get_fp_offset(phar_get_link_source(entry TSRMLS_CC) TSRMLS_CC);
  606. } else {
  607. (*ret)->zero = phar_get_fp_offset(entry TSRMLS_CC);
  608. }
  609. if (!phar->is_persistent) {
  610. ++(entry->fp_refcount);
  611. ++(entry->phar->refcount);
  612. }
  613. return SUCCESS;
  614. }
  615. /* }}} */
  616. /**
  617. * Create a new dummy file slot within a writeable phar for a newly created file
  618. */
  619. 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) /* {{{ */
  620. {
  621. phar_archive_data *phar;
  622. phar_entry_info *entry, etemp;
  623. phar_entry_data *ret;
  624. const char *pcr_error;
  625. char is_dir;
  626. #ifdef PHP_WIN32
  627. phar_unixify_path_separators(path, path_len);
  628. #endif
  629. is_dir = (path_len && path[path_len - 1] == '/') ? 1 : 0;
  630. if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
  631. return NULL;
  632. }
  633. if (FAILURE == phar_get_entry_data(&ret, fname, fname_len, path, path_len, mode, allow_dir, error, security TSRMLS_CC)) {
  634. return NULL;
  635. } else if (ret) {
  636. return ret;
  637. }
  638. if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
  639. if (error) {
  640. spprintf(error, 0, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
  641. }
  642. return NULL;
  643. }
  644. if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
  645. if (error) {
  646. spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be created, could not make cached phar writeable", path, fname);
  647. }
  648. return NULL;
  649. }
  650. /* create a new phar data holder */
  651. ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
  652. /* create an entry, this is a new file */
  653. memset(&etemp, 0, sizeof(phar_entry_info));
  654. etemp.filename_len = path_len;
  655. etemp.fp_type = PHAR_MOD;
  656. etemp.fp = php_stream_fopen_tmpfile();
  657. if (!etemp.fp) {
  658. if (error) {
  659. spprintf(error, 0, "phar error: unable to create temporary file");
  660. }
  661. efree(ret);
  662. return NULL;
  663. }
  664. etemp.fp_refcount = 1;
  665. if (allow_dir == 2) {
  666. etemp.is_dir = 1;
  667. etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_DIR;
  668. } else {
  669. etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_FILE;
  670. }
  671. if (is_dir) {
  672. etemp.filename_len--; /* strip trailing / */
  673. path_len--;
  674. }
  675. phar_add_virtual_dirs(phar, path, path_len TSRMLS_CC);
  676. etemp.is_modified = 1;
  677. etemp.timestamp = sapi_get_request_time(TSRMLS_C);
  678. etemp.is_crc_checked = 1;
  679. etemp.phar = phar;
  680. etemp.filename = estrndup(path, path_len);
  681. etemp.is_zip = phar->is_zip;
  682. if (phar->is_tar) {
  683. etemp.is_tar = phar->is_tar;
  684. etemp.tar_type = etemp.is_dir ? TAR_DIR : TAR_FILE;
  685. }
  686. if (FAILURE == zend_hash_add(&phar->manifest, etemp.filename, path_len, (void*)&etemp, sizeof(phar_entry_info), (void **) &entry)) {
  687. php_stream_close(etemp.fp);
  688. if (error) {
  689. spprintf(error, 0, "phar error: unable to add new entry \"%s\" to phar \"%s\"", etemp.filename, phar->fname);
  690. }
  691. efree(ret);
  692. efree(etemp.filename);
  693. return NULL;
  694. }
  695. if (!entry) {
  696. php_stream_close(etemp.fp);
  697. efree(etemp.filename);
  698. efree(ret);
  699. return NULL;
  700. }
  701. ++(phar->refcount);
  702. ret->phar = phar;
  703. ret->fp = entry->fp;
  704. ret->position = ret->zero = 0;
  705. ret->for_write = 1;
  706. ret->is_zip = entry->is_zip;
  707. ret->is_tar = entry->is_tar;
  708. ret->internal_file = entry;
  709. return ret;
  710. }
  711. /* }}} */
  712. /* initialize a phar_archive_data's read-only fp for existing phar data */
  713. int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC) /* {{{ */
  714. {
  715. if (phar_get_pharfp(phar TSRMLS_CC)) {
  716. return SUCCESS;
  717. }
  718. if (php_check_open_basedir(phar->fname TSRMLS_CC)) {
  719. return FAILURE;
  720. }
  721. phar_set_pharfp(phar, php_stream_open_wrapper(phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL) TSRMLS_CC);
  722. if (!phar_get_pharfp(phar TSRMLS_CC)) {
  723. return FAILURE;
  724. }
  725. return SUCCESS;
  726. }
  727. /* }}} */
  728. /* copy file data from an existing to a new phar_entry_info that is not in the manifest */
  729. int phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error TSRMLS_DC) /* {{{ */
  730. {
  731. phar_entry_info *link;
  732. if (FAILURE == phar_open_entry_fp(source, error, 1 TSRMLS_CC)) {
  733. return FAILURE;
  734. }
  735. if (dest->link) {
  736. efree(dest->link);
  737. dest->link = NULL;
  738. dest->tar_type = (dest->is_tar ? TAR_FILE : '\0');
  739. }
  740. dest->fp_type = PHAR_MOD;
  741. dest->offset = 0;
  742. dest->is_modified = 1;
  743. dest->fp = php_stream_fopen_tmpfile();
  744. phar_seek_efp(source, 0, SEEK_SET, 0, 1 TSRMLS_CC);
  745. link = phar_get_link_source(source TSRMLS_CC);
  746. if (!link) {
  747. link = source;
  748. }
  749. if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), dest->fp, link->uncompressed_filesize, NULL)) {
  750. php_stream_close(dest->fp);
  751. dest->fp_type = PHAR_FP;
  752. if (error) {
  753. 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);
  754. }
  755. return FAILURE;
  756. }
  757. return SUCCESS;
  758. }
  759. /* }}} */
  760. /* open and decompress a compressed phar entry
  761. */
  762. int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TSRMLS_DC) /* {{{ */
  763. {
  764. php_stream_filter *filter;
  765. phar_archive_data *phar = entry->phar;
  766. char *filtername;
  767. off_t loc;
  768. php_stream *ufp;
  769. phar_entry_data dummy;
  770. if (follow_links && entry->link) {
  771. phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
  772. if (link_entry && link_entry != entry) {
  773. return phar_open_entry_fp(link_entry, error, 1 TSRMLS_CC);
  774. }
  775. }
  776. if (entry->is_modified) {
  777. return SUCCESS;
  778. }
  779. if (entry->fp_type == PHAR_TMP) {
  780. if (!entry->fp) {
  781. entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
  782. }
  783. return SUCCESS;
  784. }
  785. if (entry->fp_type != PHAR_FP) {
  786. /* either newly created or already modified */
  787. return SUCCESS;
  788. }
  789. if (!phar_get_pharfp(phar TSRMLS_CC)) {
  790. if (FAILURE == phar_open_archive_fp(phar TSRMLS_CC)) {
  791. spprintf(error, 4096, "phar error: Cannot open phar archive \"%s\" for reading", phar->fname);
  792. return FAILURE;
  793. }
  794. }
  795. if ((entry->old_flags && !(entry->old_flags & PHAR_ENT_COMPRESSION_MASK)) || !(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
  796. dummy.internal_file = entry;
  797. dummy.phar = phar;
  798. dummy.zero = entry->offset;
  799. dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
  800. if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
  801. return FAILURE;
  802. }
  803. return SUCCESS;
  804. }
  805. if (!phar_get_entrypufp(entry TSRMLS_CC)) {
  806. phar_set_entrypufp(entry, php_stream_fopen_tmpfile() TSRMLS_CC);
  807. if (!phar_get_entrypufp(entry TSRMLS_CC)) {
  808. spprintf(error, 4096, "phar error: Cannot open temporary file for decompressing phar archive \"%s\" file \"%s\"", phar->fname, entry->filename);
  809. return FAILURE;
  810. }
  811. }
  812. dummy.internal_file = entry;
  813. dummy.phar = phar;
  814. dummy.zero = entry->offset;
  815. dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
  816. if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
  817. return FAILURE;
  818. }
  819. ufp = phar_get_entrypufp(entry TSRMLS_CC);
  820. if ((filtername = phar_decompress_filter(entry, 0)) != NULL) {
  821. filter = php_stream_filter_create(filtername, NULL, 0 TSRMLS_CC);
  822. } else {
  823. filter = NULL;
  824. }
  825. if (!filter) {
  826. 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);
  827. return FAILURE;
  828. }
  829. /* now we can safely use proper decompression */
  830. /* save the new offset location within ufp */
  831. php_stream_seek(ufp, 0, SEEK_END);
  832. loc = php_stream_tell(ufp);
  833. php_stream_filter_append(&ufp->writefilters, filter);
  834. php_stream_seek(phar_get_entrypfp(entry TSRMLS_CC), phar_get_fp_offset(entry TSRMLS_CC), SEEK_SET);
  835. if (SUCCESS != phar_stream_copy_to_stream(phar_get_entrypfp(entry TSRMLS_CC), ufp, entry->compressed_filesize, NULL)) {
  836. spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
  837. php_stream_filter_remove(filter, 1 TSRMLS_CC);
  838. return FAILURE;
  839. }
  840. php_stream_filter_flush(filter, 1);
  841. php_stream_flush(ufp);
  842. php_stream_filter_remove(filter, 1 TSRMLS_CC);
  843. if (php_stream_tell(ufp) - loc != (off_t) entry->uncompressed_filesize) {
  844. spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
  845. return FAILURE;
  846. }
  847. entry->old_flags = entry->flags;
  848. /* this is now the new location of the file contents within this fp */
  849. phar_set_fp_type(entry, PHAR_UFP, loc TSRMLS_CC);
  850. dummy.zero = entry->offset;
  851. dummy.fp = ufp;
  852. if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 0 TSRMLS_CC)) {
  853. return FAILURE;
  854. }
  855. return SUCCESS;
  856. }
  857. /* }}} */
  858. #if defined(PHP_VERSION_ID) && PHP_VERSION_ID < 50202
  859. typedef struct {
  860. char *data;
  861. size_t fpos;
  862. size_t fsize;
  863. size_t smax;
  864. int mode;
  865. php_stream **owner_ptr;
  866. } php_stream_memory_data;
  867. #endif
  868. int phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
  869. {
  870. if (entry->fp_type == PHAR_MOD) {
  871. /* already newly created, truncate */
  872. #if PHP_VERSION_ID >= 50202
  873. php_stream_truncate_set_size(entry->fp, 0);
  874. #else
  875. if (php_stream_is(entry->fp, PHP_STREAM_IS_TEMP)) {
  876. if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_MEMORY)) {
  877. php_stream *inner = *(php_stream**)entry->fp->abstract;
  878. php_stream_memory_data *memfp = (php_stream_memory_data*)inner->abstract;
  879. memfp->fpos = 0;
  880. memfp->fsize = 0;
  881. } else if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_STDIO)) {
  882. php_stream_truncate_set_size(*(php_stream**)entry->fp->abstract, 0);
  883. } else {
  884. if (error) {
  885. spprintf(error, 0, "phar error: file \"%s\" cannot be opened for writing, no truncate support", phar->fname);
  886. }
  887. return FAILURE;
  888. }
  889. } else if (php_stream_is(entry->fp, PHP_STREAM_IS_STDIO)) {
  890. php_stream_truncate_set_size(entry->fp, 0);
  891. } else {
  892. if (error) {
  893. spprintf(error, 0, "phar error: file \"%s\" cannot be opened for writing, no truncate support", phar->fname);
  894. }
  895. return FAILURE;
  896. }
  897. #endif
  898. entry->old_flags = entry->flags;
  899. entry->is_modified = 1;
  900. phar->is_modified = 1;
  901. /* reset file size */
  902. entry->uncompressed_filesize = 0;
  903. entry->compressed_filesize = 0;
  904. entry->crc32 = 0;
  905. entry->flags = PHAR_ENT_PERM_DEF_FILE;
  906. entry->fp_type = PHAR_MOD;
  907. entry->offset = 0;
  908. return SUCCESS;
  909. }
  910. if (error) {
  911. *error = NULL;
  912. }
  913. /* open a new temp file for writing */
  914. if (entry->link) {
  915. efree(entry->link);
  916. entry->link = NULL;
  917. entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
  918. }
  919. entry->fp = php_stream_fopen_tmpfile();
  920. if (!entry->fp) {
  921. if (error) {
  922. spprintf(error, 0, "phar error: unable to create temporary file");
  923. }
  924. return FAILURE;
  925. }
  926. entry->old_flags = entry->flags;
  927. entry->is_modified = 1;
  928. phar->is_modified = 1;
  929. /* reset file size */
  930. entry->uncompressed_filesize = 0;
  931. entry->compressed_filesize = 0;
  932. entry->crc32 = 0;
  933. entry->flags = PHAR_ENT_PERM_DEF_FILE;
  934. entry->fp_type = PHAR_MOD;
  935. entry->offset = 0;
  936. return SUCCESS;
  937. }
  938. /* }}} */
  939. int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
  940. {
  941. php_stream *fp;
  942. phar_entry_info *link;
  943. if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
  944. return FAILURE;
  945. }
  946. if (entry->fp_type == PHAR_MOD) {
  947. return SUCCESS;
  948. }
  949. fp = php_stream_fopen_tmpfile();
  950. phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC);
  951. link = phar_get_link_source(entry TSRMLS_CC);
  952. if (!link) {
  953. link = entry;
  954. }
  955. if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), fp, link->uncompressed_filesize, NULL)) {
  956. if (error) {
  957. spprintf(error, 4096, "phar error: cannot separate entry file \"%s\" contents in phar archive \"%s\" for write access", entry->filename, entry->phar->fname);
  958. }
  959. return FAILURE;
  960. }
  961. if (entry->link) {
  962. efree(entry->link);
  963. entry->link = NULL;
  964. entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
  965. }
  966. entry->offset = 0;
  967. entry->fp = fp;
  968. entry->fp_type = PHAR_MOD;
  969. entry->is_modified = 1;
  970. return SUCCESS;
  971. }
  972. /* }}} */
  973. /**
  974. * helper function to open an internal file's fp just-in-time
  975. */
  976. phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
  977. {
  978. if (error) {
  979. *error = NULL;
  980. }
  981. /* seek to start of internal file and read it */
  982. if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
  983. return NULL;
  984. }
  985. if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) {
  986. spprintf(error, 4096, "phar error: cannot seek to start of file \"%s\" in phar \"%s\"", entry->filename, phar->fname);
  987. return NULL;
  988. }
  989. return entry;
  990. }
  991. /* }}} */
  992. int phar_free_alias(phar_archive_data *phar, char *alias, int alias_len TSRMLS_DC) /* {{{ */
  993. {
  994. if (phar->refcount || phar->is_persistent) {
  995. return FAILURE;
  996. }
  997. /* this archive has no open references, so emit an E_STRICT and remove it */
  998. if (zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
  999. return FAILURE;
  1000. }
  1001. /* invalidate phar cache */
  1002. PHAR_G(last_phar) = NULL;
  1003. PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
  1004. return SUCCESS;
  1005. }
  1006. /* }}} */
  1007. /**
  1008. * Looks up a phar archive in the filename map, connecting it to the alias
  1009. * (if any) or returns null
  1010. */
  1011. int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, char *alias, int alias_len, char **error TSRMLS_DC) /* {{{ */
  1012. {
  1013. phar_archive_data *fd, **fd_ptr;
  1014. char *my_realpath, *save;
  1015. int save_len;
  1016. ulong fhash, ahash;
  1017. phar_request_initialize(TSRMLS_C);
  1018. if (error) {
  1019. *error = NULL;
  1020. }
  1021. *archive = NULL;
  1022. if (PHAR_G(last_phar) && fname_len == PHAR_G(last_phar_name_len) && !memcmp(fname, PHAR_G(last_phar_name), fname_len)) {
  1023. *archive = PHAR_G(last_phar);
  1024. if (alias && alias_len) {
  1025. 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))) {
  1026. if (error) {
  1027. spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, PHAR_G(last_phar)->fname, fname);
  1028. }
  1029. *archive = NULL;
  1030. return FAILURE;
  1031. }
  1032. 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)) {
  1033. zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len);
  1034. }
  1035. zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&(*archive), sizeof(phar_archive_data*), NULL);
  1036. PHAR_G(last_alias) = alias;
  1037. PHAR_G(last_alias_len) = alias_len;
  1038. }
  1039. return SUCCESS;
  1040. }
  1041. if (alias && alias_len && PHAR_G(last_phar) && alias_len == PHAR_G(last_alias_len) && !memcmp(alias, PHAR_G(last_alias), alias_len)) {
  1042. fd = PHAR_G(last_phar);
  1043. fd_ptr = &fd;
  1044. goto alias_success;
  1045. }
  1046. if (alias && alias_len) {
  1047. ahash = zend_inline_hash_func(alias, alias_len);
  1048. if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void**)&fd_ptr)) {
  1049. alias_success:
  1050. if (fname && (fname_len != (*fd_ptr)->fname_len || strncmp(fname, (*fd_ptr)->fname, fname_len))) {
  1051. if (error) {
  1052. spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
  1053. }
  1054. if (SUCCESS == phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
  1055. efree(*error);
  1056. *error = NULL;
  1057. }
  1058. return FAILURE;
  1059. }
  1060. *archive = *fd_ptr;
  1061. fd = *fd_ptr;
  1062. PHAR_G(last_phar) = fd;
  1063. PHAR_G(last_phar_name) = fd->fname;
  1064. PHAR_G(last_phar_name_len) = fd->fname_len;
  1065. PHAR_G(last_alias) = alias;
  1066. PHAR_G(last_alias_len) = alias_len;
  1067. return SUCCESS;
  1068. }
  1069. if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, alias, alias_len, ahash, (void **)&fd_ptr)) {
  1070. goto alias_success;
  1071. }
  1072. }
  1073. fhash = zend_inline_hash_func(fname, fname_len);
  1074. my_realpath = NULL;
  1075. save = fname;
  1076. save_len = fname_len;
  1077. if (fname && fname_len) {
  1078. if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
  1079. *archive = *fd_ptr;
  1080. fd = *fd_ptr;
  1081. if (alias && alias_len) {
  1082. if (!fd->is_temporary_alias && (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len))) {
  1083. if (error) {
  1084. spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
  1085. }
  1086. return FAILURE;
  1087. }
  1088. if (fd->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len, (void**)&fd_ptr)) {
  1089. zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len);
  1090. }
  1091. zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
  1092. }
  1093. PHAR_G(last_phar) = fd;
  1094. PHAR_G(last_phar_name) = fd->fname;
  1095. PHAR_G(last_phar_name_len) = fd->fname_len;
  1096. PHAR_G(last_alias) = fd->alias;
  1097. PHAR_G(last_alias_len) = fd->alias_len;
  1098. return SUCCESS;
  1099. }
  1100. if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
  1101. *archive = *fd_ptr;
  1102. fd = *fd_ptr;
  1103. /* this could be problematic - alias should never be different from manifest alias
  1104. for cached phars */
  1105. if (!fd->is_temporary_alias && alias && alias_len) {
  1106. if (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len)) {
  1107. if (error) {
  1108. spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
  1109. }
  1110. return FAILURE;
  1111. }
  1112. }
  1113. PHAR_G(last_phar) = fd;
  1114. PHAR_G(last_phar_name) = fd->fname;
  1115. PHAR_G(last_phar_name_len) = fd->fname_len;
  1116. PHAR_G(last_alias) = fd->alias;
  1117. PHAR_G(last_alias_len) = fd->alias_len;
  1118. return SUCCESS;
  1119. }
  1120. if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), save, save_len, fhash, (void**)&fd_ptr)) {
  1121. fd = *archive = *fd_ptr;
  1122. PHAR_G(last_phar) = fd;
  1123. PHAR_G(last_phar_name) = fd->fname;
  1124. PHAR_G(last_phar_name_len) = fd->fname_len;
  1125. PHAR_G(last_alias) = fd->alias;
  1126. PHAR_G(last_alias_len) = fd->alias_len;
  1127. return SUCCESS;
  1128. }
  1129. if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, save, save_len, fhash, (void**)&fd_ptr)) {
  1130. fd = *archive = *fd_ptr;
  1131. PHAR_G(last_phar) = fd;
  1132. PHAR_G(last_phar_name) = fd->fname;
  1133. PHAR_G(last_phar_name_len) = fd->fname_len;
  1134. PHAR_G(last_alias) = fd->alias;
  1135. PHAR_G(last_alias_len) = fd->alias_len;
  1136. return SUCCESS;
  1137. }
  1138. /* not found, try converting \ to / */
  1139. my_realpath = expand_filepath(fname, my_realpath TSRMLS_CC);
  1140. if (my_realpath) {
  1141. fname_len = strlen(my_realpath);
  1142. fname = my_realpath;
  1143. } else {
  1144. return FAILURE;
  1145. }
  1146. #ifdef PHP_WIN32
  1147. phar_unixify_path_separators(fname, fname_len);
  1148. #endif
  1149. fhash = zend_inline_hash_func(fname, fname_len);
  1150. if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
  1151. realpath_success:
  1152. *archive = *fd_ptr;
  1153. fd = *fd_ptr;
  1154. if (alias && alias_len) {
  1155. zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
  1156. }
  1157. efree(my_realpath);
  1158. PHAR_G(last_phar) = fd;
  1159. PHAR_G(last_phar_name) = fd->fname;
  1160. PHAR_G(last_phar_name_len) = fd->fname_len;
  1161. PHAR_G(last_alias) = fd->alias;
  1162. PHAR_G(last_alias_len) = fd->alias_len;
  1163. return SUCCESS;
  1164. }
  1165. if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
  1166. goto realpath_success;
  1167. }
  1168. efree(my_realpath);
  1169. }
  1170. return FAILURE;
  1171. }
  1172. /* }}} */
  1173. /**
  1174. * Determine which stream compression filter (if any) we need to read this file
  1175. */
  1176. char * phar_compress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
  1177. {
  1178. switch (entry->flags & PHAR_ENT_COMPRESSION_MASK) {
  1179. case PHAR_ENT_COMPRESSED_GZ:
  1180. return "zlib.deflate";
  1181. case PHAR_ENT_COMPRESSED_BZ2:
  1182. return "bzip2.compress";
  1183. default:
  1184. return return_unknown ? "unknown" : NULL;
  1185. }
  1186. }
  1187. /* }}} */
  1188. /**
  1189. * Determine which stream decompression filter (if any) we need to read this file
  1190. */
  1191. char * phar_decompress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
  1192. {
  1193. php_uint32 flags;
  1194. if (entry->is_modified) {
  1195. flags = entry->old_flags;
  1196. } else {
  1197. flags = entry->flags;
  1198. }
  1199. switch (flags & PHAR_ENT_COMPRESSION_MASK) {
  1200. case PHAR_ENT_COMPRESSED_GZ:
  1201. return "zlib.inflate";
  1202. case PHAR_ENT_COMPRESSED_BZ2:
  1203. return "bzip2.decompress";
  1204. default:
  1205. return return_unknown ? "unknown" : NULL;
  1206. }
  1207. }
  1208. /* }}} */
  1209. /**
  1210. * retrieve information on a file contained within a phar, or null if it ain't there
  1211. */
  1212. phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len, char **error, int security TSRMLS_DC) /* {{{ */
  1213. {
  1214. return phar_get_entry_info_dir(phar, path, path_len, 0, error, security TSRMLS_CC);
  1215. }
  1216. /* }}} */
  1217. /**
  1218. * retrieve information on a file or directory contained within a phar, or null if none found
  1219. * allow_dir is 0 for none, 1 for both empty directories in the phar and temp directories, and 2 for only
  1220. * valid pre-existing empty directory entries
  1221. */
  1222. 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) /* {{{ */
  1223. {
  1224. const char *pcr_error;
  1225. phar_entry_info *entry;
  1226. int is_dir;
  1227. #ifdef PHP_WIN32
  1228. phar_unixify_path_separators(path, path_len);
  1229. #endif
  1230. is_dir = (path_len && (path[path_len - 1] == '/')) ? 1 : 0;
  1231. if (error) {
  1232. *error = NULL;
  1233. }
  1234. if (security && path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) {
  1235. if (error) {
  1236. spprintf(error, 4096, "phar error: cannot directly access magic \".phar\" directory or files within it");
  1237. }
  1238. return NULL;
  1239. }
  1240. if (!path_len && !dir) {
  1241. if (error) {
  1242. spprintf(error, 4096, "phar error: invalid path \"%s\" must not be empty", path);
  1243. }
  1244. return NULL;
  1245. }
  1246. if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
  1247. if (error) {
  1248. spprintf(error, 4096, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
  1249. }
  1250. return NULL;
  1251. }
  1252. if (!phar->manifest.arBuckets) {
  1253. return NULL;
  1254. }
  1255. if (is_dir) {
  1256. if (!path_len || path_len == 1) {
  1257. return NULL;
  1258. }
  1259. path_len--;
  1260. }
  1261. if (SUCCESS == zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
  1262. if (entry->is_deleted) {
  1263. /* entry is deleted, but has not been flushed to disk yet */
  1264. return NULL;
  1265. }
  1266. if (entry->is_dir && !dir) {
  1267. if (error) {
  1268. spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
  1269. }
  1270. return NULL;
  1271. }
  1272. if (!entry->is_dir && dir == 2) {
  1273. /* user requested a directory, we must return one */
  1274. if (error) {
  1275. spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
  1276. }
  1277. return NULL;
  1278. }
  1279. return entry;
  1280. }
  1281. if (dir) {
  1282. if (zend_hash_exists(&phar->virtual_dirs, path, path_len)) {
  1283. /* a file or directory exists in a sub-directory of this path */
  1284. entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info));
  1285. /* this next line tells PharFileInfo->__destruct() to efree the filename */
  1286. entry->is_temp_dir = entry->is_dir = 1;
  1287. entry->filename = (char *) estrndup(path, path_len + 1);
  1288. entry->filename_len = path_len;
  1289. entry->phar = phar;
  1290. return entry;
  1291. }
  1292. }
  1293. if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) {
  1294. phar_zstr key;
  1295. char *str_key;
  1296. ulong unused;
  1297. uint keylen;
  1298. zend_hash_internal_pointer_reset(&phar->mounted_dirs);
  1299. while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) {
  1300. if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, NULL)) {
  1301. break;
  1302. }
  1303. PHAR_STR(key, str_key);
  1304. if ((int)keylen >= path_len || strncmp(str_key, path, keylen)) {
  1305. PHAR_STR_FREE(str_key);
  1306. continue;
  1307. } else {
  1308. char *test;
  1309. int test_len;
  1310. php_stream_statbuf ssb;
  1311. if (SUCCESS != zend_hash_find(&phar->manifest, str_key, keylen, (void **) &entry)) {
  1312. if (error) {
  1313. spprintf(error, 4096, "phar internal error: mounted path \"%s\" could not be retrieved from manifest", str_key);
  1314. }
  1315. PHAR_STR_FREE(str_key);
  1316. return NULL;
  1317. }
  1318. if (!entry->tmp || !entry->is_mounted) {
  1319. if (error) {
  1320. spprintf(error, 4096, "phar internal error: mounted path \"%s\" is not properly initialized as a mounted path", str_key);
  1321. }
  1322. PHAR_STR_FREE(str_key);
  1323. return NULL;
  1324. }
  1325. PHAR_STR_FREE(str_key);
  1326. test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, path + keylen);
  1327. if (SUCCESS != php_stream_stat_path(test, &ssb)) {
  1328. efree(test);
  1329. return NULL;
  1330. }
  1331. if (ssb.sb.st_mode & S_IFDIR && !dir) {
  1332. efree(test);
  1333. if (error) {
  1334. spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
  1335. }
  1336. return NULL;
  1337. }
  1338. if ((ssb.sb.st_mode & S_IFDIR) == 0 && dir) {
  1339. efree(test);
  1340. /* user requested a directory, we must return one */
  1341. if (error) {
  1342. spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
  1343. }
  1344. return NULL;
  1345. }
  1346. /* mount the file just in time */
  1347. if (SUCCESS != phar_mount_entry(phar, test, test_len, path, path_len TSRMLS_CC)) {
  1348. efree(test);
  1349. if (error) {
  1350. spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be mounted", path, test);
  1351. }
  1352. return NULL;
  1353. }
  1354. efree(test);
  1355. if (SUCCESS != zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
  1356. if (error) {
  1357. spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be retrieved after being mounted", path, test);
  1358. }
  1359. return NULL;
  1360. }
  1361. return entry;
  1362. }
  1363. }
  1364. }
  1365. return NULL;
  1366. }
  1367. /* }}} */
  1368. static const char hexChars[] = "0123456789ABCDEF";
  1369. static int phar_hex_str(const char *digest, size_t digest_len, char **signature TSRMLS_DC) /* {{{ */
  1370. {
  1371. int pos = -1;
  1372. size_t len = 0;
  1373. *signature = (char*)safe_pemalloc(digest_len, 2, 1, PHAR_G(persist));
  1374. for (; len < digest_len; ++len) {
  1375. (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] >> 4];
  1376. (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] & 0x0F];
  1377. }
  1378. (*signature)[++pos] = '\0';
  1379. return pos;
  1380. }
  1381. /* }}} */
  1382. #ifndef PHAR_HAVE_OPENSSL
  1383. 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) /* {{{ */
  1384. {
  1385. zend_fcall_info fci;
  1386. zend_fcall_info_cache fcc;
  1387. zval *zdata, *zsig, *zkey, *retval_ptr, **zp[3], *openssl;
  1388. MAKE_STD_ZVAL(zdata);
  1389. MAKE_STD_ZVAL(openssl);
  1390. ZVAL_STRINGL(openssl, is_sign ? "openssl_sign" : "openssl_verify", is_sign ? sizeof("openssl_sign")-1 : sizeof("openssl_verify")-1, 1);
  1391. MAKE_STD_ZVAL(zsig);
  1392. ZVAL_STRINGL(zsig, *signature, *signature_len, 1);
  1393. MAKE_STD_ZVAL(zkey);
  1394. ZVAL_STRINGL(zkey, key, key_len, 1);
  1395. zp[0] = &zdata;
  1396. zp[1] = &zsig;
  1397. zp[2] = &zkey;
  1398. php_stream_rewind(fp);
  1399. Z_TYPE_P(zdata) = IS_STRING;
  1400. Z_STRLEN_P(zdata) = end;
  1401. #if PHP_MAJOR_VERSION > 5
  1402. if (end != (off_t) php_stream_copy_to_mem(fp, (void **) &(Z_STRVAL_P(zdata)), (size_t) end, 0)) {
  1403. #else
  1404. if (end != (off_t) php_stream_copy_to_mem(fp, &(Z_STRVAL_P(zdata)), (size_t) end, 0)) {
  1405. #endif
  1406. zval_dtor(zdata);
  1407. zval_dtor(zsig);
  1408. zval_dtor(zkey);
  1409. zval_dtor(openssl);
  1410. efree(openssl);
  1411. efree(zdata);
  1412. efree(zkey);
  1413. efree(zsig);
  1414. return FAILURE;
  1415. }
  1416. #if PHP_VERSION_ID < 50300
  1417. if (FAILURE == zend_fcall_info_init(openssl, &fci, &fcc TSRMLS_CC)) {
  1418. #else
  1419. if (FAILURE == zend_fcall_info_init(openssl, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) {
  1420. #endif
  1421. zval_dtor(zdata);
  1422. zval_dtor(zsig);
  1423. zval_dtor(zkey);
  1424. zval_dtor(openssl);
  1425. efree(openssl);
  1426. efree(zdata);
  1427. efree(zkey);
  1428. efree(zsig);
  1429. return FAILURE;
  1430. }
  1431. fci.param_count = 3;
  1432. fci.params = zp;
  1433. #if PHP_VERSION_ID < 50300
  1434. ++(zdata->refcount);
  1435. if (!is_sign) {
  1436. ++(zsig->refcount);
  1437. }
  1438. ++(zkey->refcount);
  1439. #else
  1440. Z_ADDREF_P(zdata);
  1441. if (is_sign) {
  1442. Z_SET_ISREF_P(zsig);
  1443. } else {
  1444. Z_ADDREF_P(zsig);
  1445. }
  1446. Z_ADDREF_P(zkey);
  1447. #endif
  1448. fci.retval_ptr_ptr = &retval_ptr;
  1449. if (FAILURE == zend_call_function(&fci, &fcc TSRMLS_CC)) {
  1450. zval_dtor(zdata);
  1451. zval_dtor(zsig);
  1452. zval_dtor(zkey);
  1453. zval_dtor(openssl);
  1454. efree(openssl);
  1455. efree(zdata);
  1456. efree(zkey);
  1457. efree(zsig);
  1458. return FAILURE;
  1459. }
  1460. zval_dtor(openssl);
  1461. efree(openssl);
  1462. #if PHP_VERSION_ID < 50300
  1463. --(zdata->refcount);
  1464. if (!is_sign) {
  1465. --(zsig->refcount);
  1466. }
  1467. --(zkey->refcount);
  1468. #else
  1469. Z_DELREF_P(zdata);
  1470. if (is_sign) {
  1471. Z_UNSET_ISREF_P(zsig);
  1472. } else {
  1473. Z_DELREF_P(zsig);
  1474. }
  1475. Z_DELREF_P(zkey);
  1476. #endif
  1477. zval_dtor(zdata);
  1478. efree(zdata);
  1479. zval_dtor(zkey);
  1480. efree(zkey);
  1481. switch (Z_TYPE_P(retval_ptr)) {
  1482. default:
  1483. case IS_LONG:
  1484. zval_dtor(zsig);
  1485. efree(zsig);
  1486. if (1 == Z_LVAL_P(retval_ptr)) {
  1487. efree(retval_ptr);
  1488. return SUCCESS;
  1489. }
  1490. efree(retval_ptr);
  1491. return FAILURE;
  1492. case IS_BOOL:
  1493. efree(retval_ptr);
  1494. if (Z_BVAL_P(retval_ptr)) {
  1495. *signature = estrndup(Z_STRVAL_P(zsig), Z_STRLEN_P(zsig));
  1496. *signature_len = Z_STRLEN_P(zsig);
  1497. zval_dtor(zsig);
  1498. efree(zsig);
  1499. return SUCCESS;
  1500. }
  1501. zval_dtor(zsig);
  1502. efree(zsig);
  1503. return FAILURE;
  1504. }
  1505. }
  1506. /* }}} */
  1507. #endif /* #ifndef PHAR_HAVE_OPENSSL */
  1508. 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) /* {{{ */
  1509. {
  1510. int read_size, len;
  1511. off_t read_len;
  1512. unsigned char buf[1024];
  1513. php_stream_rewind(fp);
  1514. switch (sig_type) {
  1515. case PHAR_SIG_OPENSSL: {
  1516. #ifdef PHAR_HAVE_OPENSSL
  1517. BIO *in;
  1518. EVP_PKEY *key;
  1519. EVP_MD *mdtype = (EVP_MD *) EVP_sha1();
  1520. EVP_MD_CTX md_ctx;
  1521. #else
  1522. int

Large files files are truncated, but you can click here to view the full file