root/ext/opcache/zend_file_cache.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zend_file_cache_flock
  2. zend_file_cache_flock
  3. zend_file_cache_mkdir
  4. zend_file_cache_serialize_interned
  5. zend_file_cache_unserialize_interned
  6. zend_file_cache_serialize_hash
  7. zend_file_cache_serialize_ast
  8. zend_file_cache_serialize_zval
  9. zend_file_cache_serialize_op_array
  10. zend_file_cache_serialize_func
  11. zend_file_cache_serialize_prop_info
  12. zend_file_cache_serialize_class
  13. zend_file_cache_serialize
  14. zend_file_cache_get_bin_file_path
  15. zend_file_cache_script_store
  16. zend_file_cache_unserialize_hash
  17. zend_file_cache_unserialize_ast
  18. zend_file_cache_unserialize_zval
  19. zend_file_cache_unserialize_op_array
  20. zend_file_cache_unserialize_func
  21. zend_file_cache_unserialize_prop_info
  22. zend_file_cache_unserialize_class
  23. zend_file_cache_unserialize
  24. zend_file_cache_script_load
  25. zend_file_cache_invalidate

   1 /*
   2    +----------------------------------------------------------------------+
   3    | Zend OPcache                                                         |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1998-2016 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: Dmitry Stogov <dmitry@zend.com>                             |
  16    +----------------------------------------------------------------------+
  17 */
  18 
  19 #include "zend.h"
  20 #include "zend_virtual_cwd.h"
  21 #include "zend_compile.h"
  22 #include "zend_vm.h"
  23 #include "zend_interfaces.h"
  24 
  25 #include "php.h"
  26 
  27 #ifdef HAVE_OPCACHE_FILE_CACHE
  28 
  29 #include "ZendAccelerator.h"
  30 #include "zend_file_cache.h"
  31 #include "zend_shared_alloc.h"
  32 #include "zend_accelerator_util_funcs.h"
  33 #include "zend_accelerator_hash.h"
  34 
  35 #include <sys/types.h>
  36 #include <sys/stat.h>
  37 #include <fcntl.h>
  38 
  39 #if HAVE_UNISTD_H
  40 #include <unistd.h>
  41 #endif
  42 
  43 #ifdef HAVE_SYS_UIO_H
  44 # include <sys/uio.h>
  45 #endif
  46 
  47 #ifdef HAVE_SYS_FILE_H
  48 # include <sys/file.h>
  49 #endif
  50 
  51 #ifdef ZEND_WIN32
  52 # define LOCK_SH 0
  53 # define LOCK_EX 1
  54 # define LOCK_UN 2
  55 static int zend_file_cache_flock(int fd, int op)
  56 {
  57         OVERLAPPED offset = {0,0,0,0,NULL};
  58         if (op == LOCK_EX) {
  59                 if (LockFileEx((HANDLE)_get_osfhandle(fd),
  60                                LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &offset) == TRUE) {
  61                         return 0;
  62                 }
  63         } else if (op == LOCK_SH) {
  64                 if (LockFileEx((HANDLE)_get_osfhandle(fd),
  65                                0, 0, 1, 0, &offset) == TRUE) {
  66                         return 0;
  67                 }
  68         } else if (op == LOCK_UN) {
  69                 if (UnlockFileEx((HANDLE)_get_osfhandle(fd),
  70                                  0, 1, 0, &offset) == TRUE) {
  71                         return 0;
  72                 }
  73         }
  74         return -1;
  75 }
  76 #elif defined(HAVE_FLOCK)
  77 # define zend_file_cache_flock flock
  78 #else
  79 # define LOCK_SH 0
  80 # define LOCK_EX 1
  81 # define LOCK_UN 2
  82 static int zend_file_cache_flock(int fd, int type)
  83 {
  84         return 0;
  85 }
  86 #endif
  87 
  88 #ifndef O_BINARY
  89 #  define O_BINARY 0
  90 #endif
  91 
  92 #define SUFFIX ".bin"
  93 
  94 #define IS_SERIALIZED_INTERNED(ptr) \
  95         ((size_t)(ptr) & Z_UL(1))
  96 #define IS_SERIALIZED(ptr) \
  97         ((char*)(ptr) < (char*)script->size)
  98 #define IS_UNSERIALIZED(ptr) \
  99         (((char*)(ptr) >= (char*)script->mem && (char*)(ptr) < (char*)script->mem + script->size) || \
 100          IS_ACCEL_INTERNED(ptr))
 101 #define SERIALIZE_PTR(ptr) do { \
 102                 if (ptr) { \
 103                         ZEND_ASSERT(IS_UNSERIALIZED(ptr)); \
 104                         (ptr) = (void*)((char*)(ptr) - (char*)script->mem); \
 105                 } \
 106         } while (0)
 107 #define UNSERIALIZE_PTR(ptr) do { \
 108                 if (ptr) { \
 109                         ZEND_ASSERT(IS_SERIALIZED(ptr)); \
 110                         (ptr) = (void*)((char*)buf + (size_t)(ptr)); \
 111                 } \
 112         } while (0)
 113 #define SERIALIZE_STR(ptr) do { \
 114                 if (ptr) { \
 115                         if (IS_ACCEL_INTERNED(ptr)) { \
 116                                 (ptr) = zend_file_cache_serialize_interned((zend_string*)(ptr), info); \
 117                         } else { \
 118                                 ZEND_ASSERT(IS_UNSERIALIZED(ptr)); \
 119                                 /* script->corrupted shows if the script in SHM or not */ \
 120                                 if (EXPECTED(script->corrupted)) { \
 121                                         GC_FLAGS(ptr) |= IS_STR_INTERNED; \
 122                                         GC_FLAGS(ptr) &= ~IS_STR_PERMANENT; \
 123                                 } \
 124                                 (ptr) = (void*)((char*)(ptr) - (char*)script->mem); \
 125                         } \
 126                 } \
 127         } while (0)
 128 #define UNSERIALIZE_STR(ptr) do { \
 129                 if (ptr) { \
 130                         if (IS_SERIALIZED_INTERNED(ptr)) { \
 131                                 (ptr) = (void*)zend_file_cache_unserialize_interned((zend_string*)(ptr), !script->corrupted); \
 132                         } else { \
 133                                 ZEND_ASSERT(IS_SERIALIZED(ptr)); \
 134                                 (ptr) = (void*)((char*)buf + (size_t)(ptr)); \
 135                                 /* script->corrupted shows if the script in SHM or not */ \
 136                                 if (EXPECTED(!script->corrupted)) { \
 137                                         GC_FLAGS(ptr) |= IS_STR_INTERNED | IS_STR_PERMANENT; \
 138                                 } else { \
 139                                         GC_FLAGS(ptr) |= IS_STR_INTERNED; \
 140                                         GC_FLAGS(ptr) &= ~IS_STR_PERMANENT; \
 141                                 } \
 142                         } \
 143                 } \
 144         } while (0)
 145 
 146 static const uint32_t uninitialized_bucket[-HT_MIN_MASK] =
 147         {HT_INVALID_IDX, HT_INVALID_IDX};
 148 
 149 typedef struct _zend_file_cache_metainfo {
 150         char         magic[8];
 151         char         system_id[32];
 152         size_t       mem_size;
 153         size_t       str_size;
 154         size_t       script_offset;
 155         accel_time_t timestamp;
 156         uint32_t     checksum;
 157 } zend_file_cache_metainfo;
 158 
 159 static int zend_file_cache_mkdir(char *filename, size_t start)
 160 {
 161         char *s = filename + start;
 162 
 163         while (*s) {
 164                 if (IS_SLASH(*s)) {
 165                         char old = *s;
 166                         *s = '\000';
 167                         if (mkdir(filename, S_IRWXU) < 0 && errno != EEXIST) {
 168                                 *s = old;
 169                                 return FAILURE;
 170                         }
 171                         *s = old;
 172                 }
 173                 s++;
 174         }
 175         return SUCCESS;
 176 }
 177 
 178 typedef void (*serialize_callback_t)(zval                     *zv,
 179                                      zend_persistent_script   *script,
 180                                      zend_file_cache_metainfo *info,
 181                                      void                     *buf);
 182 
 183 typedef void (*unserialize_callback_t)(zval                    *zv,
 184                                        zend_persistent_script  *script,
 185                                        void                    *buf);
 186 
 187 static void zend_file_cache_serialize_zval(zval                     *zv,
 188                                            zend_persistent_script   *script,
 189                                            zend_file_cache_metainfo *info,
 190                                            void                     *buf);
 191 static void zend_file_cache_unserialize_zval(zval                    *zv,
 192                                              zend_persistent_script  *script,
 193                                              void                    *buf);
 194 
 195 static void *zend_file_cache_serialize_interned(zend_string              *str,
 196                                                 zend_file_cache_metainfo *info)
 197 {
 198         size_t len;
 199         void *ret;
 200 
 201         /* check if the same interned string was already stored */
 202         ret = zend_shared_alloc_get_xlat_entry(str);
 203         if (ret) {
 204                 return ret;
 205         }
 206 
 207         len = ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(ZSTR_LEN(str)));
 208         ret = (void*)(info->str_size | Z_UL(1));
 209         zend_shared_alloc_register_xlat_entry(str, ret);
 210         if (info->str_size + len > ZSTR_LEN((zend_string*)ZCG(mem))) {
 211                 size_t new_len = info->str_size + len;
 212                 ZCG(mem) = (void*)zend_string_realloc(
 213                         (zend_string*)ZCG(mem),
 214                         ((_ZSTR_HEADER_SIZE + 1 + new_len + 4095) & ~0xfff) - (_ZSTR_HEADER_SIZE + 1),
 215                         0);
 216         }
 217         memcpy(ZSTR_VAL((zend_string*)ZCG(mem)) + info->str_size, str, len);
 218         info->str_size += len;
 219         return ret;
 220 }
 221 
 222 static void *zend_file_cache_unserialize_interned(zend_string *str, int in_shm)
 223 {
 224         zend_string *ret;
 225 
 226         str = (zend_string*)((char*)ZCG(mem) + ((size_t)(str) & ~Z_UL(1)));
 227         if (in_shm) {
 228                 ret = accel_new_interned_string(str);
 229                 if (ret == str) {
 230                         /* String wasn't interned but we will use it as interned anyway */
 231                         GC_FLAGS(ret) |= IS_STR_INTERNED | IS_STR_PERMANENT;
 232                 }
 233         } else {
 234                 ret = str;
 235                 GC_FLAGS(ret) |= IS_STR_INTERNED;
 236                 GC_FLAGS(ret) &= ~IS_STR_PERMANENT;
 237         }
 238         return ret;
 239 }
 240 
 241 static void zend_file_cache_serialize_hash(HashTable                *ht,
 242                                            zend_persistent_script   *script,
 243                                            zend_file_cache_metainfo *info,
 244                                            void                     *buf,
 245                                            serialize_callback_t      func)
 246 {
 247         Bucket *p, *end;
 248 
 249         if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
 250                 ht->arData = NULL;
 251                 return;
 252         }
 253         if (IS_SERIALIZED(ht->arData)) {
 254                 return;
 255         }
 256         SERIALIZE_PTR(ht->arData);
 257         p = ht->arData;
 258         UNSERIALIZE_PTR(p);
 259         end = p + ht->nNumUsed;
 260         while (p < end) {
 261                 if (Z_TYPE(p->val) != IS_UNDEF) {
 262                         SERIALIZE_STR(p->key);
 263                         func(&p->val, script, info, buf);
 264                 }
 265                 p++;
 266         }
 267 }
 268 
 269 static zend_ast *zend_file_cache_serialize_ast(zend_ast                 *ast,
 270                                                zend_persistent_script   *script,
 271                                                zend_file_cache_metainfo *info,
 272                                                void                     *buf)
 273 {
 274         uint32_t i;
 275         zend_ast *ret;
 276 
 277         SERIALIZE_PTR(ast);
 278         ret = ast;
 279         UNSERIALIZE_PTR(ast);
 280 
 281         if (ast->kind == ZEND_AST_ZVAL) {
 282                 zend_file_cache_serialize_zval(&((zend_ast_zval*)ast)->val, script, info, buf);
 283         } else if (zend_ast_is_list(ast)) {
 284                 zend_ast_list *list = zend_ast_get_list(ast);
 285                 for (i = 0; i < list->children; i++) {
 286                         if (list->child[i]) {
 287                                 list->child[i] = zend_file_cache_serialize_ast(list->child[i], script, info, buf);
 288                         }
 289                 }
 290         } else {
 291                 uint32_t children = zend_ast_get_num_children(ast);
 292                 for (i = 0; i < children; i++) {
 293                         if (ast->child[i]) {
 294                                 ast->child[i] = zend_file_cache_serialize_ast(ast->child[i], script, info, buf);
 295                         }
 296                 }
 297         }
 298         return ret;
 299 }
 300 
 301 static void zend_file_cache_serialize_zval(zval                     *zv,
 302                                            zend_persistent_script   *script,
 303                                            zend_file_cache_metainfo *info,
 304                                            void                     *buf)
 305 {
 306         switch (Z_TYPE_P(zv)) {
 307                 case IS_STRING:
 308                 case IS_CONSTANT:
 309                         if (!IS_SERIALIZED(Z_STR_P(zv))) {
 310                                 SERIALIZE_STR(Z_STR_P(zv));
 311                         }
 312                         break;
 313                 case IS_ARRAY:
 314                         if (!IS_SERIALIZED(Z_ARR_P(zv))) {
 315                                 HashTable *ht;
 316 
 317                                 SERIALIZE_PTR(Z_ARR_P(zv));
 318                                 ht = Z_ARR_P(zv);
 319                                 UNSERIALIZE_PTR(ht);
 320                                 zend_file_cache_serialize_hash(ht, script, info, buf, zend_file_cache_serialize_zval);
 321                         }
 322                         break;
 323                 case IS_REFERENCE:
 324                         if (!IS_SERIALIZED(Z_REF_P(zv))) {
 325                                 zend_reference *ref;
 326 
 327                                 SERIALIZE_PTR(Z_REF_P(zv));
 328                                 ref = Z_REF_P(zv);
 329                                 UNSERIALIZE_PTR(ref);
 330                                 zend_file_cache_serialize_zval(&ref->val, script, info, buf);
 331                         }
 332                         break;
 333                 case IS_CONSTANT_AST:
 334                         if (!IS_SERIALIZED(Z_AST_P(zv))) {
 335                                 zend_ast_ref *ast;
 336 
 337                                 SERIALIZE_PTR(Z_AST_P(zv));
 338                                 ast = Z_AST_P(zv);
 339                                 UNSERIALIZE_PTR(ast);
 340                                 if (!IS_SERIALIZED(ast->ast)) {
 341                                         ast->ast = zend_file_cache_serialize_ast(ast->ast, script, info, buf);
 342                                 }
 343                         }
 344                         break;
 345         }
 346 }
 347 
 348 static void zend_file_cache_serialize_op_array(zend_op_array            *op_array,
 349                                                zend_persistent_script   *script,
 350                                                zend_file_cache_metainfo *info,
 351                                                void                     *buf)
 352 {
 353         if (op_array->static_variables && !IS_SERIALIZED(op_array->static_variables)) {
 354                 HashTable *ht;
 355 
 356                 SERIALIZE_PTR(op_array->static_variables);
 357                 ht = op_array->static_variables;
 358                 UNSERIALIZE_PTR(ht);
 359                 zend_file_cache_serialize_hash(ht, script, info, buf, zend_file_cache_serialize_zval);
 360         }
 361 
 362         if (op_array->literals && !IS_SERIALIZED(op_array->literals)) {
 363                 zval *p, *end;
 364 
 365                 SERIALIZE_PTR(op_array->literals);
 366                 p = op_array->literals;
 367                 UNSERIALIZE_PTR(p);
 368                 end = p + op_array->last_literal;
 369                 while (p < end) {
 370                         zend_file_cache_serialize_zval(p, script, info, buf);
 371                         p++;
 372                 }
 373         }
 374 
 375         if (!IS_SERIALIZED(op_array->opcodes)) {
 376 #if ZEND_USE_ABS_CONST_ADDR || ZEND_USE_ABS_JMP_ADDR
 377                 zend_op *opline, *end;
 378 
 379                 SERIALIZE_PTR(op_array->opcodes);
 380                 opline = op_array->opcodes;
 381                 UNSERIALIZE_PTR(opline);
 382                 end = opline + op_array->last;
 383                 while (opline < end) {
 384 # if ZEND_USE_ABS_CONST_ADDR
 385                         if (ZEND_OP1_TYPE(opline) == IS_CONST) {
 386                                 SERIALIZE_PTR(opline->op1.zv);
 387                         }
 388                         if (ZEND_OP2_TYPE(opline) == IS_CONST) {
 389                                 SERIALIZE_PTR(opline->op2.zv);
 390                         }
 391 # endif
 392 # if ZEND_USE_ABS_JMP_ADDR
 393                         switch (opline->opcode) {
 394                                 case ZEND_JMP:
 395                                 case ZEND_FAST_CALL:
 396                                 case ZEND_DECLARE_ANON_CLASS:
 397                                 case ZEND_DECLARE_ANON_INHERITED_CLASS:
 398                                         SERIALIZE_PTR(opline->op1.jmp_addr);
 399                                         break;
 400                                 case ZEND_JMPZNZ:
 401                                         /* relative extended_value don't have to be changed */
 402                                         /* break omitted intentionally */
 403                                 case ZEND_JMPZ:
 404                                 case ZEND_JMPNZ:
 405                                 case ZEND_JMPZ_EX:
 406                                 case ZEND_JMPNZ_EX:
 407                                 case ZEND_JMP_SET:
 408                                 case ZEND_COALESCE:
 409                                 case ZEND_NEW:
 410                                 case ZEND_FE_RESET_R:
 411                                 case ZEND_FE_RESET_RW:
 412                                 case ZEND_ASSERT_CHECK:
 413                                         SERIALIZE_PTR(opline->op2.jmp_addr);
 414                                         break;
 415                                 case ZEND_FE_FETCH_R:
 416                                 case ZEND_FE_FETCH_RW:
 417                                         /* relative extended_value don't have to be changed */
 418                                         break;
 419                         }
 420 # endif
 421                         opline++;
 422                 }
 423 #else
 424                 SERIALIZE_PTR(op_array->opcodes);
 425 #endif
 426 
 427                 if (op_array->arg_info) {
 428                         zend_arg_info *p, *end;
 429                         SERIALIZE_PTR(op_array->arg_info);
 430                         p = op_array->arg_info;
 431                         UNSERIALIZE_PTR(p);
 432                         end = p + op_array->num_args;
 433                         if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
 434                                 p--;
 435                         }
 436                         if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
 437                                 end++;
 438                         }
 439                         while (p < end) {
 440                                 if (!IS_SERIALIZED(p->name)) {
 441                                         SERIALIZE_STR(p->name);
 442                                 }
 443                                 if (!IS_SERIALIZED(p->class_name)) {
 444                                         SERIALIZE_STR(p->class_name);
 445                                 }
 446                                 p++;
 447                         }
 448                 }
 449 
 450                 if (op_array->vars) {
 451                         zend_string **p, **end;
 452 
 453                         SERIALIZE_PTR(op_array->vars);
 454                         p = op_array->vars;
 455                         UNSERIALIZE_PTR(p);
 456                         end = p + op_array->last_var;
 457                         while (p < end) {
 458                                 if (!IS_SERIALIZED(*p)) {
 459                                         SERIALIZE_STR(*p);
 460                                 }
 461                                 p++;
 462                         }
 463                 }
 464 
 465                 SERIALIZE_STR(op_array->function_name);
 466                 SERIALIZE_STR(op_array->filename);
 467                 SERIALIZE_PTR(op_array->brk_cont_array);
 468                 SERIALIZE_PTR(op_array->scope);
 469                 SERIALIZE_STR(op_array->doc_comment);
 470                 SERIALIZE_PTR(op_array->try_catch_array);
 471                 SERIALIZE_PTR(op_array->prototype);
 472         }
 473 }
 474 
 475 static void zend_file_cache_serialize_func(zval                     *zv,
 476                                            zend_persistent_script   *script,
 477                                            zend_file_cache_metainfo *info,
 478                                            void                     *buf)
 479 {
 480         zend_op_array *op_array;
 481 
 482         SERIALIZE_PTR(Z_PTR_P(zv));
 483         op_array = Z_PTR_P(zv);
 484         UNSERIALIZE_PTR(op_array);
 485         zend_file_cache_serialize_op_array(op_array, script, info, buf);
 486 }
 487 
 488 static void zend_file_cache_serialize_prop_info(zval                     *zv,
 489                                                 zend_persistent_script   *script,
 490                                                 zend_file_cache_metainfo *info,
 491                                                 void                     *buf)
 492 {
 493         if (!IS_SERIALIZED(Z_PTR_P(zv))) {
 494                 zend_property_info *prop;
 495 
 496                 SERIALIZE_PTR(Z_PTR_P(zv));
 497                 prop = Z_PTR_P(zv);
 498                 UNSERIALIZE_PTR(prop);
 499 
 500                 if (prop->ce && !IS_SERIALIZED(prop->ce)) {
 501                         SERIALIZE_PTR(prop->ce);
 502                 }
 503                 if (prop->name && !IS_SERIALIZED(prop->name)) {
 504                         SERIALIZE_STR(prop->name);
 505                 }
 506                 if (prop->doc_comment && !IS_SERIALIZED(prop->doc_comment)) {
 507                         SERIALIZE_STR(prop->doc_comment);
 508                 }
 509         }
 510 }
 511 
 512 static void zend_file_cache_serialize_class(zval                     *zv,
 513                                             zend_persistent_script   *script,
 514                                             zend_file_cache_metainfo *info,
 515                                             void                     *buf)
 516 {
 517         zend_class_entry *ce;
 518 
 519         SERIALIZE_PTR(Z_PTR_P(zv));
 520         ce = Z_PTR_P(zv);
 521         UNSERIALIZE_PTR(ce);
 522 
 523         SERIALIZE_STR(ce->name);
 524         zend_file_cache_serialize_hash(&ce->function_table, script, info, buf, zend_file_cache_serialize_func);
 525         if (ce->default_properties_table) {
 526                 zval *p, *end;
 527 
 528                 SERIALIZE_PTR(ce->default_properties_table);
 529                 p = ce->default_properties_table;
 530                 UNSERIALIZE_PTR(p);
 531                 end = p + ce->default_properties_count;
 532                 while (p < end) {
 533                         zend_file_cache_serialize_zval(p, script, info, buf);
 534                         p++;
 535                 }
 536         }
 537         if (ce->default_static_members_table) {
 538                 zval *p, *end;
 539 
 540                 SERIALIZE_PTR(ce->default_static_members_table);
 541                 p = ce->default_static_members_table;
 542                 UNSERIALIZE_PTR(p);
 543                 end = p + ce->default_static_members_count;
 544                 while (p < end) {
 545                         zend_file_cache_serialize_zval(p, script, info, buf);
 546                         p++;
 547                 }
 548         }
 549         zend_file_cache_serialize_hash(&ce->constants_table, script, info, buf, zend_file_cache_serialize_zval);
 550         SERIALIZE_STR(ZEND_CE_FILENAME(ce));
 551         SERIALIZE_STR(ZEND_CE_DOC_COMMENT(ce));
 552         zend_file_cache_serialize_hash(&ce->properties_info, script, info, buf, zend_file_cache_serialize_prop_info);
 553 
 554         if (ce->trait_aliases) {
 555                 zend_trait_alias **p, *q;
 556 
 557                 SERIALIZE_PTR(ce->trait_aliases);
 558                 p = ce->trait_aliases;
 559                 UNSERIALIZE_PTR(p);
 560 
 561                 while (*p) {
 562                         SERIALIZE_PTR(*p);
 563                         q = *p;
 564                         UNSERIALIZE_PTR(q);
 565 
 566                         if (q->trait_method) {
 567                                 zend_trait_method_reference *m;
 568 
 569                                 SERIALIZE_PTR(q->trait_method);
 570                                 m = q->trait_method;
 571                                 UNSERIALIZE_PTR(m);
 572 
 573                                 if (m->method_name) {
 574                                         SERIALIZE_STR(m->method_name);
 575                                 }
 576                                 if (m->class_name) {
 577                                         SERIALIZE_STR(m->class_name);
 578                                 }
 579                         }
 580 
 581                         if (q->alias) {
 582                                 SERIALIZE_STR(q->alias);
 583                         }
 584                         p++;
 585                 }
 586         }
 587 
 588         if (ce->trait_precedences) {
 589                 zend_trait_precedence **p, *q;
 590 
 591                 SERIALIZE_PTR(ce->trait_precedences);
 592                 p = ce->trait_precedences;
 593                 UNSERIALIZE_PTR(p);
 594 
 595                 while (*p) {
 596                         SERIALIZE_PTR(*p);
 597                         q = *p;
 598                         UNSERIALIZE_PTR(q);
 599 
 600                         if (q->trait_method) {
 601                                 zend_trait_method_reference *m;
 602 
 603                                 SERIALIZE_PTR(q->trait_method);
 604                                 m = q->trait_method;
 605                                 UNSERIALIZE_PTR(m);
 606 
 607                                 if (m->method_name) {
 608                                         SERIALIZE_STR(m->method_name);
 609                                 }
 610                                 if (m->class_name) {
 611                                         SERIALIZE_STR(m->class_name);
 612                                 }
 613                         }
 614 
 615                         if (q->exclude_from_classes) {
 616                                 zend_string **s;
 617 
 618                                 SERIALIZE_PTR(q->exclude_from_classes);
 619                                 s = (zend_string**)q->exclude_from_classes;
 620                                 UNSERIALIZE_PTR(s);
 621 
 622                                 while (*s) {
 623                                         SERIALIZE_STR(*s);
 624                                         s++;
 625                                 }
 626                         }
 627                         p++;
 628                 }
 629         }
 630 
 631         SERIALIZE_PTR(ce->parent);
 632         SERIALIZE_PTR(ce->constructor);
 633         SERIALIZE_PTR(ce->destructor);
 634         SERIALIZE_PTR(ce->clone);
 635         SERIALIZE_PTR(ce->__get);
 636         SERIALIZE_PTR(ce->__set);
 637         SERIALIZE_PTR(ce->__call);
 638         SERIALIZE_PTR(ce->serialize_func);
 639         SERIALIZE_PTR(ce->unserialize_func);
 640         SERIALIZE_PTR(ce->__isset);
 641         SERIALIZE_PTR(ce->__unset);
 642         SERIALIZE_PTR(ce->__tostring);
 643         SERIALIZE_PTR(ce->__callstatic);
 644         SERIALIZE_PTR(ce->__debugInfo);
 645 }
 646 
 647 static void zend_file_cache_serialize(zend_persistent_script   *script,
 648                                       zend_file_cache_metainfo *info,
 649                                       void                     *buf)
 650 {
 651         zend_persistent_script *new_script;
 652 
 653         memcpy(info->magic, "OPCACHE", 8);
 654         memcpy(info->system_id, ZCG(system_id), 32);
 655         info->mem_size = script->size;
 656         info->str_size = 0;
 657         info->script_offset = (char*)script - (char*)script->mem;
 658         info->timestamp = script->timestamp;
 659 
 660         memcpy(buf, script->mem, script->size);
 661 
 662         new_script = (zend_persistent_script*)((char*)buf + info->script_offset);
 663         SERIALIZE_STR(new_script->full_path);
 664 
 665         zend_file_cache_serialize_hash(&new_script->class_table, script, info, buf, zend_file_cache_serialize_class);
 666         zend_file_cache_serialize_hash(&new_script->function_table, script, info, buf, zend_file_cache_serialize_func);
 667         zend_file_cache_serialize_op_array(&new_script->main_op_array, script, info, buf);
 668 
 669         SERIALIZE_PTR(new_script->arena_mem);
 670         new_script->mem = NULL;
 671 }
 672 
 673 static char *zend_file_cache_get_bin_file_path(zend_string *script_path)
 674 {
 675         size_t len;
 676         char *filename;
 677 
 678         len = strlen(ZCG(accel_directives).file_cache);
 679         filename = emalloc(len + 33 + ZSTR_LEN(script_path) + sizeof(SUFFIX));
 680         memcpy(filename, ZCG(accel_directives).file_cache, len);
 681 #ifndef ZEND_WIN32
 682         filename[len] = '/';
 683         memcpy(filename + len + 1, ZCG(system_id), 32);
 684         memcpy(filename + len + 33, ZSTR_VAL(script_path), ZSTR_LEN(script_path));
 685         memcpy(filename + len + 33 + ZSTR_LEN(script_path), SUFFIX, sizeof(SUFFIX));
 686 #else
 687         filename[len] = '\\';
 688         memcpy(filename + len + 1, ZCG(system_id), 32);
 689         if (ZSTR_LEN(script_path) >= 2 && ':' == ZSTR_VAL(script_path)[1]) {
 690                 /* local fs */
 691                 *(filename + len + 33) = '\\';
 692                 *(filename + len + 34) = ZSTR_VAL(script_path)[0];
 693                 memcpy(filename + len + 35, ZSTR_VAL(script_path) + 2, ZSTR_LEN(script_path) - 2);
 694                 memcpy(filename + len + 35 + ZSTR_LEN(script_path) - 2, SUFFIX, sizeof(SUFFIX));
 695         } else {
 696                 /* network path */
 697                 memcpy(filename + len + 33, ZSTR_VAL(script_path), ZSTR_LEN(script_path));
 698                 memcpy(filename + len + 33 + ZSTR_LEN(script_path), SUFFIX, sizeof(SUFFIX));
 699         }
 700 #endif
 701 
 702         return filename;
 703 }
 704 
 705 int zend_file_cache_script_store(zend_persistent_script *script, int in_shm)
 706 {
 707         int fd;
 708         char *filename;
 709         zend_file_cache_metainfo info;
 710 #ifdef HAVE_SYS_UIO_H
 711         struct iovec vec[3];
 712 #endif
 713         void *mem, *buf;
 714 
 715         filename = zend_file_cache_get_bin_file_path(script->full_path);
 716 
 717         if (zend_file_cache_mkdir(filename, strlen(ZCG(accel_directives).file_cache)) != SUCCESS) {
 718                 zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot create directory for file '%s'\n", filename);
 719                 efree(filename);
 720                 return FAILURE;
 721         }
 722 
 723 #ifndef ZEND_WIN32
 724         fd = open(filename, O_CREAT | O_EXCL | O_RDWR | O_BINARY, S_IRUSR | S_IWUSR);
 725 #else
 726         fd = open(filename, O_CREAT | O_EXCL | O_RDWR | O_BINARY, _S_IREAD | _S_IWRITE);
 727 #endif
 728         if (fd < 0) {
 729                 if (errno != EEXIST) {
 730                         zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot create file '%s'\n", filename);
 731                 }
 732                 efree(filename);
 733                 return FAILURE;
 734         }
 735 
 736         if (zend_file_cache_flock(fd, LOCK_EX) != 0) {
 737                 close(fd);
 738                 efree(filename);
 739                 return FAILURE;
 740         }
 741 
 742 #ifdef __SSE2__
 743         /* Align to 64-byte boundary */
 744         mem = emalloc(script->size + 64);
 745         buf = (void*)(((zend_uintptr_t)mem + 63L) & ~63L);
 746 #else
 747         mem = buf = emalloc(script->size);
 748 #endif
 749 
 750         ZCG(mem) = zend_string_alloc(4096 - (_ZSTR_HEADER_SIZE + 1), 0);
 751 
 752         zend_shared_alloc_init_xlat_table();
 753         if (!in_shm) {
 754                 script->corrupted = 1; /* used to check if script restored to SHM or process memory */
 755         }
 756         zend_file_cache_serialize(script, &info, buf);
 757         if (!in_shm) {
 758                 script->corrupted = 0;
 759         }
 760         zend_shared_alloc_destroy_xlat_table();
 761 
 762         info.checksum = zend_adler32(ADLER32_INIT, buf, script->size);
 763         info.checksum = zend_adler32(info.checksum, (signed char*)ZSTR_VAL((zend_string*)ZCG(mem)), info.str_size);
 764 
 765 #ifdef HAVE_SYS_UIO_H
 766         vec[0].iov_base = &info;
 767         vec[0].iov_len = sizeof(info);
 768         vec[1].iov_base = buf;
 769         vec[1].iov_len = script->size;
 770         vec[2].iov_base = ZSTR_VAL((zend_string*)ZCG(mem));
 771         vec[2].iov_len = info.str_size;
 772 
 773         if (writev(fd, vec, 3) != (ssize_t)(sizeof(info) + script->size + info.str_size)) {
 774                 zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot write to file '%s'\n", filename);
 775                 zend_string_release((zend_string*)ZCG(mem));
 776                 efree(mem);
 777                 unlink(filename);
 778                 efree(filename);
 779                 return FAILURE;
 780         }
 781 #else
 782         if (ZEND_LONG_MAX < (zend_long)(sizeof(info) + script->size + info.str_size) ||
 783                 write(fd, &info, sizeof(info)) != sizeof(info) ||
 784                 write(fd, buf, script->size) != script->size ||
 785                 write(fd, ((zend_string*)ZCG(mem))->val, info.str_size) != info.str_size
 786                 ) {
 787                 zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot write to file '%s'\n", filename);
 788                 zend_string_release((zend_string*)ZCG(mem));
 789                 efree(mem);
 790                 unlink(filename);
 791                 efree(filename);
 792                 return FAILURE;
 793         }
 794 #endif
 795 
 796         zend_string_release((zend_string*)ZCG(mem));
 797         efree(mem);
 798         if (zend_file_cache_flock(fd, LOCK_UN) != 0) {
 799                 zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s'\n", filename);
 800         }
 801         close(fd);
 802         efree(filename);
 803 
 804         return SUCCESS;
 805 }
 806 
 807 static void zend_file_cache_unserialize_hash(HashTable               *ht,
 808                                              zend_persistent_script  *script,
 809                                              void                    *buf,
 810                                              unserialize_callback_t   func,
 811                                              dtor_func_t              dtor)
 812 {
 813         Bucket *p, *end;
 814 
 815         ht->pDestructor = dtor;
 816         if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
 817                 HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
 818                 return;
 819         }
 820         if (IS_UNSERIALIZED(ht->arData)) {
 821                 return;
 822         }
 823         UNSERIALIZE_PTR(ht->arData);
 824         p = ht->arData;
 825         end = p + ht->nNumUsed;
 826         while (p < end) {
 827                 if (Z_TYPE(p->val) != IS_UNDEF) {
 828                         UNSERIALIZE_STR(p->key);
 829                         func(&p->val, script, buf);
 830                 }
 831                 p++;
 832         }
 833 }
 834 
 835 static zend_ast *zend_file_cache_unserialize_ast(zend_ast                *ast,
 836                                                  zend_persistent_script  *script,
 837                                                  void                    *buf)
 838 {
 839         uint32_t i;
 840 
 841         UNSERIALIZE_PTR(ast);
 842 
 843         if (ast->kind == ZEND_AST_ZVAL) {
 844                 zend_file_cache_unserialize_zval(&((zend_ast_zval*)ast)->val, script, buf);
 845         } else if (zend_ast_is_list(ast)) {
 846                 zend_ast_list *list = zend_ast_get_list(ast);
 847                 for (i = 0; i < list->children; i++) {
 848                         if (list->child[i]) {
 849                                 list->child[i] = zend_file_cache_unserialize_ast(list->child[i], script, buf);
 850                         }
 851                 }
 852         } else {
 853                 uint32_t children = zend_ast_get_num_children(ast);
 854                 for (i = 0; i < children; i++) {
 855                         if (ast->child[i]) {
 856                                 ast->child[i] = zend_file_cache_unserialize_ast(ast->child[i], script, buf);
 857                         }
 858                 }
 859         }
 860         return ast;
 861 }
 862 
 863 static void zend_file_cache_unserialize_zval(zval                    *zv,
 864                                              zend_persistent_script  *script,
 865                                              void                    *buf)
 866 {
 867         switch (Z_TYPE_P(zv)) {
 868                 case IS_STRING:
 869                 case IS_CONSTANT:
 870                         if (!IS_UNSERIALIZED(Z_STR_P(zv))) {
 871                                 UNSERIALIZE_STR(Z_STR_P(zv));
 872                         }
 873                         break;
 874                 case IS_ARRAY:
 875                         if (!IS_UNSERIALIZED(Z_ARR_P(zv))) {
 876                                 HashTable *ht;
 877 
 878                                 UNSERIALIZE_PTR(Z_ARR_P(zv));
 879                                 ht = Z_ARR_P(zv);
 880                                 zend_file_cache_unserialize_hash(ht,
 881                                                 script, buf, zend_file_cache_unserialize_zval, ZVAL_PTR_DTOR);
 882                         }
 883                         break;
 884                 case IS_REFERENCE:
 885                         if (!IS_UNSERIALIZED(Z_REF_P(zv))) {
 886                                 zend_reference *ref;
 887 
 888                                 UNSERIALIZE_PTR(Z_REF_P(zv));
 889                                 ref = Z_REF_P(zv);
 890                                 zend_file_cache_unserialize_zval(&ref->val, script, buf);
 891                         }
 892                         break;
 893                 case IS_CONSTANT_AST:
 894                         if (!IS_UNSERIALIZED(Z_AST_P(zv))) {
 895                                 zend_ast_ref *ast;
 896 
 897                                 UNSERIALIZE_PTR(Z_AST_P(zv));
 898                                 ast = Z_AST_P(zv);
 899                                 if (!IS_UNSERIALIZED(ast->ast)) {
 900                                         ast->ast = zend_file_cache_unserialize_ast(ast->ast, script, buf);
 901                                 }
 902                         }
 903                         break;
 904         }
 905 }
 906 
 907 static void zend_file_cache_unserialize_op_array(zend_op_array           *op_array,
 908                                                  zend_persistent_script  *script,
 909                                                  void                    *buf)
 910 {
 911         if (op_array->static_variables && !IS_UNSERIALIZED(op_array->static_variables)) {
 912                 HashTable *ht;
 913 
 914                 UNSERIALIZE_PTR(op_array->static_variables);
 915                 ht = op_array->static_variables;
 916                 zend_file_cache_unserialize_hash(ht,
 917                                 script, buf, zend_file_cache_unserialize_zval, ZVAL_PTR_DTOR);
 918         }
 919 
 920         if (op_array->literals && !IS_UNSERIALIZED(op_array->literals)) {
 921                 zval *p, *end;
 922 
 923                 UNSERIALIZE_PTR(op_array->literals);
 924                 p = op_array->literals;
 925                 end = p + op_array->last_literal;
 926                 while (p < end) {
 927                         zend_file_cache_unserialize_zval(p, script, buf);
 928                         p++;
 929                 }
 930         }
 931 
 932         if (!IS_UNSERIALIZED(op_array->opcodes)) {
 933                 zend_op *opline, *end;
 934 
 935                 UNSERIALIZE_PTR(op_array->opcodes);
 936                 opline = op_array->opcodes;
 937                 end = opline + op_array->last;
 938                 while (opline < end) {
 939 # if ZEND_USE_ABS_CONST_ADDR
 940                         if (ZEND_OP1_TYPE(opline) == IS_CONST) {
 941                                 UNSERIALIZE_PTR(opline->op1.zv);
 942                         }
 943                         if (ZEND_OP2_TYPE(opline) == IS_CONST) {
 944                                 UNSERIALIZE_PTR(opline->op2.zv);
 945                         }
 946 # endif
 947 # if ZEND_USE_ABS_JMP_ADDR
 948                         switch (opline->opcode) {
 949                                 case ZEND_JMP:
 950                                 case ZEND_FAST_CALL:
 951                                 case ZEND_DECLARE_ANON_CLASS:
 952                                 case ZEND_DECLARE_ANON_INHERITED_CLASS:
 953                                         UNSERIALIZE_PTR(opline->op1.jmp_addr);
 954                                         break;
 955                                 case ZEND_JMPZNZ:
 956                                         /* relative extended_value don't have to be changed */
 957                                         /* break omitted intentionally */
 958                                 case ZEND_JMPZ:
 959                                 case ZEND_JMPNZ:
 960                                 case ZEND_JMPZ_EX:
 961                                 case ZEND_JMPNZ_EX:
 962                                 case ZEND_JMP_SET:
 963                                 case ZEND_COALESCE:
 964                                 case ZEND_NEW:
 965                                 case ZEND_FE_RESET_R:
 966                                 case ZEND_FE_RESET_RW:
 967                                 case ZEND_ASSERT_CHECK:
 968                                         UNSERIALIZE_PTR(opline->op2.jmp_addr);
 969                                         break;
 970                                 case ZEND_FE_FETCH_R:
 971                                 case ZEND_FE_FETCH_RW:
 972                                         /* relative extended_value don't have to be changed */
 973                                         break;
 974                         }
 975 # endif
 976                         ZEND_VM_SET_OPCODE_HANDLER(opline);
 977                         opline++;
 978                 }
 979 
 980                 if (op_array->arg_info) {
 981                         zend_arg_info *p, *end;
 982                         UNSERIALIZE_PTR(op_array->arg_info);
 983                         p = op_array->arg_info;
 984                         end = p + op_array->num_args;
 985                         if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
 986                                 p--;
 987                         }
 988                         if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
 989                                 end++;
 990                         }
 991                         while (p < end) {
 992                                 if (!IS_UNSERIALIZED(p->name)) {
 993                                         UNSERIALIZE_STR(p->name);
 994                                 }
 995                                 if (!IS_UNSERIALIZED(p->class_name)) {
 996                                         UNSERIALIZE_STR(p->class_name);
 997                                 }
 998                                 p++;
 999                         }
1000                 }
1001 
1002                 if (op_array->vars) {
1003                         zend_string **p, **end;
1004 
1005                         UNSERIALIZE_PTR(op_array->vars);
1006                         p = op_array->vars;
1007                         end = p + op_array->last_var;
1008                         while (p < end) {
1009                                 if (!IS_UNSERIALIZED(*p)) {
1010                                         UNSERIALIZE_STR(*p);
1011                                 }
1012                                 p++;
1013                         }
1014                 }
1015 
1016                 UNSERIALIZE_STR(op_array->function_name);
1017                 UNSERIALIZE_STR(op_array->filename);
1018                 UNSERIALIZE_PTR(op_array->brk_cont_array);
1019                 UNSERIALIZE_PTR(op_array->scope);
1020                 UNSERIALIZE_STR(op_array->doc_comment);
1021                 UNSERIALIZE_PTR(op_array->try_catch_array);
1022                 UNSERIALIZE_PTR(op_array->prototype);
1023         }
1024 }
1025 
1026 static void zend_file_cache_unserialize_func(zval                    *zv,
1027                                              zend_persistent_script  *script,
1028                                              void                    *buf)
1029 {
1030         zend_op_array *op_array;
1031 
1032         UNSERIALIZE_PTR(Z_PTR_P(zv));
1033         op_array = Z_PTR_P(zv);
1034         zend_file_cache_unserialize_op_array(op_array, script, buf);
1035 }
1036 
1037 static void zend_file_cache_unserialize_prop_info(zval                    *zv,
1038                                                   zend_persistent_script  *script,
1039                                                   void                    *buf)
1040 {
1041         if (!IS_UNSERIALIZED(Z_PTR_P(zv))) {
1042                 zend_property_info *prop;
1043 
1044                 UNSERIALIZE_PTR(Z_PTR_P(zv));
1045                 prop = Z_PTR_P(zv);
1046 
1047                 if (prop->ce && !IS_UNSERIALIZED(prop->ce)) {
1048                         UNSERIALIZE_PTR(prop->ce);
1049                 }
1050                 if (prop->name && !IS_UNSERIALIZED(prop->name)) {
1051                         UNSERIALIZE_STR(prop->name);
1052                 }
1053                 if (prop->doc_comment && !IS_UNSERIALIZED(prop->doc_comment)) {
1054                         UNSERIALIZE_STR(prop->doc_comment);
1055                 }
1056         }
1057 }
1058 
1059 static void zend_file_cache_unserialize_class(zval                    *zv,
1060                                               zend_persistent_script  *script,
1061                                               void                    *buf)
1062 {
1063         zend_class_entry *ce;
1064 
1065         UNSERIALIZE_PTR(Z_PTR_P(zv));
1066         ce = Z_PTR_P(zv);
1067 
1068         UNSERIALIZE_STR(ce->name);
1069         zend_file_cache_unserialize_hash(&ce->function_table,
1070                         script, buf, zend_file_cache_unserialize_func, ZEND_FUNCTION_DTOR);
1071         if (ce->default_properties_table) {
1072                 zval *p, *end;
1073 
1074                 UNSERIALIZE_PTR(ce->default_properties_table);
1075                 p = ce->default_properties_table;
1076                 end = p + ce->default_properties_count;
1077                 while (p < end) {
1078                         zend_file_cache_unserialize_zval(p, script, buf);
1079                         p++;
1080                 }
1081         }
1082         if (ce->default_static_members_table) {
1083                 zval *p, *end;
1084 
1085                 UNSERIALIZE_PTR(ce->default_static_members_table);
1086                 p = ce->default_static_members_table;
1087                 end = p + ce->default_static_members_count;
1088                 while (p < end) {
1089                         zend_file_cache_unserialize_zval(p, script, buf);
1090                         p++;
1091                 }
1092         }
1093         zend_file_cache_unserialize_hash(&ce->constants_table,
1094                         script, buf, zend_file_cache_unserialize_zval, NULL);
1095         UNSERIALIZE_STR(ZEND_CE_FILENAME(ce));
1096         UNSERIALIZE_STR(ZEND_CE_DOC_COMMENT(ce));
1097         zend_file_cache_unserialize_hash(&ce->properties_info,
1098                         script, buf, zend_file_cache_unserialize_prop_info, ZVAL_PTR_DTOR);
1099 
1100         if (ce->trait_aliases) {
1101                 zend_trait_alias **p, *q;
1102 
1103                 UNSERIALIZE_PTR(ce->trait_aliases);
1104                 p = ce->trait_aliases;
1105 
1106                 while (*p) {
1107                         UNSERIALIZE_PTR(*p);
1108                         q = *p;
1109 
1110                         if (q->trait_method) {
1111                                 zend_trait_method_reference *m;
1112 
1113                                 UNSERIALIZE_PTR(q->trait_method);
1114                                 m = q->trait_method;
1115 
1116                                 if (m->method_name) {
1117                                         UNSERIALIZE_STR(m->method_name);
1118                                 }
1119                                 if (m->class_name) {
1120                                         UNSERIALIZE_STR(m->class_name);
1121                                 }
1122                         }
1123 
1124                         if (q->alias) {
1125                                 UNSERIALIZE_STR(q->alias);
1126                         }
1127                         p++;
1128                 }
1129         }
1130 
1131         if (ce->trait_precedences) {
1132                 zend_trait_precedence **p, *q;
1133 
1134                 UNSERIALIZE_PTR(ce->trait_precedences);
1135                 p = ce->trait_precedences;
1136 
1137                 while (*p) {
1138                         UNSERIALIZE_PTR(*p);
1139                         q = *p;
1140 
1141                         if (q->trait_method) {
1142                                 zend_trait_method_reference *m;
1143 
1144                                 UNSERIALIZE_PTR(q->trait_method);
1145                                 m = q->trait_method;
1146 
1147                                 if (m->method_name) {
1148                                         UNSERIALIZE_STR(m->method_name);
1149                                 }
1150                                 if (m->class_name) {
1151                                         UNSERIALIZE_STR(m->class_name);
1152                                 }
1153                         }
1154 
1155                         if (q->exclude_from_classes) {
1156                                 zend_string **s;
1157 
1158                                 UNSERIALIZE_PTR(q->exclude_from_classes);
1159                                 s = (zend_string**)q->exclude_from_classes;
1160 
1161                                 while (*s) {
1162                                         UNSERIALIZE_STR(*s);
1163                                         s++;
1164                                 }
1165                         }
1166                         p++;
1167                 }
1168         }
1169 
1170         UNSERIALIZE_PTR(ce->parent);
1171         UNSERIALIZE_PTR(ce->constructor);
1172         UNSERIALIZE_PTR(ce->destructor);
1173         UNSERIALIZE_PTR(ce->clone);
1174         UNSERIALIZE_PTR(ce->__get);
1175         UNSERIALIZE_PTR(ce->__set);
1176         UNSERIALIZE_PTR(ce->__call);
1177         UNSERIALIZE_PTR(ce->serialize_func);
1178         UNSERIALIZE_PTR(ce->unserialize_func);
1179         UNSERIALIZE_PTR(ce->__isset);
1180         UNSERIALIZE_PTR(ce->__unset);
1181         UNSERIALIZE_PTR(ce->__tostring);
1182         UNSERIALIZE_PTR(ce->__callstatic);
1183         UNSERIALIZE_PTR(ce->__debugInfo);
1184 
1185         if (UNEXPECTED((ce->ce_flags & ZEND_ACC_ANON_CLASS))) {
1186                 ce->serialize = zend_class_serialize_deny;
1187                 ce->unserialize = zend_class_unserialize_deny;
1188         }
1189 }
1190 
1191 static void zend_file_cache_unserialize(zend_persistent_script  *script,
1192                                         void                    *buf)
1193 {
1194         script->mem = buf;
1195 
1196         UNSERIALIZE_STR(script->full_path);
1197 
1198         zend_file_cache_unserialize_hash(&script->class_table,
1199                         script, buf, zend_file_cache_unserialize_class, ZEND_CLASS_DTOR);
1200         zend_file_cache_unserialize_hash(&script->function_table,
1201                         script, buf, zend_file_cache_unserialize_func, ZEND_FUNCTION_DTOR);
1202         zend_file_cache_unserialize_op_array(&script->main_op_array, script, buf);
1203 
1204         UNSERIALIZE_PTR(script->arena_mem);
1205 }
1206 
1207 zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handle)
1208 {
1209         zend_string *full_path = file_handle->opened_path;
1210         int fd;
1211         char *filename;
1212         zend_persistent_script *script;
1213         zend_file_cache_metainfo info;
1214         zend_accel_hash_entry *bucket;
1215         void *mem, *checkpoint, *buf;
1216         int cache_it = 1;
1217 
1218         if (!full_path) {
1219                 return NULL;
1220         }
1221         filename = zend_file_cache_get_bin_file_path(full_path);
1222 
1223         fd = open(filename, O_RDONLY | O_BINARY);
1224         if (fd < 0) {
1225                 efree(filename);
1226                 return NULL;
1227         }
1228 
1229         if (zend_file_cache_flock(fd, LOCK_SH) != 0) {
1230                 close(fd);
1231                 efree(filename);
1232                 return NULL;
1233         }
1234 
1235         if (read(fd, &info, sizeof(info)) != sizeof(info)) {
1236                 zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s'\n", filename);
1237                 zend_file_cache_flock(fd, LOCK_UN);
1238                 close(fd);
1239                 unlink(filename);
1240                 efree(filename);
1241                 return NULL;
1242         }
1243 
1244         /* verify header */
1245         if (memcmp(info.magic, "OPCACHE", 8) != 0) {
1246                 zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s' (wrong header)\n", filename);
1247                 zend_file_cache_flock(fd, LOCK_UN);
1248                 close(fd);
1249                 unlink(filename);
1250                 efree(filename);
1251                 return NULL;
1252         }
1253         if (memcmp(info.system_id, ZCG(system_id), 32) != 0) {
1254                 zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s' (wrong \"system_id\")\n", filename);
1255                 zend_file_cache_flock(fd, LOCK_UN);
1256                 close(fd);
1257                 unlink(filename);
1258                 efree(filename);
1259                 return NULL;
1260         }
1261 
1262         /* verify timestamp */
1263         if (ZCG(accel_directives).validate_timestamps &&
1264             zend_get_file_handle_timestamp(file_handle, NULL) != info.timestamp) {
1265                 if (zend_file_cache_flock(fd, LOCK_UN) != 0) {
1266                         zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s'\n", filename);
1267                 }
1268                 close(fd);
1269                 unlink(filename);
1270                 efree(filename);
1271                 return NULL;
1272         }
1273 
1274         checkpoint = zend_arena_checkpoint(CG(arena));
1275 #ifdef __SSE2__
1276         /* Align to 64-byte boundary */
1277         mem = zend_arena_alloc(&CG(arena), info.mem_size + info.str_size + 64);
1278         mem = (void*)(((zend_uintptr_t)mem + 63L) & ~63L);
1279 #else
1280         mem = zend_arena_alloc(&CG(arena), info.mem_size + info.str_size);
1281 #endif
1282 
1283         if (read(fd, mem, info.mem_size + info.str_size) != (ssize_t)(info.mem_size + info.str_size)) {
1284                 zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s'\n", filename);
1285                 zend_file_cache_flock(fd, LOCK_UN);
1286                 close(fd);
1287                 unlink(filename);
1288                 zend_arena_release(&CG(arena), checkpoint);
1289                 efree(filename);
1290                 return NULL;
1291         }
1292         if (zend_file_cache_flock(fd, LOCK_UN) != 0) {
1293                 zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s'\n", filename);
1294         }
1295         close(fd);
1296 
1297         /* verify checksum */
1298         if (ZCG(accel_directives).file_cache_consistency_checks &&
1299             zend_adler32(ADLER32_INIT, mem, info.mem_size + info.str_size) != info.checksum) {
1300                 zend_accel_error(ACCEL_LOG_WARNING, "corrupted file '%s'\n", filename);
1301                 unlink(filename);
1302                 zend_arena_release(&CG(arena), checkpoint);
1303                 efree(filename);
1304                 return NULL;
1305         }
1306 
1307         if (!ZCG(accel_directives).file_cache_only &&
1308             !ZCSG(restart_in_progress) &&
1309             accelerator_shm_read_lock() == SUCCESS) {
1310                 /* exclusive lock */
1311                 zend_shared_alloc_lock();
1312 
1313                 /* Check if we still need to put the file into the cache (may be it was
1314                  * already stored by another process. This final check is done under
1315                  * exclusive lock) */
1316                 bucket = zend_accel_hash_find_entry(&ZCSG(hash), full_path);
1317                 if (bucket) {
1318                         script = (zend_persistent_script *)bucket->data;
1319                         if (!script->corrupted) {
1320                                 zend_shared_alloc_unlock();
1321                                 zend_arena_release(&CG(arena), checkpoint);
1322                                 efree(filename);
1323                                 return script;
1324                         }
1325                 }
1326 
1327                 if (zend_accel_hash_is_full(&ZCSG(hash))) {
1328                         zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
1329                         ZSMMG(memory_exhausted) = 1;
1330                         zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
1331                         zend_shared_alloc_unlock();
1332                         goto use_process_mem;
1333                 }
1334 
1335 #ifdef __SSE2__
1336                 /* Align to 64-byte boundary */
1337                 buf = zend_shared_alloc(info.mem_size + 64);
1338                 buf = (void*)(((zend_uintptr_t)buf + 63L) & ~63L);
1339 #else
1340                 buf = zend_shared_alloc(info.mem_size);
1341 #endif
1342 
1343                 if (!buf) {
1344                         zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
1345                         zend_shared_alloc_unlock();
1346                         goto use_process_mem;
1347                 }
1348                 memcpy(buf, mem, info.mem_size);
1349         } else {
1350 use_process_mem:
1351                 buf = mem;
1352                 cache_it = 0;
1353         }
1354 
1355         ZCG(mem) = ((char*)mem + info.mem_size);
1356         script = (zend_persistent_script*)((char*)buf + info.script_offset);
1357         script->corrupted = !cache_it; /* used to check if script restored to SHM or process memory */
1358         zend_file_cache_unserialize(script, buf);
1359         script->corrupted = 0;
1360 
1361         if (cache_it) {
1362                 script->dynamic_members.checksum = zend_accel_script_checksum(script);
1363                 script->dynamic_members.last_used = ZCG(request_time);
1364 
1365                 zend_accel_hash_update(&ZCSG(hash), ZSTR_VAL(script->full_path), ZSTR_LEN(script->full_path), 0, script);
1366 
1367                 zend_shared_alloc_unlock();
1368                 zend_arena_release(&CG(arena), checkpoint);
1369         }
1370         efree(filename);
1371 
1372         return script;
1373 }
1374 
1375 void zend_file_cache_invalidate(zend_string *full_path)
1376 {
1377         char *filename;
1378 
1379         filename = zend_file_cache_get_bin_file_path(full_path);
1380 
1381         unlink(filename);
1382         efree(filename);
1383 }
1384 
1385 #endif /* HAVE_OPCACHE_FILE_CACHE */

/* [<][>][^][v][top][bottom][index][help] */