PageRenderTime 59ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/ext/phar/phar.c

http://github.com/php/php-src
C | 3591 lines | 2768 code | 490 blank | 333 comment | 917 complexity | 7da5396f75bf1eabaf02252ee1710cb0 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1

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. +----------------------------------------------------------------------+
  5. | Copyright (c) The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt. |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Gregory Beaver <cellog@php.net> |
  16. | Marcus Boerger <helly@php.net> |
  17. +----------------------------------------------------------------------+
  18. */
  19. #define PHAR_MAIN 1
  20. #include "phar_internal.h"
  21. #include "SAPI.h"
  22. #include "func_interceptors.h"
  23. static void destroy_phar_data(zval *zv);
  24. ZEND_DECLARE_MODULE_GLOBALS(phar)
  25. zend_string *(*phar_save_resolve_path)(const char *filename, size_t filename_len);
  26. /**
  27. * set's phar->is_writeable based on the current INI value
  28. */
  29. static int phar_set_writeable_bit(zval *zv, void *argument) /* {{{ */
  30. {
  31. zend_bool keep = *(zend_bool *)argument;
  32. phar_archive_data *phar = (phar_archive_data *)Z_PTR_P(zv);
  33. if (!phar->is_data) {
  34. phar->is_writeable = !keep;
  35. }
  36. return ZEND_HASH_APPLY_KEEP;
  37. }
  38. /* }}} */
  39. /* if the original value is 0 (disabled), then allow setting/unsetting at will. Otherwise only allow 1 (enabled), and error on disabling */
  40. ZEND_INI_MH(phar_ini_modify_handler) /* {{{ */
  41. {
  42. zend_bool old, ini;
  43. if (ZSTR_LEN(entry->name) == sizeof("phar.readonly")-1) {
  44. old = PHAR_G(readonly_orig);
  45. } else {
  46. old = PHAR_G(require_hash_orig);
  47. }
  48. if (ZSTR_LEN(new_value) == 2 && !strcasecmp("on", ZSTR_VAL(new_value))) {
  49. ini = (zend_bool) 1;
  50. }
  51. else if (ZSTR_LEN(new_value) == 3 && !strcasecmp("yes", ZSTR_VAL(new_value))) {
  52. ini = (zend_bool) 1;
  53. }
  54. else if (ZSTR_LEN(new_value) == 4 && !strcasecmp("true", ZSTR_VAL(new_value))) {
  55. ini = (zend_bool) 1;
  56. }
  57. else {
  58. ini = (zend_bool) atoi(ZSTR_VAL(new_value));
  59. }
  60. /* do not allow unsetting in runtime */
  61. if (stage == ZEND_INI_STAGE_STARTUP) {
  62. if (ZSTR_LEN(entry->name) == sizeof("phar.readonly")-1) {
  63. PHAR_G(readonly_orig) = ini;
  64. } else {
  65. PHAR_G(require_hash_orig) = ini;
  66. }
  67. } else if (old && !ini) {
  68. return FAILURE;
  69. }
  70. if (ZSTR_LEN(entry->name) == sizeof("phar.readonly")-1) {
  71. PHAR_G(readonly) = ini;
  72. if (PHAR_G(request_init) && HT_IS_INITIALIZED(&PHAR_G(phar_fname_map))) {
  73. zend_hash_apply_with_argument(&(PHAR_G(phar_fname_map)), phar_set_writeable_bit, (void *)&ini);
  74. }
  75. } else {
  76. PHAR_G(require_hash) = ini;
  77. }
  78. return SUCCESS;
  79. }
  80. /* }}}*/
  81. /* this global stores the global cached pre-parsed manifests */
  82. HashTable cached_phars;
  83. HashTable cached_alias;
  84. static void phar_split_cache_list(void) /* {{{ */
  85. {
  86. char *tmp;
  87. char *key, *lasts, *end;
  88. char ds[2];
  89. phar_archive_data *phar;
  90. uint32_t i = 0;
  91. if (!PHAR_G(cache_list) || !(PHAR_G(cache_list)[0])) {
  92. return;
  93. }
  94. ds[0] = DEFAULT_DIR_SEPARATOR;
  95. ds[1] = '\0';
  96. tmp = estrdup(PHAR_G(cache_list));
  97. /* fake request startup */
  98. PHAR_G(request_init) = 1;
  99. zend_init_rsrc_list();
  100. EG(regular_list).nNextFreeElement=1; /* we don't want resource id 0 */
  101. PHAR_G(has_bz2) = zend_hash_str_exists(&module_registry, "bz2", sizeof("bz2")-1);
  102. PHAR_G(has_zlib) = zend_hash_str_exists(&module_registry, "zlib", sizeof("zlib")-1);
  103. /* these two are dummies and will be destroyed later */
  104. zend_hash_init(&cached_phars, sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data, 1);
  105. zend_hash_init(&cached_alias, sizeof(phar_archive_data*), zend_get_hash_value, NULL, 1);
  106. /* these two are real and will be copied over cached_phars/cached_alias later */
  107. zend_hash_init(&(PHAR_G(phar_fname_map)), sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data, 1);
  108. zend_hash_init(&(PHAR_G(phar_alias_map)), sizeof(phar_archive_data*), zend_get_hash_value, NULL, 1);
  109. PHAR_G(manifest_cached) = 1;
  110. PHAR_G(persist) = 1;
  111. for (key = php_strtok_r(tmp, ds, &lasts);
  112. key;
  113. key = php_strtok_r(NULL, ds, &lasts)) {
  114. size_t len;
  115. end = strchr(key, DEFAULT_DIR_SEPARATOR);
  116. if (end) {
  117. len = end - key;
  118. } else {
  119. len = strlen(key);
  120. }
  121. if (SUCCESS == phar_open_from_filename(key, len, NULL, 0, 0, &phar, NULL)) {
  122. phar->phar_pos = i++;
  123. php_stream_close(phar->fp);
  124. phar->fp = NULL;
  125. } else {
  126. PHAR_G(persist) = 0;
  127. PHAR_G(manifest_cached) = 0;
  128. efree(tmp);
  129. zend_hash_destroy(&(PHAR_G(phar_fname_map)));
  130. HT_INVALIDATE(&PHAR_G(phar_fname_map));
  131. zend_hash_destroy(&(PHAR_G(phar_alias_map)));
  132. HT_INVALIDATE(&PHAR_G(phar_alias_map));
  133. zend_hash_destroy(&cached_phars);
  134. zend_hash_destroy(&cached_alias);
  135. zend_hash_graceful_reverse_destroy(&EG(regular_list));
  136. memset(&EG(regular_list), 0, sizeof(HashTable));
  137. /* free cached manifests */
  138. PHAR_G(request_init) = 0;
  139. return;
  140. }
  141. }
  142. PHAR_G(persist) = 0;
  143. PHAR_G(request_init) = 0;
  144. /* destroy dummy values from before */
  145. zend_hash_destroy(&cached_phars);
  146. zend_hash_destroy(&cached_alias);
  147. cached_phars = PHAR_G(phar_fname_map);
  148. cached_alias = PHAR_G(phar_alias_map);
  149. HT_INVALIDATE(&PHAR_G(phar_fname_map));
  150. HT_INVALIDATE(&PHAR_G(phar_alias_map));
  151. zend_hash_graceful_reverse_destroy(&EG(regular_list));
  152. memset(&EG(regular_list), 0, sizeof(HashTable));
  153. efree(tmp);
  154. }
  155. /* }}} */
  156. ZEND_INI_MH(phar_ini_cache_list) /* {{{ */
  157. {
  158. PHAR_G(cache_list) = ZSTR_VAL(new_value);
  159. if (stage == ZEND_INI_STAGE_STARTUP) {
  160. phar_split_cache_list();
  161. }
  162. return SUCCESS;
  163. }
  164. /* }}} */
  165. PHP_INI_BEGIN()
  166. STD_PHP_INI_BOOLEAN("phar.readonly", "1", PHP_INI_ALL, phar_ini_modify_handler, readonly, zend_phar_globals, phar_globals)
  167. STD_PHP_INI_BOOLEAN("phar.require_hash", "1", PHP_INI_ALL, phar_ini_modify_handler, require_hash, zend_phar_globals, phar_globals)
  168. STD_PHP_INI_ENTRY("phar.cache_list", "", PHP_INI_SYSTEM, phar_ini_cache_list, cache_list, zend_phar_globals, phar_globals)
  169. PHP_INI_END()
  170. /**
  171. * When all uses of a phar have been concluded, this frees the manifest
  172. * and the phar slot
  173. */
  174. void phar_destroy_phar_data(phar_archive_data *phar) /* {{{ */
  175. {
  176. if (phar->alias && phar->alias != phar->fname) {
  177. pefree(phar->alias, phar->is_persistent);
  178. phar->alias = NULL;
  179. }
  180. if (phar->fname) {
  181. pefree(phar->fname, phar->is_persistent);
  182. phar->fname = NULL;
  183. }
  184. if (phar->signature) {
  185. pefree(phar->signature, phar->is_persistent);
  186. phar->signature = NULL;
  187. }
  188. if (HT_IS_INITIALIZED(&phar->manifest)) {
  189. zend_hash_destroy(&phar->manifest);
  190. HT_INVALIDATE(&phar->manifest);
  191. }
  192. if (HT_IS_INITIALIZED(&phar->mounted_dirs)) {
  193. zend_hash_destroy(&phar->mounted_dirs);
  194. HT_INVALIDATE(&phar->mounted_dirs);
  195. }
  196. if (HT_IS_INITIALIZED(&phar->virtual_dirs)) {
  197. zend_hash_destroy(&phar->virtual_dirs);
  198. HT_INVALIDATE(&phar->virtual_dirs);
  199. }
  200. if (Z_TYPE(phar->metadata) != IS_UNDEF) {
  201. if (phar->is_persistent) {
  202. if (phar->metadata_len) {
  203. /* for zip comments that are strings */
  204. free(Z_PTR(phar->metadata));
  205. } else {
  206. zval_internal_ptr_dtor(&phar->metadata);
  207. }
  208. } else {
  209. zval_ptr_dtor(&phar->metadata);
  210. }
  211. phar->metadata_len = 0;
  212. ZVAL_UNDEF(&phar->metadata);
  213. }
  214. if (phar->fp) {
  215. php_stream_close(phar->fp);
  216. phar->fp = 0;
  217. }
  218. if (phar->ufp) {
  219. php_stream_close(phar->ufp);
  220. phar->ufp = 0;
  221. }
  222. pefree(phar, phar->is_persistent);
  223. }
  224. /* }}}*/
  225. /**
  226. * Delete refcount and destruct if needed. On destruct return 1 else 0.
  227. */
  228. int phar_archive_delref(phar_archive_data *phar) /* {{{ */
  229. {
  230. if (phar->is_persistent) {
  231. return 0;
  232. }
  233. if (--phar->refcount < 0) {
  234. if (PHAR_G(request_done)
  235. || zend_hash_str_del(&(PHAR_G(phar_fname_map)), phar->fname, phar->fname_len) != SUCCESS) {
  236. phar_destroy_phar_data(phar);
  237. }
  238. return 1;
  239. } else if (!phar->refcount) {
  240. /* invalidate phar cache */
  241. PHAR_G(last_phar) = NULL;
  242. PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
  243. if (phar->fp && (!(phar->flags & PHAR_FILE_COMPRESSION_MASK) || !phar->alias)) {
  244. /* close open file handle - allows removal or rename of
  245. the file on windows, which has greedy locking
  246. only close if the archive was not already compressed. If it
  247. was compressed, then the fp does not refer to the original file.
  248. We're also closing compressed files to save resources,
  249. but only if the archive isn't aliased. */
  250. php_stream_close(phar->fp);
  251. phar->fp = NULL;
  252. }
  253. if (!zend_hash_num_elements(&phar->manifest)) {
  254. /* this is a new phar that has perhaps had an alias/metadata set, but has never
  255. been flushed */
  256. if (zend_hash_str_del(&(PHAR_G(phar_fname_map)), phar->fname, phar->fname_len) != SUCCESS) {
  257. phar_destroy_phar_data(phar);
  258. }
  259. return 1;
  260. }
  261. }
  262. return 0;
  263. }
  264. /* }}}*/
  265. /**
  266. * Destroy phar's in shutdown, here we don't care about aliases
  267. */
  268. static void destroy_phar_data_only(zval *zv) /* {{{ */
  269. {
  270. phar_archive_data *phar_data = (phar_archive_data *) Z_PTR_P(zv);
  271. if (EG(exception) || --phar_data->refcount < 0) {
  272. phar_destroy_phar_data(phar_data);
  273. }
  274. }
  275. /* }}}*/
  276. /**
  277. * Delete aliases to phar's that got kicked out of the global table
  278. */
  279. static int phar_unalias_apply(zval *zv, void *argument) /* {{{ */
  280. {
  281. return Z_PTR_P(zv) == argument ? ZEND_HASH_APPLY_REMOVE : ZEND_HASH_APPLY_KEEP;
  282. }
  283. /* }}} */
  284. /**
  285. * Delete aliases to phar's that got kicked out of the global table
  286. */
  287. static int phar_tmpclose_apply(zval *zv) /* {{{ */
  288. {
  289. phar_entry_info *entry = (phar_entry_info *) Z_PTR_P(zv);
  290. if (entry->fp_type != PHAR_TMP) {
  291. return ZEND_HASH_APPLY_KEEP;
  292. }
  293. if (entry->fp && !entry->fp_refcount) {
  294. php_stream_close(entry->fp);
  295. entry->fp = NULL;
  296. }
  297. return ZEND_HASH_APPLY_KEEP;
  298. }
  299. /* }}} */
  300. /**
  301. * Filename map destructor
  302. */
  303. static void destroy_phar_data(zval *zv) /* {{{ */
  304. {
  305. phar_archive_data *phar_data = (phar_archive_data *)Z_PTR_P(zv);
  306. if (PHAR_G(request_ends)) {
  307. /* first, iterate over the manifest and close all PHAR_TMP entry fp handles,
  308. this prevents unnecessary unfreed stream resources */
  309. zend_hash_apply(&(phar_data->manifest), phar_tmpclose_apply);
  310. destroy_phar_data_only(zv);
  311. return;
  312. }
  313. zend_hash_apply_with_argument(&(PHAR_G(phar_alias_map)), phar_unalias_apply, phar_data);
  314. if (--phar_data->refcount < 0) {
  315. phar_destroy_phar_data(phar_data);
  316. }
  317. }
  318. /* }}}*/
  319. /**
  320. * destructor for the manifest hash, frees each file's entry
  321. */
  322. void destroy_phar_manifest_entry_int(phar_entry_info *entry) /* {{{ */
  323. {
  324. if (entry->cfp) {
  325. php_stream_close(entry->cfp);
  326. entry->cfp = 0;
  327. }
  328. if (entry->fp) {
  329. php_stream_close(entry->fp);
  330. entry->fp = 0;
  331. }
  332. if (Z_TYPE(entry->metadata) != IS_UNDEF) {
  333. if (entry->is_persistent) {
  334. if (entry->metadata_len) {
  335. /* for zip comments that are strings */
  336. free(Z_PTR(entry->metadata));
  337. } else {
  338. zval_internal_ptr_dtor(&entry->metadata);
  339. }
  340. } else {
  341. zval_ptr_dtor(&entry->metadata);
  342. }
  343. entry->metadata_len = 0;
  344. ZVAL_UNDEF(&entry->metadata);
  345. }
  346. if (entry->metadata_str.s) {
  347. smart_str_free(&entry->metadata_str);
  348. entry->metadata_str.s = NULL;
  349. }
  350. pefree(entry->filename, entry->is_persistent);
  351. if (entry->link) {
  352. pefree(entry->link, entry->is_persistent);
  353. entry->link = 0;
  354. }
  355. if (entry->tmp) {
  356. pefree(entry->tmp, entry->is_persistent);
  357. entry->tmp = 0;
  358. }
  359. }
  360. /* }}} */
  361. void destroy_phar_manifest_entry(zval *zv) /* {{{ */
  362. {
  363. phar_entry_info *entry = Z_PTR_P(zv);
  364. destroy_phar_manifest_entry_int(entry);
  365. pefree(entry, entry->is_persistent);
  366. }
  367. /* }}} */
  368. int phar_entry_delref(phar_entry_data *idata) /* {{{ */
  369. {
  370. int ret = 0;
  371. if (idata->internal_file && !idata->internal_file->is_persistent) {
  372. if (--idata->internal_file->fp_refcount < 0) {
  373. idata->internal_file->fp_refcount = 0;
  374. }
  375. if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
  376. php_stream_close(idata->fp);
  377. }
  378. /* if phar_get_or_create_entry_data returns a sub-directory, we have to free it */
  379. if (idata->internal_file->is_temp_dir) {
  380. destroy_phar_manifest_entry_int(idata->internal_file);
  381. efree(idata->internal_file);
  382. }
  383. }
  384. phar_archive_delref(idata->phar);
  385. efree(idata);
  386. return ret;
  387. }
  388. /* }}} */
  389. /**
  390. * Removes an entry, either by actually removing it or by marking it.
  391. */
  392. void phar_entry_remove(phar_entry_data *idata, char **error) /* {{{ */
  393. {
  394. phar_archive_data *phar;
  395. phar = idata->phar;
  396. if (idata->internal_file->fp_refcount < 2) {
  397. if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
  398. php_stream_close(idata->fp);
  399. }
  400. zend_hash_str_del(&idata->phar->manifest, idata->internal_file->filename, idata->internal_file->filename_len);
  401. idata->phar->refcount--;
  402. efree(idata);
  403. } else {
  404. idata->internal_file->is_deleted = 1;
  405. phar_entry_delref(idata);
  406. }
  407. if (!phar->donotflush) {
  408. phar_flush(phar, 0, 0, 0, error);
  409. }
  410. }
  411. /* }}} */
  412. #define MAPPHAR_ALLOC_FAIL(msg) \
  413. if (fp) {\
  414. php_stream_close(fp);\
  415. }\
  416. if (error) {\
  417. spprintf(error, 0, msg, fname);\
  418. }\
  419. return FAILURE;
  420. #define MAPPHAR_FAIL(msg) \
  421. efree(savebuf);\
  422. if (mydata) {\
  423. phar_destroy_phar_data(mydata);\
  424. }\
  425. if (signature) {\
  426. pefree(signature, PHAR_G(persist));\
  427. }\
  428. MAPPHAR_ALLOC_FAIL(msg)
  429. #ifdef WORDS_BIGENDIAN
  430. # define PHAR_GET_32(buffer, var) \
  431. var = ((((unsigned char*)(buffer))[3]) << 24) \
  432. | ((((unsigned char*)(buffer))[2]) << 16) \
  433. | ((((unsigned char*)(buffer))[1]) << 8) \
  434. | (((unsigned char*)(buffer))[0]); \
  435. (buffer) += 4
  436. # define PHAR_GET_16(buffer, var) \
  437. var = ((((unsigned char*)(buffer))[1]) << 8) \
  438. | (((unsigned char*)(buffer))[0]); \
  439. (buffer) += 2
  440. #else
  441. # define PHAR_GET_32(buffer, var) \
  442. memcpy(&var, buffer, sizeof(var)); \
  443. buffer += 4
  444. # define PHAR_GET_16(buffer, var) \
  445. var = *(uint16_t*)(buffer); \
  446. buffer += 2
  447. #endif
  448. #define PHAR_ZIP_16(var) ((uint16_t)((((uint16_t)var[0]) & 0xff) | \
  449. (((uint16_t)var[1]) & 0xff) << 8))
  450. #define PHAR_ZIP_32(var) ((uint32_t)((((uint32_t)var[0]) & 0xff) | \
  451. (((uint32_t)var[1]) & 0xff) << 8 | \
  452. (((uint32_t)var[2]) & 0xff) << 16 | \
  453. (((uint32_t)var[3]) & 0xff) << 24))
  454. /**
  455. * Open an already loaded phar
  456. */
  457. int phar_open_parsed_phar(char *fname, size_t fname_len, char *alias, size_t alias_len, zend_bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
  458. {
  459. phar_archive_data *phar;
  460. #ifdef PHP_WIN32
  461. char *save_fname;
  462. ALLOCA_FLAG(fname_use_heap)
  463. #endif
  464. if (error) {
  465. *error = NULL;
  466. }
  467. #ifdef PHP_WIN32
  468. save_fname = fname;
  469. if (memchr(fname, '\\', fname_len)) {
  470. fname = do_alloca(fname_len + 1, fname_use_heap);
  471. memcpy(fname, save_fname, fname_len);
  472. fname[fname_len] = '\0';
  473. phar_unixify_path_separators(fname, fname_len);
  474. }
  475. #endif
  476. if (SUCCESS == phar_get_archive(&phar, fname, fname_len, alias, alias_len, error)
  477. && ((alias && fname_len == phar->fname_len
  478. && !strncmp(fname, phar->fname, fname_len)) || !alias)
  479. ) {
  480. phar_entry_info *stub;
  481. #ifdef PHP_WIN32
  482. if (fname != save_fname) {
  483. free_alloca(fname, fname_use_heap);
  484. fname = save_fname;
  485. }
  486. #endif
  487. /* logic above is as follows:
  488. If an explicit alias was requested, ensure the filename passed in
  489. matches the phar's filename.
  490. If no alias was passed in, then it can match either and be valid
  491. */
  492. if (!is_data) {
  493. /* prevent any ".phar" without a stub getting through */
  494. if (!phar->halt_offset && !phar->is_brandnew && (phar->is_tar || phar->is_zip)) {
  495. if (PHAR_G(readonly) && NULL == (stub = zend_hash_str_find_ptr(&(phar->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1))) {
  496. if (error) {
  497. spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
  498. }
  499. return FAILURE;
  500. }
  501. }
  502. }
  503. if (pphar) {
  504. *pphar = phar;
  505. }
  506. return SUCCESS;
  507. } else {
  508. #ifdef PHP_WIN32
  509. if (fname != save_fname) {
  510. free_alloca(fname, fname_use_heap);
  511. fname = save_fname;
  512. }
  513. #endif
  514. if (pphar) {
  515. *pphar = NULL;
  516. }
  517. if (phar && error && !(options & REPORT_ERRORS)) {
  518. efree(error);
  519. }
  520. return FAILURE;
  521. }
  522. }
  523. /* }}}*/
  524. /**
  525. * Parse out metadata from the manifest for a single file
  526. *
  527. * Meta-data is in this format:
  528. * [len32][data...]
  529. *
  530. * data is the serialized zval
  531. */
  532. int phar_parse_metadata(char **buffer, zval *metadata, uint32_t zip_metadata_len) /* {{{ */
  533. {
  534. php_unserialize_data_t var_hash;
  535. if (zip_metadata_len) {
  536. const unsigned char *p;
  537. unsigned char *p_buff = (unsigned char *)estrndup(*buffer, zip_metadata_len);
  538. p = p_buff;
  539. ZVAL_NULL(metadata);
  540. PHP_VAR_UNSERIALIZE_INIT(var_hash);
  541. if (!php_var_unserialize(metadata, &p, p + zip_metadata_len, &var_hash)) {
  542. efree(p_buff);
  543. PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
  544. zval_ptr_dtor(metadata);
  545. ZVAL_UNDEF(metadata);
  546. return FAILURE;
  547. }
  548. efree(p_buff);
  549. PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
  550. if (PHAR_G(persist)) {
  551. /* lazy init metadata */
  552. zval_ptr_dtor(metadata);
  553. Z_PTR_P(metadata) = pemalloc(zip_metadata_len, 1);
  554. memcpy(Z_PTR_P(metadata), *buffer, zip_metadata_len);
  555. return SUCCESS;
  556. }
  557. } else {
  558. ZVAL_UNDEF(metadata);
  559. }
  560. return SUCCESS;
  561. }
  562. /* }}}*/
  563. /**
  564. * Size of fixed fields in the manifest.
  565. * See: http://php.net/manual/en/phar.fileformat.phar.php
  566. */
  567. #define MANIFEST_FIXED_LEN 18
  568. #define SAFE_PHAR_GET_32(buffer, endbuffer, var) \
  569. if (UNEXPECTED(buffer + 4 > endbuffer)) { \
  570. MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)"); \
  571. } \
  572. PHAR_GET_32(buffer, var);
  573. /**
  574. * Does not check for a previously opened phar in the cache.
  575. *
  576. * Parse a new one and add it to the cache, returning either SUCCESS or
  577. * FAILURE, and setting pphar to the pointer to the manifest entry
  578. *
  579. * This is used by phar_open_from_filename to process the manifest, but can be called
  580. * directly.
  581. */
  582. static int phar_parse_pharfile(php_stream *fp, char *fname, size_t fname_len, char *alias, size_t alias_len, zend_long halt_offset, phar_archive_data** pphar, uint32_t compression, char **error) /* {{{ */
  583. {
  584. char b32[4], *buffer, *endbuffer, *savebuf;
  585. phar_archive_data *mydata = NULL;
  586. phar_entry_info entry;
  587. uint32_t manifest_len, manifest_count, manifest_flags, manifest_index, tmp_len, sig_flags;
  588. uint16_t manifest_ver;
  589. uint32_t len;
  590. zend_long offset;
  591. size_t sig_len;
  592. int register_alias = 0, temp_alias = 0;
  593. char *signature = NULL;
  594. zend_string *str;
  595. if (pphar) {
  596. *pphar = NULL;
  597. }
  598. if (error) {
  599. *error = NULL;
  600. }
  601. /* check for ?>\n and increment accordingly */
  602. if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) {
  603. MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"")
  604. }
  605. buffer = b32;
  606. if (3 != php_stream_read(fp, buffer, 3)) {
  607. MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
  608. }
  609. if ((*buffer == ' ' || *buffer == '\n') && *(buffer + 1) == '?' && *(buffer + 2) == '>') {
  610. int nextchar;
  611. halt_offset += 3;
  612. if (EOF == (nextchar = php_stream_getc(fp))) {
  613. MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
  614. }
  615. if ((char) nextchar == '\r') {
  616. /* if we have an \r we require an \n as well */
  617. if (EOF == (nextchar = php_stream_getc(fp)) || (char)nextchar != '\n') {
  618. MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
  619. }
  620. ++halt_offset;
  621. }
  622. if ((char) nextchar == '\n') {
  623. ++halt_offset;
  624. }
  625. }
  626. /* make sure we are at the right location to read the manifest */
  627. if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) {
  628. MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"")
  629. }
  630. /* read in manifest */
  631. buffer = b32;
  632. if (4 != php_stream_read(fp, buffer, 4)) {
  633. MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at manifest length)")
  634. }
  635. PHAR_GET_32(buffer, manifest_len);
  636. if (manifest_len > 1048576 * 100) {
  637. /* prevent serious memory issues by limiting manifest to at most 100 MB in length */
  638. MAPPHAR_ALLOC_FAIL("manifest cannot be larger than 100 MB in phar \"%s\"")
  639. }
  640. buffer = (char *)emalloc(manifest_len);
  641. savebuf = buffer;
  642. endbuffer = buffer + manifest_len;
  643. if (manifest_len < MANIFEST_FIXED_LEN || manifest_len != php_stream_read(fp, buffer, manifest_len)) {
  644. MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)")
  645. }
  646. /* extract the number of entries */
  647. SAFE_PHAR_GET_32(buffer, endbuffer, manifest_count);
  648. if (manifest_count == 0) {
  649. MAPPHAR_FAIL("in phar \"%s\", manifest claims to have zero entries. Phars must have at least 1 entry");
  650. }
  651. /* extract API version, lowest nibble currently unused */
  652. manifest_ver = (((unsigned char)buffer[0]) << 8)
  653. + ((unsigned char)buffer[1]);
  654. buffer += 2;
  655. if ((manifest_ver & PHAR_API_VER_MASK) < PHAR_API_MIN_READ) {
  656. efree(savebuf);
  657. php_stream_close(fp);
  658. if (error) {
  659. spprintf(error, 0, "phar \"%s\" is API version %1.u.%1.u.%1.u, and cannot be processed", fname, manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0x0F);
  660. }
  661. return FAILURE;
  662. }
  663. SAFE_PHAR_GET_32(buffer, endbuffer, manifest_flags);
  664. manifest_flags &= ~PHAR_HDR_COMPRESSION_MASK;
  665. manifest_flags &= ~PHAR_FILE_COMPRESSION_MASK;
  666. /* remember whether this entire phar was compressed with gz/bzip2 */
  667. manifest_flags |= compression;
  668. /* The lowest nibble contains the phar wide flags. The compression flags can */
  669. /* be ignored on reading because it is being generated anyways. */
  670. if (manifest_flags & PHAR_HDR_SIGNATURE) {
  671. char sig_buf[8], *sig_ptr = sig_buf;
  672. zend_off_t read_len;
  673. size_t end_of_phar;
  674. if (-1 == php_stream_seek(fp, -8, SEEK_END)
  675. || (read_len = php_stream_tell(fp)) < 20
  676. || 8 != php_stream_read(fp, sig_buf, 8)
  677. || memcmp(sig_buf+4, "GBMB", 4)) {
  678. efree(savebuf);
  679. php_stream_close(fp);
  680. if (error) {
  681. spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
  682. }
  683. return FAILURE;
  684. }
  685. PHAR_GET_32(sig_ptr, sig_flags);
  686. switch(sig_flags) {
  687. case PHAR_SIG_OPENSSL: {
  688. uint32_t signature_len;
  689. char *sig;
  690. zend_off_t whence;
  691. /* we store the signature followed by the signature length */
  692. if (-1 == php_stream_seek(fp, -12, SEEK_CUR)
  693. || 4 != php_stream_read(fp, sig_buf, 4)) {
  694. efree(savebuf);
  695. php_stream_close(fp);
  696. if (error) {
  697. spprintf(error, 0, "phar \"%s\" openssl signature length could not be read", fname);
  698. }
  699. return FAILURE;
  700. }
  701. sig_ptr = sig_buf;
  702. PHAR_GET_32(sig_ptr, signature_len);
  703. sig = (char *) emalloc(signature_len);
  704. whence = signature_len + 4;
  705. whence = -whence;
  706. if (-1 == php_stream_seek(fp, whence, SEEK_CUR)
  707. || !(end_of_phar = php_stream_tell(fp))
  708. || signature_len != php_stream_read(fp, sig, signature_len)) {
  709. efree(savebuf);
  710. efree(sig);
  711. php_stream_close(fp);
  712. if (error) {
  713. spprintf(error, 0, "phar \"%s\" openssl signature could not be read", fname);
  714. }
  715. return FAILURE;
  716. }
  717. if (FAILURE == phar_verify_signature(fp, end_of_phar, PHAR_SIG_OPENSSL, sig, signature_len, fname, &signature, &sig_len, error)) {
  718. efree(savebuf);
  719. efree(sig);
  720. php_stream_close(fp);
  721. if (error) {
  722. char *save = *error;
  723. spprintf(error, 0, "phar \"%s\" openssl signature could not be verified: %s", fname, *error);
  724. efree(save);
  725. }
  726. return FAILURE;
  727. }
  728. efree(sig);
  729. }
  730. break;
  731. case PHAR_SIG_SHA512: {
  732. unsigned char digest[64];
  733. php_stream_seek(fp, -(8 + 64), SEEK_END);
  734. read_len = php_stream_tell(fp);
  735. if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
  736. efree(savebuf);
  737. php_stream_close(fp);
  738. if (error) {
  739. spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
  740. }
  741. return FAILURE;
  742. }
  743. if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA512, (char *)digest, 64, fname, &signature, &sig_len, error)) {
  744. efree(savebuf);
  745. php_stream_close(fp);
  746. if (error) {
  747. char *save = *error;
  748. spprintf(error, 0, "phar \"%s\" SHA512 signature could not be verified: %s", fname, *error);
  749. efree(save);
  750. }
  751. return FAILURE;
  752. }
  753. break;
  754. }
  755. case PHAR_SIG_SHA256: {
  756. unsigned char digest[32];
  757. php_stream_seek(fp, -(8 + 32), SEEK_END);
  758. read_len = php_stream_tell(fp);
  759. if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
  760. efree(savebuf);
  761. php_stream_close(fp);
  762. if (error) {
  763. spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
  764. }
  765. return FAILURE;
  766. }
  767. if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA256, (char *)digest, 32, fname, &signature, &sig_len, error)) {
  768. efree(savebuf);
  769. php_stream_close(fp);
  770. if (error) {
  771. char *save = *error;
  772. spprintf(error, 0, "phar \"%s\" SHA256 signature could not be verified: %s", fname, *error);
  773. efree(save);
  774. }
  775. return FAILURE;
  776. }
  777. break;
  778. }
  779. case PHAR_SIG_SHA1: {
  780. unsigned char digest[20];
  781. php_stream_seek(fp, -(8 + 20), SEEK_END);
  782. read_len = php_stream_tell(fp);
  783. if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
  784. efree(savebuf);
  785. php_stream_close(fp);
  786. if (error) {
  787. spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
  788. }
  789. return FAILURE;
  790. }
  791. if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA1, (char *)digest, 20, fname, &signature, &sig_len, error)) {
  792. efree(savebuf);
  793. php_stream_close(fp);
  794. if (error) {
  795. char *save = *error;
  796. spprintf(error, 0, "phar \"%s\" SHA1 signature could not be verified: %s", fname, *error);
  797. efree(save);
  798. }
  799. return FAILURE;
  800. }
  801. break;
  802. }
  803. case PHAR_SIG_MD5: {
  804. unsigned char digest[16];
  805. php_stream_seek(fp, -(8 + 16), SEEK_END);
  806. read_len = php_stream_tell(fp);
  807. if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
  808. efree(savebuf);
  809. php_stream_close(fp);
  810. if (error) {
  811. spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
  812. }
  813. return FAILURE;
  814. }
  815. if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_MD5, (char *)digest, 16, fname, &signature, &sig_len, error)) {
  816. efree(savebuf);
  817. php_stream_close(fp);
  818. if (error) {
  819. char *save = *error;
  820. spprintf(error, 0, "phar \"%s\" MD5 signature could not be verified: %s", fname, *error);
  821. efree(save);
  822. }
  823. return FAILURE;
  824. }
  825. break;
  826. }
  827. default:
  828. efree(savebuf);
  829. php_stream_close(fp);
  830. if (error) {
  831. spprintf(error, 0, "phar \"%s\" has a broken or unsupported signature", fname);
  832. }
  833. return FAILURE;
  834. }
  835. } else if (PHAR_G(require_hash)) {
  836. efree(savebuf);
  837. php_stream_close(fp);
  838. if (error) {
  839. spprintf(error, 0, "phar \"%s\" does not have a signature", fname);
  840. }
  841. return FAILURE;
  842. } else {
  843. sig_flags = 0;
  844. sig_len = 0;
  845. }
  846. /* extract alias */
  847. SAFE_PHAR_GET_32(buffer, endbuffer, tmp_len);
  848. if (buffer + tmp_len > endbuffer) {
  849. MAPPHAR_FAIL("internal corruption of phar \"%s\" (buffer overrun)");
  850. }
  851. if (manifest_len < MANIFEST_FIXED_LEN + tmp_len) {
  852. MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)")
  853. }
  854. /* tmp_len = 0 says alias length is 0, which means the alias is not stored in the phar */
  855. if (tmp_len) {
  856. /* if the alias is stored we enforce it (implicit overrides explicit) */
  857. if (alias && alias_len && (alias_len != tmp_len || strncmp(alias, buffer, tmp_len)))
  858. {
  859. php_stream_close(fp);
  860. if (signature) {
  861. efree(signature);
  862. }
  863. if (error) {
  864. spprintf(error, 0, "cannot load phar \"%s\" with implicit alias \"%.*s\" under different alias \"%s\"", fname, tmp_len, buffer, alias);
  865. }
  866. efree(savebuf);
  867. return FAILURE;
  868. }
  869. alias_len = tmp_len;
  870. alias = buffer;
  871. buffer += tmp_len;
  872. register_alias = 1;
  873. } else if (!alias_len || !alias) {
  874. /* if we neither have an explicit nor an implicit alias, we use the filename */
  875. alias = NULL;
  876. alias_len = 0;
  877. register_alias = 0;
  878. } else if (alias_len) {
  879. register_alias = 1;
  880. temp_alias = 1;
  881. }
  882. /* we have 5 32-bit items plus 1 byte at least */
  883. if (manifest_count > ((manifest_len - MANIFEST_FIXED_LEN - tmp_len) / (5 * 4 + 1))) {
  884. /* prevent serious memory issues */
  885. MAPPHAR_FAIL("internal corruption of phar \"%s\" (too many manifest entries for size of manifest)")
  886. }
  887. mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
  888. mydata->is_persistent = PHAR_G(persist);
  889. /* check whether we have meta data, zero check works regardless of byte order */
  890. SAFE_PHAR_GET_32(buffer, endbuffer, len);
  891. if (mydata->is_persistent) {
  892. mydata->metadata_len = len;
  893. if (!len) {
  894. /* FIXME: not sure why this is needed but removing it breaks tests */
  895. SAFE_PHAR_GET_32(buffer, endbuffer, len);
  896. }
  897. }
  898. if(len > (size_t)(endbuffer - buffer)) {
  899. MAPPHAR_FAIL("internal corruption of phar \"%s\" (trying to read past buffer end)");
  900. }
  901. if (phar_parse_metadata(&buffer, &mydata->metadata, len) == FAILURE) {
  902. MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
  903. }
  904. buffer += len;
  905. /* set up our manifest */
  906. zend_hash_init(&mydata->manifest, manifest_count,
  907. zend_get_hash_value, destroy_phar_manifest_entry, (zend_bool)mydata->is_persistent);
  908. zend_hash_init(&mydata->mounted_dirs, 5,
  909. zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
  910. zend_hash_init(&mydata->virtual_dirs, manifest_count * 2,
  911. zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
  912. mydata->fname = pestrndup(fname, fname_len, mydata->is_persistent);
  913. #ifdef PHP_WIN32
  914. phar_unixify_path_separators(mydata->fname, fname_len);
  915. #endif
  916. mydata->fname_len = fname_len;
  917. offset = halt_offset + manifest_len + 4;
  918. memset(&entry, 0, sizeof(phar_entry_info));
  919. entry.phar = mydata;
  920. entry.fp_type = PHAR_FP;
  921. entry.is_persistent = mydata->is_persistent;
  922. for (manifest_index = 0; manifest_index < manifest_count; ++manifest_index) {
  923. if (buffer + 28 > endbuffer) {
  924. MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)")
  925. }
  926. PHAR_GET_32(buffer, entry.filename_len);
  927. if (entry.filename_len == 0) {
  928. MAPPHAR_FAIL("zero-length filename encountered in phar \"%s\"");
  929. }
  930. if (entry.is_persistent) {
  931. entry.manifest_pos = manifest_index;
  932. }
  933. if (entry.filename_len > (size_t)(endbuffer - buffer - 24)) {
  934. MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
  935. }
  936. if ((manifest_ver & PHAR_API_VER_MASK) >= PHAR_API_MIN_DIR && buffer[entry.filename_len - 1] == '/') {
  937. entry.is_dir = 1;
  938. } else {
  939. entry.is_dir = 0;
  940. }
  941. phar_add_virtual_dirs(mydata, buffer, entry.filename_len);
  942. entry.filename = pestrndup(buffer, entry.filename_len, entry.is_persistent);
  943. buffer += entry.filename_len;
  944. PHAR_GET_32(buffer, entry.uncompressed_filesize);
  945. PHAR_GET_32(buffer, entry.timestamp);
  946. if (offset == halt_offset + manifest_len + 4) {
  947. mydata->min_timestamp = entry.timestamp;
  948. mydata->max_timestamp = entry.timestamp;
  949. } else {
  950. if (mydata->min_timestamp > entry.timestamp) {
  951. mydata->min_timestamp = entry.timestamp;
  952. } else if (mydata->max_timestamp < entry.timestamp) {
  953. mydata->max_timestamp = entry.timestamp;
  954. }
  955. }
  956. PHAR_GET_32(buffer, entry.compressed_filesize);
  957. PHAR_GET_32(buffer, entry.crc32);
  958. PHAR_GET_32(buffer, entry.flags);
  959. if (entry.is_dir) {
  960. entry.filename_len--;
  961. entry.flags |= PHAR_ENT_PERM_DEF_DIR;
  962. }
  963. PHAR_GET_32(buffer, len);
  964. if (entry.is_persistent) {
  965. entry.metadata_len = len;
  966. } else {
  967. entry.metadata_len = 0;
  968. }
  969. if (len > (size_t)(endbuffer - buffer)) {
  970. pefree(entry.filename, entry.is_persistent);
  971. MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
  972. }
  973. if (phar_parse_metadata(&buffer, &entry.metadata, len) == FAILURE) {
  974. pefree(entry.filename, entry.is_persistent);
  975. MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
  976. }
  977. buffer += len;
  978. entry.offset = entry.offset_abs = offset;
  979. offset += entry.compressed_filesize;
  980. switch (entry.flags & PHAR_ENT_COMPRESSION_MASK) {
  981. case PHAR_ENT_COMPRESSED_GZ:
  982. if (!PHAR_G(has_zlib)) {
  983. if (Z_TYPE(entry.metadata) != IS_UNDEF) {
  984. if (entry.is_persistent) {
  985. free(Z_PTR(entry.metadata));
  986. } else {
  987. zval_ptr_dtor(&entry.metadata);
  988. }
  989. }
  990. pefree(entry.filename, entry.is_persistent);
  991. MAPPHAR_FAIL("zlib extension is required for gz compressed .phar file \"%s\"");
  992. }
  993. break;
  994. case PHAR_ENT_COMPRESSED_BZ2:
  995. if (!PHAR_G(has_bz2)) {
  996. if (Z_TYPE(entry.metadata) != IS_UNDEF) {
  997. if (entry.is_persistent) {
  998. free(Z_PTR(entry.metadata));
  999. } else {
  1000. zval_ptr_dtor(&entry.metadata);
  1001. }
  1002. }
  1003. pefree(entry.filename, entry.is_persistent);
  1004. MAPPHAR_FAIL("bz2 extension is required for bzip2 compressed .phar file \"%s\"");
  1005. }
  1006. break;
  1007. default:
  1008. if (entry.uncompressed_filesize != entry.compressed_filesize) {
  1009. if (Z_TYPE(entry.metadata) != IS_UNDEF) {
  1010. if (entry.is_persistent) {
  1011. free(Z_PTR(entry.metadata));
  1012. } else {
  1013. zval_ptr_dtor(&entry.metadata);
  1014. }
  1015. }
  1016. pefree(entry.filename, entry.is_persistent);
  1017. MAPPHAR_FAIL("internal corruption of phar \"%s\" (compressed and uncompressed size does not match for uncompressed entry)");
  1018. }
  1019. break;
  1020. }
  1021. manifest_flags |= (entry.flags & PHAR_ENT_COMPRESSION_MASK);
  1022. /* if signature matched, no need to check CRC32 for each file */
  1023. entry.is_crc_checked = (manifest_flags & PHAR_HDR_SIGNATURE ? 1 : 0);
  1024. phar_set_inode(&entry);
  1025. if (mydata->is_persistent) {
  1026. str = zend_string_init_interned(entry.filename, entry.filename_len, 1);
  1027. } else {
  1028. str = zend_string_init(entry.filename, entry.filename_len, 0);
  1029. }
  1030. zend_hash_add_mem(&mydata->manifest, str, (void*)&entry, sizeof(phar_entry_info));
  1031. zend_string_release(str);
  1032. }
  1033. snprintf(mydata->version, sizeof(mydata->version), "%u.%u.%u", manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0xF);
  1034. mydata->internal_file_start = halt_offset + manifest_len + 4;
  1035. mydata->halt_offset = halt_offset;
  1036. mydata->flags = manifest_flags;
  1037. endbuffer = strrchr(mydata->fname, '/');
  1038. if (endbuffer) {
  1039. mydata->ext = memchr(endbuffer, '.', (mydata->fname + fname_len) - endbuffer);
  1040. if (mydata->ext == endbuffer) {
  1041. mydata->ext = memchr(endbuffer + 1, '.', (mydata->fname + fname_len) - endbuffer - 1);
  1042. }
  1043. if (mydata->ext) {
  1044. mydata->ext_len = (mydata->fname + mydata->fname_len) - mydata->ext;
  1045. }
  1046. }
  1047. mydata->alias = alias ?
  1048. pestrndup(alias, alias_len, mydata->is_persistent) :
  1049. pestrndup(mydata->fname, fname_len, mydata->is_persistent);
  1050. mydata->alias_len = alias ? alias_len : fname_len;
  1051. mydata->sig_flags = sig_flags;
  1052. mydata->fp = fp;
  1053. mydata->sig_len = sig_len;
  1054. mydata->signature = signature;
  1055. phar_request_initialize();
  1056. if (register_alias) {
  1057. phar_archive_data *fd_ptr;
  1058. mydata->is_temporary_alias = temp_alias;
  1059. if (!phar_validate_alias(mydata->alias, mydata->alias_len)) {
  1060. signature = NULL;
  1061. fp = NULL;
  1062. MAPPHAR_FAIL("Cannot open archive \"%s\", invalid alias");
  1063. }
  1064. if (NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len))) {
  1065. if (SUCCESS != phar_free_alias(fd_ptr, alias, alias_len)) {
  1066. signature = NULL;
  1067. fp = NULL;
  1068. MAPPHAR_FAIL("Cannot open archive \"%s\", alias is already in use by existing archive");
  1069. }
  1070. }
  1071. if (mydata->is_persistent) {
  1072. str = zend_string_init_interned(alias, alias_len, 1);
  1073. } else {
  1074. str = zend_string_init(alias, alias_len, 0);
  1075. }
  1076. zend_hash_add_ptr(&(PHAR_G(phar_alias_map)), str, mydata);
  1077. zend_string_release(str);
  1078. } else {
  1079. mydata->is_temporary_alias = 1;
  1080. }
  1081. if (mydata->is_persistent) {
  1082. str = zend_string_init_interned(mydata->fname, fname_len, 1);
  1083. } else {
  1084. str = zend_string_init(mydata->fname, fname_len, 0);
  1085. }
  1086. zend_hash_add_ptr(&(PHAR_G(phar_fname_map)), str, mydata);
  1087. zend_string_release(str);
  1088. efree(savebuf);
  1089. if (pphar) {
  1090. *pphar = mydata;
  1091. }
  1092. return SUCCESS;
  1093. }
  1094. /* }}} */
  1095. /**
  1096. * Create or open a phar for writing
  1097. */
  1098. int phar_open_or_create_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, zend_bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
  1099. {
  1100. const char *ext_str, *z;
  1101. char *my_error;
  1102. size_t ext_len;
  1103. phar_archive_data **test, *unused = NULL;
  1104. test = &unused;
  1105. if (error) {
  1106. *error = NULL;
  1107. }
  1108. /* first try to open an existing file */
  1109. if (phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, !is_data, 0, 1) == SUCCESS) {
  1110. goto check_file;
  1111. }
  1112. /* next try to create a new file */
  1113. if (FAILURE == phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, !is_data, 1, 1)) {
  1114. if (error) {
  1115. if (ext_len == -2) {
  1116. spprintf(error, 0, "Cannot create a phar archive from a URL like \"%s\". Phar objects can only be created from local files", fname);
  1117. } else {
  1118. spprintf(error, 0, "Cannot create phar '%s', file extension (or combination) not recognised or the directory does not exist", fname);
  1119. }
  1120. }
  1121. return FAILURE;
  1122. }
  1123. check_file:
  1124. if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, is_data, options, test, &my_error) == SUCCESS) {
  1125. if (pphar) {
  1126. *pphar = *test;
  1127. }
  1128. if ((*test)->is_data && !(*test)->is_tar && !(*test)->is_zip) {
  1129. if (error) {
  1130. spprintf(error, 0, "Cannot open '%s' as a PharData object. Use Phar::__construct() for executable archives", fname);
  1131. }
  1132. return FAILURE;
  1133. }
  1134. if (PHAR_G(readonly) && !(*test)->is_data && ((*test)->is_tar || (*test)->is_zip)) {
  1135. phar_entry_info *stub;
  1136. if (NULL == (stub = zend_hash_str_find_ptr(&((*test)->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1))) {
  1137. spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
  1138. return FAILURE;
  1139. }
  1140. }
  1141. if (!PHAR_G(readonly) || (*test)->is_data) {
  1142. (*test)->is_writeable = 1;
  1143. }
  1144. return SUCCESS;
  1145. } else if (my_error) {
  1146. if (error) {
  1147. *error = my_error;
  1148. } else {
  1149. efree(my_error);
  1150. }
  1151. return FAILURE;
  1152. }
  1153. if (ext_len > 3 && (z = memchr(ext_str, 'z', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ip", 2)) {
  1154. /* assume zip-based phar */
  1155. return phar_open_or_create_zip(fname, fname_len, alias, alias_len, is_data, options, pphar, error);
  1156. }
  1157. if (ext_len > 3 && (z = memchr(ext_str, 't', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ar", 2)) {
  1158. /* assume tar-based phar */
  1159. return phar_open_or_create_tar(fname, fname_len, alias, alias_len, is_data, options, pphar, error);
  1160. }
  1161. return phar_create_or_parse_filename(fname, fname_len, alias, alias_len, is_data, options, pphar, error);
  1162. }
  1163. /* }}} */
  1164. int phar_create_or_parse_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, zend_bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
  1165. {
  1166. phar_archive_data *mydata;
  1167. php_stream *fp;
  1168. zend_string *actual = NULL;
  1169. char *p;
  1170. if (!pphar) {
  1171. pphar = &mydata;
  1172. }
  1173. if (php_check_open_basedir(fname)) {
  1174. return FAILURE;
  1175. }
  1176. /* first open readonly so it won't be created if not present */
  1177. fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, &actual);
  1178. if (actual) {
  1179. fname = ZSTR_VAL(actual);
  1180. fname_len = ZSTR_LEN(actual);
  1181. }
  1182. if (fp) {
  1183. if (phar_open_from_fp(fp, fname, fname_len, alias, alias_len, options, pphar, is_data, error) == SUCCESS) {
  1184. if ((*pphar)->is_data || !PHAR_G(readonly)) {
  1185. (*pphar)->is_writeable = 1;
  1186. }
  1187. if (actual) {
  1188. zend_string_release_ex(actual, 0);
  1189. }
  1190. return SUCCESS;
  1191. } else {
  1192. /* file exists, but is either corrupt or not a phar archive */
  1193. if (actual) {
  1194. zend_string_release_ex(actual, 0);
  1195. }
  1196. return FAILURE;
  1197. }
  1198. }
  1199. if (actual) {
  1200. zend_string_release_ex(actual, 0);
  1201. }
  1202. if (PHAR_G(readonly) && !is_data) {
  1203. if (options & REPORT_ERRORS) {
  1204. if (error) {
  1205. spprintf(error, 0, "creating archive \"%s\" disabled by the php.ini setting phar.readonly", fname);
  1206. }
  1207. }
  1208. return FAILURE;
  1209. }
  1210. /* set up our manifest */
  1211. mydata = ecalloc(1, sizeof(phar_archive_data));
  1212. mydata->fname = expand_filepath(fname, NULL);
  1213. if (mydata->fname == NULL) {
  1214. efree(mydata);
  1215. return FAILURE;
  1216. }
  1217. fname_len = strlen(mydata->fname);
  1218. #ifdef PHP_WIN32
  1219. phar_unixify_path_separators(mydata->fname, fname_len);
  1220. #endif
  1221. p = strrchr(mydata->fname, '/');
  1222. if (p) {
  1223. mydata->ext = memchr(p, '.', (mydata->fname + fname_len) - p);
  1224. if (mydata->ext == p) {
  1225. mydata->ext = memchr(p + 1, '.', (mydata->fname + fname_len) - p - 1);
  1226. }
  1227. if (mydata->ext) {
  1228. mydata->ext_len = (mydata->fname + fname_len) - mydata->ext;
  1229. }
  1230. }
  1231. if (pphar) {
  1232. *pphar = mydata;
  1233. }
  1234. zend_hash_init(&mydata->manifest, sizeof(phar_entry_info),
  1235. zend_get_hash_value, destroy_phar_manifest_entry, 0);
  1236. zend_hash_init(&mydata->mounted_dirs, sizeof(char *),
  1237. zend_get_hash_value, NULL, 0);
  1238. zend_hash_init(&mydata->virtual_dirs, sizeof(char *),
  1239. zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
  1240. mydata->fname_len = fname_len;
  1241. snprintf(mydata->version, sizeof(mydata->version), "%s", PHP_PHAR_API_VERSION);
  1242. mydata->is_temporary_alias = alias ? 0 : 1;
  1243. mydata->internal_file_start = -1;
  1244. mydata->fp = NULL;
  1245. mydata->is_writeable = 1;
  1246. mydata->is_brandnew = 1;
  1247. phar_request_initialize();
  1248. zend_hash_str_add_ptr(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len, mydata);
  1249. if (is_data) {
  1250. alias = NULL;
  1251. alias_len = 0;
  1252. mydata->is_data = 1;
  1253. /* assume tar format, PharData can specify other */
  1254. mydata->is_tar = 1;
  1255. } else {
  1256. phar_archive_data *fd_ptr;
  1257. if (alias && NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len))) {
  1258. if (SUCCESS != phar_free_alias(fd_ptr, alias, alias_len)) {
  1259. if (error) {
  1260. spprintf(error, 4096, "phar error: phar \"%s\" cannot set alias \"%s\", already in use by another phar archive", mydata->fname, alias);
  1261. }
  1262. zend_hash_str_del(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len);
  1263. if (pphar) {
  1264. *pphar = NULL;
  1265. }
  1266. return FAILURE;
  1267. }
  1268. }
  1269. mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len);
  1270. mydata->alias_len = alias ? alias_len : fname_len;
  1271. }
  1272. if (alias_len && alias) {
  1273. if (NULL == zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, mydata)) {
  1274. if (options & REPORT_ERRORS) {
  1275. if (error) {
  1276. spprintf(error, 0, "archive \"%s\" cannot be associated with alias \"%s\", already in use", fname, alias);
  1277. }
  1278. }
  1279. zend_hash_str_del(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len);
  1280. if (pphar) {
  1281. *pphar = NULL;
  1282. }
  1283. return FAILURE;
  1284. }
  1285. }
  1286. return SUCCESS;
  1287. }
  1288. /* }}}*/
  1289. /**
  1290. * Return an already opened filename.
  1291. *
  1292. * Or scan a phar file for the required __HALT_COMPILER(); ?> token and verify
  1293. * that the manifest is proper, then pass it to phar_parse_pharfile(). SUCCESS
  1294. * or FAILURE is returned and pphar is set to a pointer to the phar's manifest
  1295. */
  1296. int phar_open_from_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
  1297. {
  1298. php_stream *fp;
  1299. zend_string *actual;
  1300. int ret, is_data = 0;
  1301. if (error) {
  1302. *error = NULL;
  1303. }
  1304. if (!strstr(fname, ".phar")) {
  1305. is_data = 1;
  1306. }
  1307. if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, is_data, options, pphar, error) == SUCCESS) {
  1308. return SUCCESS;
  1309. } else if (error && *error) {
  1310. return FAILURE;
  1311. }
  1312. if (php_check_open_basedir(fname)) {
  1313. return FAILURE;
  1314. }
  1315. fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK, &actual);
  1316. if (!fp) {
  1317. if (options & REPORT_ERRORS) {
  1318. if (error) {
  1319. spprintf(error, 0, "unable to open phar for reading \"%s\"", fname);
  1320. }
  1321. }
  1322. if (actual) {
  1323. zend_string_release_ex(actual, 0);
  1324. }
  1325. return FAILURE;
  1326. }
  1327. if (actual) {
  1328. fname = ZSTR_VAL(actual);
  1329. fname_len = ZSTR_LEN(actual);
  1330. }
  1331. ret = phar_open_from_fp(fp, fname, fname_len, alias, alias_len, options, pphar, is_data, error);
  1332. if (actual) {
  1333. zend_string_release_ex(actual, 0);
  1334. }
  1335. return ret;
  1336. }
  1337. /* }}}*/
  1338. static inline char *phar_strnstr(const char *buf, int buf_len, const char *search, int search_len) /* {{{ */
  1339. {
  1340. const char *c;
  1341. ptrdiff_t so_far = 0;
  1342. if (buf_len < search_len) {
  1343. return NULL;
  1344. }
  1345. c = buf - 1;
  1346. do {
  1347. if (!(c = memchr(c + 1, search[0], buf_len - search_len - so_far))) {
  1348. return (char *) NULL;
  1349. }
  1350. so_far = c - buf;
  1351. if (so_far >= (buf_len - search_len)) {
  1352. return (char *) NULL;
  1353. }
  1354. if (!memcmp(c, search, search_len)) {
  1355. return (char *) c;
  1356. }
  1357. } while (1);
  1358. }
  1359. /* }}} */
  1360. /**
  1361. * Scan an open fp for the required __HALT_COMPILER(); ?> token and verify
  1362. * that the manifest is proper, then pass it to phar_parse_pharfile(). SUCCESS
  1363. * or FAILURE is returned and pphar is set to a pointer to the phar's manifest
  1364. */
  1365. static int phar_open_from_fp(php_stream* fp, char *fname, size_t fname_len, char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, int is_data, char **error) /* {{{ */
  1366. {
  1367. const char token[] = "__HALT_COMPILER();";
  1368. const char zip_magic[] = "PK\x03\x04";
  1369. const char gz_magic[] = "\x1f\x8b\x08";
  1370. const char bz_magic[] = "BZh";
  1371. char *pos, test = '\0';
  1372. const int window_size = 1024;
  1373. char buffer[1024 + sizeof(token)]; /* a 1024 byte window + the size of the halt_compiler token (moving window) */
  1374. const zend_long readsize = sizeof(buffer) - sizeof(token);
  1375. const zend_long tokenlen = sizeof(token) - 1;
  1376. zend_long halt_offset;
  1377. size_t got;
  1378. uint32_t compression = PHAR_FILE_COMPRESSED_NONE;
  1379. if (error) {
  1380. *error = NULL;
  1381. }
  1382. if (-1 == php_stream_rewind(fp)) {
  1383. MAPPHAR_ALLOC_FAIL("cannot rewind phar \"%s\"")
  1384. }
  1385. buffer[sizeof(buffer)-1] = '\0';
  1386. memset(buffer, 32, sizeof(token));
  1387. halt_offset = 0;
  1388. /* Maybe it's better to compile the file instead of just searching, */
  1389. /* but we only want the offset. So we want a .re scanner to find it. */
  1390. while(!php_stream_eof(fp)) {
  1391. if ((got = php_stream_read(fp, buffer+tokenlen, readsize)) < (size_t) tokenlen) {
  1392. MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated entry)")
  1393. }
  1394. if (!test) {
  1395. test = '\1';
  1396. pos = buffer+tokenlen;
  1397. if (!memcmp(pos, gz_magic, 3)) {
  1398. char err = 0;
  1399. php_stream_filter *filter;
  1400. php_stream *temp;
  1401. /* to properly decompress, we have to tell zlib to look for a zlib or gzip header */
  1402. zval filterparams;
  1403. if (!PHAR_G(has_zlib)) {
  1404. MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file, enable zlib extension in php.ini")
  1405. }
  1406. array_init(&filterparams);
  1407. /* this is defined in zlib's zconf.h */
  1408. #ifndef MAX_WBITS
  1409. #define MAX_WBITS 15
  1410. #endif
  1411. add_assoc_long_ex(&filterparams, "window", sizeof("window") - 1, MAX_WBITS + 32);
  1412. /* entire file is gzip-compressed, uncompress to temporary file */
  1413. if (!(temp = php_stream_fopen_tmpfile())) {
  1414. MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of gzipped phar archive \"%s\"")
  1415. }
  1416. php_stream_rewind(fp);
  1417. filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp));
  1418. if (!filter) {
  1419. err = 1;
  1420. add_assoc_long_ex(&filterparams, "window", sizeof("window") - 1, MAX_WBITS);
  1421. filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp));
  1422. zend_array_destroy(Z_ARR(filterparams));
  1423. if (!filter) {
  1424. php_stream_close(temp);
  1425. MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6")
  1426. }
  1427. } else {
  1428. zend_array_destroy(Z_ARR(filterparams));
  1429. }
  1430. php_stream_filter_append(&temp->writefilters, filter);
  1431. if (SUCCESS != php_stream_copy_to_stream_ex(fp, temp, PHP_STREAM_COPY_ALL, NULL)) {
  1432. if (err) {
  1433. php_stream_close(temp);
  1434. MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6")
  1435. }
  1436. php_stream_close(temp);
  1437. MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file")
  1438. }
  1439. php_stream_filter_flush(filter, 1);
  1440. php_stream_filter_remove(filter, 1);
  1441. php_stream_close(fp);
  1442. fp = temp;
  1443. php_stream_rewind(fp);
  1444. compression = PHAR_FILE_COMPRESSED_GZ;
  1445. /* now, start over */
  1446. test = '\0';
  1447. continue;
  1448. } else if (!memcmp(pos, bz_magic, 3)) {
  1449. php_stream_filter *filter;
  1450. php_stream *temp;
  1451. if (!PHAR_G(has_bz2)) {
  1452. MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file, enable bz2 extension in php.ini")
  1453. }
  1454. /* entire file is bzip-compressed, uncompress to temporary file */
  1455. if (!(temp = php_stream_fopen_tmpfile())) {
  1456. MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of bzipped phar archive \"%s\"")
  1457. }
  1458. php_stream_rewind(fp);
  1459. filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp));
  1460. if (!filter) {
  1461. php_stream_close(temp);
  1462. MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\", filter creation failed")
  1463. }
  1464. php_stream_filter_append(&temp->writefilters, filter);
  1465. if (SUCCESS != php_stream_copy_to_stream_ex(fp, temp, PHP_STREAM_COPY_ALL, NULL)) {
  1466. php_stream_close(temp);
  1467. MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file")
  1468. }
  1469. php_stream_filter_flush(filter, 1);
  1470. php_stream_filter_remove(filter, 1);
  1471. php_stream_close(fp);
  1472. fp = temp;
  1473. php_stream_rewind(fp);
  1474. compression = PHAR_FILE_COMPRESSED_BZ2;
  1475. /* now, start over …

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