source: eaccelerator/trunk/eaccelerator.c @ 24

Revision 24, 224.9 KB checked in by everaldo_canuto, 6 years ago (diff)

Use of attribute to prevent segmentation fault.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2   +----------------------------------------------------------------------+
3   | eAccelerator project                                                 |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 2004 eAccelerator                                      |
6   | http://eaccelerator.sourceforge.net                                  |
7   +----------------------------------------------------------------------+
8   | This program is free software; you can redistribute it and/or        |
9   | modify it under the terms of the GNU General Public License          |
10   | as published by the Free Software Foundation; either version 2       |
11   | of the License, or (at your option) any later version.               |
12   |                                                                      |
13   | This program is distributed in the hope that it will be useful,      |
14   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
15   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
16   | GNU General Public License for more details.                         |
17   |                                                                      |
18   | You should have received a copy of the GNU General Public License    |
19   | along with this program; if not, write to the Free Software          |
20   | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
21   | MA  02111-1307, USA.                                                 |
22   |                                                                      |
23   | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
24   +----------------------------------------------------------------------+
25   | Author(s): Dmitry Stogov <dstogov@users.sourceforge.net>             |
26   |            Seung Woo <segv@sayclub.com>                              |
27   |            Everaldo Canuto <everaldo_canuto@yahoo.com.br>            |
28   +----------------------------------------------------------------------+
29   $Id$
30*/
31
32#include "eaccelerator.h"
33#include "eaccelerator_version.h"
34
35#ifdef HAVE_EACCELERATOR
36
37#include "opcodes.h"
38
39#include "zend.h"
40#include "zend_API.h"
41#include "zend_extensions.h"
42
43#include <sys/types.h>
44#include <sys/stat.h>
45#ifdef ZEND_WIN32
46#  include "win32/time.h"
47#  include <time.h>
48#  include <sys/utime.h>
49#else
50#  include <sys/file.h>
51#  include <sys/time.h>
52#  include <utime.h>
53#endif
54#include <fcntl.h>
55
56#ifndef O_BINARY
57#  define O_BINARY 0
58#endif
59
60/*???
61#ifdef HAVE_SCHED_H
62#  include <sched.h>
63#endif
64*/
65
66#ifdef ZEND_WIN32
67#  include <process.h>
68#  ifndef S_ISREG
69#    define S_ISREG(mode) (((mode)&S_IFMT) & S_IFREG)
70#  endif
71#  ifndef S_IRUSR
72#    define S_IRUSR S_IREAD
73#  endif
74#  ifndef S_IWUSR
75#    define S_IWUSR S_IWRITE
76#  endif
77#else
78#  include <dirent.h>
79#endif
80
81#include "php.h"
82#include "php_ini.h"
83#include "php_logos.h"
84#include "main/fopen_wrappers.h"
85#include "ext/standard/info.h"
86#include "ext/standard/php_incomplete_class.h"
87#include "ext/standard/md5.h"
88
89#ifndef INCOMPLETE_CLASS
90#  define INCOMPLETE_CLASS "__PHP_Incomplete_Class"
91#endif
92#ifndef MAGIC_MEMBER
93#  define MAGIC_MEMBER "__PHP_Incomplete_Class_Name"
94#endif
95
96#include "SAPI.h"
97
98#undef HAVE_PHP_SESSIONS_SUPPORT
99#ifdef HAVE_EXT_SESSION_PHP_SESSION_H
100#  include "ext/session/php_session.h"
101#   ifdef PHP_SESSION_API
102#     if PHP_SESSION_API >= 20020306
103#       define HAVE_PHP_SESSIONS_SUPPORT
104static int eaccelerator_sessions_registered = 0;
105#       ifdef PS_CREATE_SID_ARGS
106#         include "ext/standard/php_lcg.h"
107#       endif
108#     endif
109#   endif
110#endif
111
112#define MAX_DUP_STR_LEN 256
113
114#define offsetof(str,fld) ((size_t)&(((str*)NULL)->fld))
115
116#ifdef EACCELERATOR_WITHOUT_FILE_LOCKING
117#  ifndef LOCK_SH
118#    define LOCK_SH 1
119#    define LOCK_EX 2
120#    define LOCK_UN 8
121#  endif
122#  define EACCELERATOR_FLOCK(FILE,OP)
123#else
124#  ifndef ZEND_WIN32
125#    ifdef HAVE_FLOCK
126#      define EACCELERATOR_FLOCK(FILE,OP) flock((FILE),(OP))
127#    else
128#      ifndef LOCK_SH
129#        define LOCK_SH 1
130#        define LOCK_EX 2
131#        define LOCK_UN 8
132#      endif
133#      define EACCELERATOR_FLOCK(FILE,OP)
134#    endif
135#  else
136#    define LOCK_SH 0
137#    define LOCK_EX 1
138#    define LOCK_UN 2
139#    define EACCELERATOR_FLOCK(FILE,OP) {OVERLAPPED offset = {0,0,0,0,NULL};\
140                                   if ((OP) == LOCK_EX) {\
141                                     LockFileEx((HANDLE)_get_osfhandle(FILE), \
142                                       LOCKFILE_EXCLUSIVE_LOCK, 0,\
143                                       1, 0, &offset);\
144                                   } else if ((OP) == LOCK_SH) {\
145                                     LockFileEx((HANDLE)_get_osfhandle(FILE), \
146                                       0, 0,\
147                                       1, 0, &offset);\
148                                   } else if ((OP) == LOCK_UN) {\
149                                     UnlockFileEx((HANDLE)_get_osfhandle(FILE), \
150                                       0,\
151                                       1, 0, &offset);\
152                                   }}
153#  endif
154#endif
155
156
157typedef struct _eaccelerator_op_array {
158  zend_uchar type;
159#ifdef ZEND_ENGINE_2
160  zend_bool uses_this;
161#else
162  zend_bool uses_globals;
163#endif
164  zend_bool return_reference;
165#ifdef ZEND_ENGINE_2
166  zend_uint num_args;
167  zend_uint required_num_args;
168  zend_arg_info *arg_info;
169  zend_bool pass_rest_by_reference;
170#else
171  zend_uchar *arg_types;
172#endif
173  char *function_name;
174  char *function_name_lc;
175#ifdef ZEND_ENGINE_2
176  char* scope_name;
177  int   scope_name_len;
178  zend_uint fn_flags;
179#endif
180  zend_op *opcodes;
181  zend_uint last;
182  zend_uint T;
183  zend_brk_cont_element *brk_cont_array;
184  zend_uint last_brk_cont;
185#ifdef ZEND_ENGINE_2
186        /* HOESH: try & catch support */
187        zend_try_catch_element* try_catch_array;
188        int last_try_catch;
189#endif
190  HashTable *static_variables;
191  char *filename;
192#ifdef ZEND_ENGINE_2
193  zend_uint line_start;
194  zend_uint line_end;
195  char *doc_comment;
196  zend_uint doc_comment_len;
197#endif
198} eaccelerator_op_array;
199
200typedef struct _eaccelerator_class_entry {
201  char type;
202  char *name;
203  char *name_lc;
204  uint name_length;
205  char *parent;
206  HashTable function_table;
207  HashTable default_properties;
208#ifdef ZEND_ENGINE_2
209  zend_uint ce_flags;
210  HashTable *static_members;
211  HashTable properties_info;
212  HashTable constants_table;
213  zend_uint num_interfaces;
214  char **interfaces;
215  zend_class_iterator_funcs iterator_funcs;
216
217  zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);
218  zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object TSRMLS_DC);
219  int (*interface_gets_implemented)(zend_class_entry *iface, zend_class_entry *class_type TSRMLS_DC); /* a class implements this interface */
220   
221  char *filename;
222  zend_uint line_start;
223  zend_uint line_end;
224  char *doc_comment;
225  zend_uint doc_comment_len;
226#endif
227} eaccelerator_class_entry;
228
229/*
230 * To cache functions and classes.
231 */
232typedef struct _mm_fc_entry {
233  void   *fc;
234  struct _mm_fc_entry *next;
235  int    htablen;
236  char   htabkey[1];         /* must be last element */
237} mm_fc_entry;
238
239/*
240 * A mm_cache_entry is a bucket for one PHP script file.
241 * Nested  functions and classes which defined in the file goes
242 * into the list of mm_fc_entry.
243 */
244typedef struct _mm_cache_entry {
245  struct _mm_cache_entry *next;
246#ifdef EACCELERATOR_USE_INODE
247  dev_t                  st_dev;         /* file's device                     */
248  ino_t                  st_ino;         /* file's inode                      */
249#else
250  unsigned int           hv;             /* hash value                        */
251#endif
252  off_t                  filesize;       /* file size */
253  time_t                 mtime;          /* file last modification time       */
254  time_t                 ttl;            /* expiration time                   */
255  int                    size;           /* entry size (bytes)                */
256  int                    nhits;          /* hits count                        */
257  int                    nreloads;       /* count of reloads                  */
258  int                    use_cnt;        /* how many processes uses the entry */
259  eaccelerator_op_array       *op_array;      /* script's global scope code        */
260  mm_fc_entry            *f_head;        /* list of nested functions          */
261  mm_fc_entry            *c_head;        /* list of nested classes            */
262  zend_bool              removed;        /* the entry is scheduled to remove  */
263  char                   realfilename[1];/* real file name (must be last el.) */
264} mm_cache_entry;
265
266/*
267 * bucket for user's cache
268 */
269typedef struct _mm_user_cache_entry {
270  struct _mm_user_cache_entry *next;
271  unsigned int           hv;            /* hash value                  */
272  long                   ttl;           /* expiration time             */
273  int                    size;
274  zval                   value;         /* value                       */
275  char                   key[1];        /* key value (must be last el) */
276} mm_user_cache_entry;
277
278/*
279 * Linked list of mm_cache_entry which are used by process/thread
280 */
281typedef struct _mm_used_entry {
282  struct _mm_used_entry *next;
283  mm_cache_entry        *entry;
284} mm_used_entry;
285
286/*
287 * Linked list of locks
288 */
289typedef struct _mm_lock_entry {
290  struct _mm_lock_entry *next;
291  pid_t  pid;
292#ifdef ZTS
293  THREAD_T thread;
294#endif
295  char                  key[1];
296} mm_lock_entry;
297
298typedef struct _mm_file_header {
299  char   magic[8];        /* "EACCELERATOR" */
300  int    eaccelerator_version;
301  int    zend_version;
302  int    php_version;
303  int    size;
304  time_t mtime;
305  unsigned int crc32;
306} mm_file_header;
307
308#ifdef ZTS
309#  define ZTS_LOCK()    tsrm_mutex_lock(mm_mutex)
310#  define ZTS_UNLOCK()  tsrm_mutex_unlock(mm_mutex)
311#else
312#  define ZTS_LOCK()
313#  define ZTS_UNLOCK()
314#endif
315
316#include "mm.h"
317
318#if defined(EACCELERATOR_PROTECT_SHM)
319#  define EACCELERATOR_PROTECT()    do {mm_protect(eaccelerator_mm_instance->mm, MM_PROT_READ);} while(0)
320#  define EACCELERATOR_UNPROTECT()  do {mm_protect(eaccelerator_mm_instance->mm, MM_PROT_READ|MM_PROT_WRITE);} while(0)
321#else
322#  define EACCELERATOR_PROTECT()
323#  define EACCELERATOR_UNPROTECT()
324#endif
325
326#define EACCELERATOR_LOCK_RW()    do {ZTS_LOCK(); mm_lock(eaccelerator_mm_instance->mm, MM_LOCK_RW);} while(0)
327#define EACCELERATOR_LOCK_RD()    do {ZTS_LOCK(); mm_lock(eaccelerator_mm_instance->mm, MM_LOCK_RD);} while(0)
328#define EACCELERATOR_UNLOCK()     do {mm_unlock(eaccelerator_mm_instance->mm); ZTS_UNLOCK();} while(0)
329#define EACCELERATOR_UNLOCK_RW()  EACCELERATOR_UNLOCK()
330#define EACCELERATOR_UNLOCK_RD()  EACCELERATOR_UNLOCK()
331
332#define EACCELERATOR_BLOCK_INTERRUPTIONS()   HANDLE_BLOCK_INTERRUPTIONS()
333#define EACCELERATOR_UNBLOCK_INTERRUPTIONS() HANDLE_UNBLOCK_INTERRUPTIONS()
334
335#define MM_HASH_SIZE      256
336#define MM_USER_HASH_SIZE 256
337#define MM_HASH_MAX       (MM_HASH_SIZE-1)
338#define MM_USER_HASH_MAX  (MM_USER_HASH_SIZE-1)
339
340#define eaccelerator_malloc(size)        mm_malloc(eaccelerator_mm_instance->mm, size)
341#define eaccelerator_free(x)             mm_free(eaccelerator_mm_instance->mm, x)
342#define eaccelerator_malloc_nolock(size) mm_malloc_nolock(eaccelerator_mm_instance->mm, size)
343#define eaccelerator_free_nolock(x)      mm_free_nolock(eaccelerator_mm_instance->mm, x)
344
345typedef struct {
346  MM             *mm;
347  pid_t          owner;
348  size_t         total;
349  unsigned int   hash_cnt;
350  unsigned int   user_hash_cnt;
351  zend_bool      enabled;
352  zend_bool      optimizer_enabled;
353  unsigned int   rem_cnt;
354  time_t         last_prune;
355  mm_cache_entry *removed;
356  mm_lock_entry  *locks;
357
358  mm_cache_entry      *hash[MM_HASH_SIZE];
359  mm_user_cache_entry *user_hash[MM_USER_HASH_SIZE];
360} eaccelerator_mm;
361
362/*
363 * Globals (different for each process/thread)
364 */
365ZEND_DECLARE_MODULE_GLOBALS(eaccelerator)
366
367/*
368 * Globals (common for each process/thread)
369 */
370static long eaccelerator_shm_size = 0;
371static long eaccelerator_shm_max = 0;
372static long eaccelerator_shm_ttl = 0;
373static long eaccelerator_shm_prune_period = 0;
374static long eaccelerator_debug = 0;
375static zend_bool eaccelerator_check_mtime = 1;
376static zend_bool eaccelerator_scripts_shm_only = 0;
377static eaccelerator_cache_place eaccelerator_keys_cache_place     = eaccelerator_shm_and_disk;
378static eaccelerator_cache_place eaccelerator_sessions_cache_place = eaccelerator_shm_and_disk;
379       eaccelerator_cache_place eaccelerator_content_cache_place  = eaccelerator_shm_and_disk;
380
381static eaccelerator_mm* eaccelerator_mm_instance = NULL;
382static int eaccelerator_is_zend_extension = 0;
383static int eaccelerator_is_extension      = 0;
384static zend_extension* ZendOptimizer = NULL;
385#ifdef ZTS
386static MUTEX_T mm_mutex;
387#endif
388
389static HashTable eaccelerator_global_function_table;
390static HashTable eaccelerator_global_class_table;
391
392static int binary_eaccelerator_version;
393static int binary_php_version;
394static int binary_zend_version;
395
396/* saved original functions */
397static zend_op_array *(*mm_saved_zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
398
399#if defined(PROFILE_OPCODES) || defined(WITH_EACCELERATOR_EXECUTOR)
400static void (*mm_saved_zend_execute)(zend_op_array *op_array TSRMLS_DC);
401#endif
402
403/* external declarations */
404PHPAPI void php_stripslashes(char *str, int *len TSRMLS_DC);
405PHPAPI char *php_get_uname();
406
407ZEND_DLEXPORT zend_op_array* eaccelerator_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC);
408
409
410#if defined(DEBUG) || defined(TEST_PERFORMANCE)  || defined(PROFILE_OPCODES)
411#include <ctype.h>
412#include <stdio.h>
413static FILE *F_fp;
414
415static void binary_print(char *p, int len) {
416  while (len--) {
417    fputc(*p++, F_fp);
418  }
419  fputc('\n', F_fp);
420}
421
422static void log_hashkeys(char *p, HashTable *ht)
423{
424  Bucket *b;
425  int i = 0;
426
427  b = ht->pListHead;
428
429  fputs(p, F_fp);
430  while (b) {
431    fprintf(F_fp, "[%d] ", i);
432    binary_print(b->arKey, b->nKeyLength);
433
434    b = b->pListNext;
435    i++;
436  }
437}
438
439static void pad(TSRMLS_D) {
440  int i = MMCG(xpad);
441  while (i-- > 0) {
442    fputc('\t', F_fp);
443  }
444}
445
446static void start_time(struct timeval *tvstart) {
447  gettimeofday(tvstart, NULL);
448}
449
450static long elapsed_time(struct timeval *tvstart) {
451  struct timeval tvend;
452  int sec, usec;
453  gettimeofday(&tvend, NULL);
454  sec = tvend.tv_sec - tvstart->tv_sec;
455  usec = tvend.tv_usec - tvstart->tv_usec;
456  return sec * 1000000 + usec;
457}
458#endif  /* #if defined(DEBUG) || defined(TEST_PERFORMANCE)  || defined(PROFILE_OPCODES) */
459
460static inline unsigned int hash_mm(const char *data, int len) {
461  unsigned int h;
462  const char *e = data + len;
463  for (h = 2166136261U; data < e; ) {
464    h *= 16777619;
465    h ^= *data++;
466  }
467  return h;
468}
469
470static mm_cache_entry* hash_find_mm(const char  *key,
471                                    struct stat *buf,
472                                    int         *nreloads,
473                                    time_t      ttl) {
474  unsigned int hv, slot;
475  mm_cache_entry *p, *q;
476
477#ifdef EACCELERATOR_USE_INODE
478  hv = buf->st_dev + buf->st_ino;
479#else
480  hv = hash_mm(key, strlen(key));
481#endif
482  slot = hv & MM_HASH_MAX;
483
484  EACCELERATOR_LOCK_RW();
485  q = NULL;
486  p = eaccelerator_mm_instance->hash[slot];
487  while (p != NULL) {
488#ifdef EACCELERATOR_USE_INODE
489    if (p->st_dev == buf->st_dev && p->st_ino == buf->st_ino) {
490      struct stat buf2;
491      if ((eaccelerator_check_mtime &&
492          (buf->st_mtime != p->mtime || buf->st_size != p->filesize)) ||
493          (strcmp(p->realfilename, key) != 0 &&
494           (stat(p->realfilename,&buf2) != 0 ||
495           buf2.st_dev != buf->st_dev ||
496           buf2.st_ino != buf->st_ino))) {
497#else
498    if ((p->hv == hv) && (strcmp(p->realfilename, key) == 0)) {
499      if (eaccelerator_check_mtime &&
500          (buf->st_mtime != p->mtime || buf->st_size != p->filesize)) {
501#endif
502        /* key is invalid. Remove it. */
503        *nreloads = p->nreloads+1;
504        if (q == NULL) {
505          eaccelerator_mm_instance->hash[slot] = p->next;
506        } else {
507          q->next = p->next;
508        }
509        eaccelerator_mm_instance->hash_cnt--;
510        if (p->use_cnt > 0) {
511          /* key is used by other process/thred. Shedule it to remove */
512          p->removed = 1;
513          p->next = eaccelerator_mm_instance->removed;
514          eaccelerator_mm_instance->removed = p;
515          eaccelerator_mm_instance->rem_cnt++;
516          EACCELERATOR_UNLOCK_RW();
517          return NULL;
518        } else {
519          /* key is unused. Remove it. */
520          eaccelerator_free_nolock(p);
521          EACCELERATOR_UNLOCK_RW();
522          return NULL;
523        }
524      } else {
525        /* key is valid */
526        p->nhits++;
527        p->use_cnt++;
528        p->ttl = ttl;
529        EACCELERATOR_UNLOCK_RW();
530        return p;
531      }
532    }
533    q = p;
534    p = p->next;
535  }
536  EACCELERATOR_UNLOCK_RW();
537  return NULL;
538}
539
540static void hash_add_mm(mm_cache_entry *x) {
541  mm_cache_entry *p,*q;
542  unsigned int slot;
543#ifdef EACCELERATOR_USE_INODE
544  slot = (x->st_dev + x->st_ino) & MM_HASH_MAX;
545#else
546  x->hv = hash_mm(x->realfilename, strlen(x->realfilename));
547  slot = x->hv & MM_HASH_MAX;
548#endif
549
550  EACCELERATOR_LOCK_RW();
551  x->next = eaccelerator_mm_instance->hash[slot];
552  eaccelerator_mm_instance->hash[slot] = x;
553  eaccelerator_mm_instance->hash_cnt++;
554  q = x;
555  p = x->next;
556  while (p != NULL) {
557#ifdef EACCELERATOR_USE_INODE
558    if ((p->st_dev == x->st_dev) && (p->st_ino == x->st_ino)) {
559#else
560    if ((p->hv == x->hv) &&
561        (strcmp(p->realfilename, x->realfilename) == 0)) {
562#endif
563      q->next = p->next;
564      eaccelerator_mm_instance->hash_cnt--;
565      eaccelerator_mm_instance->hash[slot]->nreloads += p->nreloads;
566      if (p->use_cnt > 0) {
567        /* key is used by other process/thred. Shedule it to remove */
568        p->removed = 1;
569        p->next = eaccelerator_mm_instance->removed;
570        eaccelerator_mm_instance->removed = p;
571        eaccelerator_mm_instance->rem_cnt++;
572        EACCELERATOR_UNLOCK_RW();
573        return;
574      } else {
575        /* key is unused. Remove it. */
576        eaccelerator_free_nolock(p);
577        EACCELERATOR_UNLOCK_RW();
578        return;
579      }
580    }
581    q = p;
582    p = p->next;
583  }
584  EACCELERATOR_UNLOCK_RW();
585}
586
587static int init_mm(TSRMLS_D) {
588  pid_t  owner = getpid();
589  MM     *mm;
590  size_t total;
591  char   mm_path[MAXPATHLEN];
592
593/*  if (getppid() != 1) return SUCCESS; */ /*???*/
594#ifdef ZEND_WIN32
595    snprintf(mm_path, MAXPATHLEN, "%s.%s", EACCELERATOR_MM_FILE, sapi_module.name);
596#else
597    snprintf(mm_path, MAXPATHLEN, "%s.%s%d", EACCELERATOR_MM_FILE, sapi_module.name, getpid());
598#endif
599/*  snprintf(mm_path, MAXPATHLEN, "%s.%s%d", EACCELERATOR_MM_FILE, sapi_module.name, geteuid());*/
600  if ((eaccelerator_mm_instance = (eaccelerator_mm*)mm_attach(eaccelerator_shm_size*1024*1024, mm_path)) != NULL) {
601#ifdef ZTS
602    mm_mutex = tsrm_mutex_alloc();
603#endif
604    return SUCCESS;
605  }
606  mm = mm_create(eaccelerator_shm_size*1024*1024, mm_path);
607  if (!mm) {
608    return FAILURE;
609  }
610#ifdef DEBUG
611#ifdef ZEND_WIN32
612  fprintf(F_fp, "init_mm [%d]\n", getpid());
613#else
614  fprintf(F_fp, "init_mm [%d,%d]\n", getpid(), getppid());
615#endif
616  fflush(F_fp);
617#endif
618#ifdef ZTS
619  mm_mutex = tsrm_mutex_alloc();
620#endif
621  total = mm_available(mm);
622  eaccelerator_mm_instance = mm_malloc(mm, sizeof(*eaccelerator_mm_instance));
623  if (!eaccelerator_mm_instance) {
624    return FAILURE;
625  }
626  mm_set_attach(mm, eaccelerator_mm_instance);
627  memset(eaccelerator_mm_instance, 0, sizeof(*eaccelerator_mm_instance));
628  eaccelerator_mm_instance->owner = owner;
629  eaccelerator_mm_instance->mm    = mm;
630  eaccelerator_mm_instance->total = total;
631  eaccelerator_mm_instance->hash_cnt = 0;
632  eaccelerator_mm_instance->rem_cnt  = 0;
633  eaccelerator_mm_instance->enabled = 1;
634  eaccelerator_mm_instance->optimizer_enabled = 1;
635  eaccelerator_mm_instance->removed = NULL;
636  eaccelerator_mm_instance->locks = NULL;
637  eaccelerator_mm_instance->user_hash_cnt = 0;
638  eaccelerator_mm_instance->last_prune = time(0);
639  EACCELERATOR_PROTECT();
640  return SUCCESS;
641}
642
643static void shutdown_mm(TSRMLS_D) {
644  if (eaccelerator_mm_instance) {
645#ifdef ZEND_WIN32
646    if (eaccelerator_mm_instance->owner == getpid()) {
647#else
648    if (getpgrp() == getpid()) {
649#endif
650      MM *mm = eaccelerator_mm_instance->mm;
651#ifdef DEBUG
652#ifdef ZEND_WIN32
653      fprintf(F_fp, "shutdown_mm [%d]\n", getpid());
654#else
655      fprintf(F_fp, "shutdown_mm [%d,%d]\n", getpid(), getppid());
656#endif
657      fflush(F_fp);
658#endif
659#ifdef ZTS
660      tsrm_mutex_free(mm_mutex);
661#endif
662      if (mm) {
663        mm_destroy(mm);
664      }
665      eaccelerator_mm_instance = NULL;
666    }
667  }
668}
669
670static void debug_printf(char *format, ...) {
671  char output_buf[512];
672  va_list args;
673
674  va_start(args, format);
675  vsnprintf(output_buf, sizeof(output_buf), format, args);
676  va_end(args);
677
678#ifdef ZEND_WIN32
679  OutputDebugString(output_buf);
680/*  zend_printf("EACCELERATOR: %s<br>\n",output_buf);*/
681#else
682  fputs(output_buf, stderr);
683#endif
684}
685
686/******************************************************************************/
687
688#define FIXUP(x) if((x)!=NULL) {(x) = (void*)(((char*)(x)) + ((long)(MMCG(mem))));}
689
690static void fixup_zval(zval* z TSRMLS_DC);
691
692typedef void (*fixup_bucket_t)(void* TSRMLS_DC);
693
694#define fixup_zval_hash(from) \
695  fixup_hash(from, (fixup_bucket_t)fixup_zval TSRMLS_CC)
696
697#ifdef ZEND_ENGINE_2
698static void fixup_property_info(zend_property_info* from TSRMLS_DC) {
699  FIXUP(from->name);
700}
701#endif
702
703static void fixup_hash(HashTable* source, fixup_bucket_t fixup_bucket TSRMLS_DC) {
704  unsigned int i;
705  Bucket *p;
706
707  if (source->nNumOfElements > 0) {
708    if (!MMCG(compress)) {
709      if (source->arBuckets != NULL) {
710        FIXUP(source->arBuckets);
711        for (i = 0; i < source->nTableSize; i++) {
712          FIXUP(source->arBuckets[i]);
713        }
714      }
715    }
716    FIXUP(source->pListHead);
717    FIXUP(source->pListTail);
718
719    p = source->pListHead;
720    while (p) {
721      FIXUP(p->pNext);
722      FIXUP(p->pLast);
723      FIXUP(p->pData);
724      FIXUP(p->pDataPtr);
725      FIXUP(p->pListLast);
726      FIXUP(p->pListNext);
727      if (p->pDataPtr) {
728        fixup_bucket(p->pDataPtr TSRMLS_CC);
729        p->pData = &p->pDataPtr;
730      } else {
731        fixup_bucket(p->pData TSRMLS_CC);
732      }
733      p = p->pListNext;
734    }
735    source->pInternalPointer = source->pListHead;
736  }
737}
738
739static void fixup_zval(zval* zv TSRMLS_DC) {
740  switch (zv->type) {
741    case IS_CONSTANT:
742    case IS_STRING:
743      if (zv->value.str.val == NULL ||
744         zv->value.str.len == 0) {
745        zv->value.str.val = empty_string;
746        zv->value.str.len = 0;
747      } else {
748        FIXUP(zv->value.str.val);
749      }
750      break;
751    case IS_ARRAY:
752    case IS_CONSTANT_ARRAY:
753      if (zv->value.ht == NULL || zv->value.ht == &EG(symbol_table)) {
754      } else {
755        FIXUP(zv->value.ht);
756        fixup_zval_hash(zv->value.ht);
757      }
758      break;
759    case IS_OBJECT:
760      if (!MMCG(compress)) {
761        return;
762      }
763#ifndef ZEND_ENGINE_2
764      FIXUP(zv->value.obj.ce);
765      if (zv->value.obj.properties != NULL) {
766        FIXUP(zv->value.obj.properties);
767        fixup_zval_hash(zv->value.obj.properties);
768      }
769#endif
770    default:
771      break;
772  }
773}
774
775static void fixup_op_array(eaccelerator_op_array* from TSRMLS_DC) {
776  zend_op *opline;
777  zend_op *end;
778
779#ifdef ZEND_ENGINE_2
780  if (from->num_args > 0) {
781    zend_uint i;
782    FIXUP(from->arg_info);
783    for (i = 0; i < from->num_args; i++) {
784      FIXUP(from->arg_info[i].name);
785      FIXUP(from->arg_info[i].class_name);
786    }
787  }
788#else
789  FIXUP(from->arg_types);
790#endif
791  FIXUP(from->function_name);
792#ifdef ZEND_ENGINE_2
793  FIXUP(from->scope_name);
794#endif
795  if (from->type == ZEND_INTERNAL_FUNCTION) {
796    return;
797  }
798
799  if (from->opcodes != NULL) {
800    FIXUP(from->opcodes);
801
802    opline = from->opcodes;
803    end = opline + from->last;
804    MMCG(compress) = 0;
805    for (;opline < end; opline++) {
806/*
807      if (opline->result.op_type == IS_CONST) fixup_zval(&opline->result.u.constant  TSRMLS_CC);
808*/
809      if (opline->op1.op_type    == IS_CONST) fixup_zval(&opline->op1.u.constant TSRMLS_CC);
810      if (opline->op2.op_type    == IS_CONST) fixup_zval(&opline->op2.u.constant TSRMLS_CC);
811#ifdef ZEND_ENGINE_2
812      switch (opline->opcode) {
813        case ZEND_JMP:
814          FIXUP(opline->op1.u.jmp_addr);
815          break;
816        case ZEND_JMPZ:
817        case ZEND_JMPNZ:
818        case ZEND_JMPZ_EX:
819        case ZEND_JMPNZ_EX:
820          FIXUP(opline->op2.u.jmp_addr);
821          break;
822      }
823      opline->handler = get_opcode_handler(opline->opcode TSRMLS_CC);
824#endif
825    }
826    MMCG(compress) = 1;
827  }
828  FIXUP(from->brk_cont_array);
829#ifdef ZEND_ENGINE_2
830        /* HOESH: try & catch support */
831        FIXUP(from->try_catch_array);
832#endif
833  if (from->static_variables != NULL) {
834    FIXUP(from->static_variables);
835    fixup_zval_hash(from->static_variables);
836  }
837  FIXUP(from->filename);
838#ifdef ZEND_ENGINE_2
839  FIXUP(from->doc_comment);
840#endif
841}
842
843static void fixup_class_entry(eaccelerator_class_entry* from TSRMLS_DC) {
844  FIXUP(from->name);
845  FIXUP(from->parent);
846#ifdef ZEND_ENGINE_2
847  FIXUP(from->filename);
848  FIXUP(from->doc_comment);
849  fixup_zval_hash(&from->constants_table);
850  fixup_zval_hash(&from->default_properties);
851  fixup_hash(&from->properties_info, (fixup_bucket_t)fixup_property_info TSRMLS_CC);
852  if (from->static_members != NULL) {
853    FIXUP(from->static_members);
854    fixup_zval_hash(from->static_members);
855  }
856#else
857  fixup_zval_hash(&from->default_properties);
858#endif
859  fixup_hash(&from->function_table, (fixup_bucket_t)fixup_op_array TSRMLS_CC);
860}
861
862static void eaccelerator_fixup(mm_cache_entry *p TSRMLS_DC) {
863  mm_fc_entry* q;
864
865  MMCG(mem) = (char*)((long)p - (long)p->next);
866  MMCG(compress) = 1;
867  p->next        = NULL;
868  FIXUP(p->op_array);
869  FIXUP(p->f_head);
870  FIXUP(p->c_head);
871  fixup_op_array(p->op_array TSRMLS_CC);
872  q = p->f_head;
873  while (q != NULL) {
874    FIXUP(q->fc);
875    fixup_op_array((eaccelerator_op_array*)q->fc TSRMLS_CC);
876    FIXUP(q->next);
877    q = q->next;
878  }
879  q = p->c_head;
880  while (q != NULL) {
881    FIXUP(q->fc);
882    fixup_class_entry((eaccelerator_class_entry*)q->fc TSRMLS_CC);
883    FIXUP(q->next);
884    q = q->next;
885  }
886}
887
888/******************************************************************************/
889
890static int encode_version(const char *s) {
891  unsigned int v1 = 0;
892  unsigned int v2 = 0;
893  unsigned int v3 = 0;
894  unsigned int c;
895  char m = '.';
896  sscanf(s, "%u.%u%c%u",&v1,&v2,&m,&v3);
897  switch (m) {
898    case  'a': c = 0; break;
899    case  'b': c = 1; break;
900    case  '.': c = 2; break;
901    case  's': c = 15; break;
902    default: c = 2;
903  }
904  return ((v1 & 0xf) << 20) |
905         ((v2 & 0xff) << 12) |
906         ((c & 0xf) << 8) |
907         (v3 & 0xff);
908}
909
910static void decode_version(char *version, int v) {
911  int t = (v & 0x000f00) >> 8;
912  char c;
913  switch (t) {
914    case  0: c = 'a'; break;
915    case  1: c = 'b'; break;
916    case  2: c = '.'; break;
917    case 15: c = 's'; break;
918    default: c = '.';
919  }
920  snprintf(version, 16, "%d.%d%c%d", (v & 0xf00000) >> 20,
921                                     (v & 0x0ff000) >> 12,
922                                     c,
923                                     (v & 0x0000ff));
924}
925
926#ifdef EACCELERATOR_USE_INODE
927static int eaccelerator_inode_key(char* s, dev_t dev, ino_t ino TSRMLS_DC) {
928  int n;
929  strncpy(s, MMCG(cache_dir), MAXPATHLEN-1);
930  strlcat(s, "/eaccelerator-", MAXPATHLEN-1);
931  n = strlen(s);
932  while (dev > 0) {
933    if (n >= MAXPATHLEN) return 0;
934    s[n++] = (dev % 10) +'0';
935    dev /= 10;
936  }
937  if (n >= MAXPATHLEN) return 0;
938  s[n++] = '.';
939  while (ino > 0) {
940    if (n >= MAXPATHLEN) return 0;
941    s[n++] = (ino % 10) +'0';
942    ino /= 10;
943  }
944  if (n >= MAXPATHLEN) return 0;
945  s[n++] = '\000';
946  return 1;
947}
948#endif
949
950static int eaccelerator_md5(char* s, const char* prefix, const char* key TSRMLS_DC) {
951#if defined(PHP_MAJOR_VERSION) && defined(PHP_MINOR_VERSION) && \
952    ((PHP_MAJOR_VERSION > 4) || (PHP_MAJOR_VERSION == 4 && PHP_MINOR_VERSION > 1))
953  char md5str[33];
954  PHP_MD5_CTX context;
955  unsigned char digest[16];
956
957  md5str[0] = '\0';
958  PHP_MD5Init(&context);
959  PHP_MD5Update(&context, key, strlen(key));
960  PHP_MD5Final(digest, &context);
961  make_digest(md5str, digest);
962  snprintf(s, MAXPATHLEN-1, "%s%s%s", MMCG(cache_dir), prefix, md5str);
963  return 1;
964#else
965  zval retval;
966  zval md5;
967  zval param;
968  zval *params[1];
969
970  ZVAL_STRING(&md5, "md5", 0);
971  INIT_ZVAL(param);
972  params[0] = &param;
973  ZVAL_STRING(params[0], (char*)key, 0);
974  if (call_user_function(CG(function_table), (zval**)NULL, &md5, &retval, 1, params TSRMLS_CC) == SUCCESS &&
975      retval.type == IS_STRING &&
976      retval.value.str.len == 32) {
977    strncpy(s, MMCG(cache_dir), MAXPATHLEN-1);
978    strlcat(s, prefix, MAXPATHLEN);
979    strlcat(s, retval.value.str.val, MAXPATHLEN);
980    zval_dtor(&retval);
981    return 1;
982  }
983  s[0] ='\0';
984#endif
985  return 0;
986}
987
988static void eaccelerator_prune(time_t t) {
989  unsigned int i;
990
991  EACCELERATOR_LOCK_RW();
992  eaccelerator_mm_instance->last_prune = t;
993  for (i = 0; i < MM_HASH_SIZE; i++) {
994    mm_cache_entry **p = &eaccelerator_mm_instance->hash[i];
995    while (*p != NULL) {
996      struct stat buf;
997      if (((*p)->ttl != 0 && (*p)->ttl < t && (*p)->use_cnt <= 0) ||
998          stat((*p)->realfilename,&buf) != 0 ||
999#ifdef EACCELERATOR_USE_INODE
1000          (*p)->st_dev != buf.st_dev ||
1001          (*p)->st_ino != buf.st_ino ||
1002#endif
1003          (*p)->mtime != buf.st_mtime ||
1004          (*p)->filesize != buf.st_size) {
1005        mm_cache_entry *r = *p;
1006        *p = (*p)->next;
1007        eaccelerator_mm_instance->hash_cnt--;
1008        eaccelerator_free_nolock(r);
1009      } else {
1010        p = &(*p)->next;
1011      }
1012    }
1013  }
1014  EACCELERATOR_UNLOCK_RW();
1015}
1016
1017static void* eaccelerator_malloc2(size_t size TSRMLS_DC) {
1018  void *p = NULL;
1019  time_t t;
1020
1021  if (eaccelerator_gc(TSRMLS_C) > 0) {
1022    p = eaccelerator_malloc(size);
1023    if (p != NULL) {
1024      return p;
1025    }
1026  }
1027  if (eaccelerator_shm_prune_period > 0) {
1028    t = time(0);
1029    if (t - eaccelerator_mm_instance->last_prune > eaccelerator_shm_prune_period) {
1030      eaccelerator_prune(t);
1031      p = eaccelerator_malloc(size);
1032    }
1033  }
1034  return p;
1035}
1036
1037#define EACCELERATOR_CRC32(crc, ch)   (crc = (crc >> 8) ^ crc32tab[(crc ^ (ch)) & 0xff])
1038
1039static const unsigned int crc32tab[256] = {
1040  0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
1041  0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
1042  0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
1043  0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
1044  0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
1045  0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
1046  0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
1047  0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
1048  0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
1049  0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
1050  0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
1051  0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
1052  0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
1053  0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
1054  0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
1055  0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
1056  0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
1057  0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
1058  0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
1059  0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
1060  0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
1061  0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
1062  0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
1063  0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
1064  0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
1065  0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
1066  0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
1067  0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
1068  0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
1069  0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
1070  0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
1071  0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
1072  0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
1073  0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
1074  0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
1075  0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
1076  0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
1077  0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
1078  0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
1079  0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
1080  0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
1081  0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
1082  0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
1083  0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
1084  0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
1085  0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
1086  0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
1087  0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
1088  0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
1089  0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
1090  0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
1091  0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
1092  0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
1093  0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
1094  0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
1095  0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
1096  0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
1097  0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
1098  0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
1099  0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1100  0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
1101  0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
1102  0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
1103  0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
1104};
1105
1106unsigned int eaccelerator_crc32(const char *p, size_t n) {
1107  unsigned int crc = ~0;
1108  for (; n--; ++p) {
1109    EACCELERATOR_CRC32(crc, *p);
1110  }
1111  return ~crc;
1112}
1113
1114static mm_cache_entry* hash_find_file(const char  *key,
1115                                      struct stat *buf TSRMLS_DC) {
1116  int f;
1117  char s[MAXPATHLEN];
1118  mm_file_header hdr;
1119  mm_cache_entry *p;
1120  int use_shm = 1;
1121
1122#ifdef EACCELERATOR_USE_INODE
1123  struct stat buf2;
1124
1125  if (!eaccelerator_inode_key(s, buf->st_dev, buf->st_ino TSRMLS_CC)) {
1126    return NULL;
1127  }
1128#else
1129  if (!eaccelerator_md5(s, "/eaccelerator-", key TSRMLS_CC)) {
1130    return NULL;
1131  }
1132#endif
1133
1134  if ((f = open(s, O_RDONLY | O_BINARY)) > 0) {
1135    EACCELERATOR_FLOCK(f, LOCK_SH);
1136    if (read(f, &hdr, sizeof(hdr)) != sizeof(hdr)) {
1137      EACCELERATOR_FLOCK(f, LOCK_UN);
1138      close(f);
1139      return NULL;
1140    }
1141    if (strncmp(hdr.magic,"EACCELERATOR",8) != 0 ||
1142        hdr.eaccelerator_version != binary_eaccelerator_version ||
1143        hdr.zend_version != binary_zend_version ||
1144        hdr.php_version != binary_php_version) {
1145      EACCELERATOR_FLOCK(f, LOCK_UN);
1146      close(f);
1147      unlink(s);
1148      return NULL;
1149    }
1150    p = eaccelerator_malloc(hdr.size);
1151    if (p == NULL) {
1152      p = eaccelerator_malloc2(hdr.size TSRMLS_CC);
1153    }
1154    if (p == NULL) {
1155      p = emalloc(hdr.size);
1156      use_shm = 0;
1157    }
1158    if (p == NULL) {
1159      EACCELERATOR_FLOCK(f, LOCK_UN);
1160      close(f);
1161      return NULL;
1162    }
1163    if (read(f, p, hdr.size) != hdr.size ||
1164        p->size != hdr.size ||
1165        hdr.crc32 != eaccelerator_crc32((const char*)p,p->size)) {
1166      EACCELERATOR_FLOCK(f, LOCK_UN);
1167      close(f);
1168      unlink(s);
1169      if (use_shm) eaccelerator_free(p); else efree(p);
1170      return NULL;
1171    }
1172    EACCELERATOR_FLOCK(f, LOCK_UN);
1173    close(f);
1174#ifdef EACCELERATOR_USE_INODE
1175    if (p->st_dev != buf->st_dev || p->st_ino != buf->st_ino) {
1176#else
1177    if (strcmp(key,p->realfilename) != 0) {
1178#endif
1179      if (use_shm) eaccelerator_free(p); else efree(p);
1180      return NULL;
1181    }
1182    if ((eaccelerator_check_mtime &&
1183        (buf->st_mtime != p->mtime || buf->st_size != p->filesize))
1184#ifdef EACCELERATOR_USE_INODE
1185        ||
1186        (strcmp(p->realfilename, key) != 0 &&
1187         (stat(p->realfilename,&buf2) != 0 ||
1188         buf2.st_dev != buf->st_dev ||
1189         buf2.st_ino != buf->st_ino))
1190#endif
1191       ) {
1192      /* key is invalid. Remove it. */
1193      if (use_shm) eaccelerator_free(p); else efree(p);
1194      unlink(s);
1195      return NULL;
1196    }
1197    eaccelerator_fixup(p TSRMLS_CC);
1198    if (use_shm) {
1199      p->nhits    = 1;
1200      p->nreloads = 1;
1201      p->use_cnt  = 1;
1202      p->removed  = 0;
1203      if (eaccelerator_shm_ttl > 0) {
1204        p->ttl = time(0) + eaccelerator_shm_ttl;
1205      } else {
1206        p->ttl = 0;
1207      }
1208      hash_add_mm(p);
1209    } else {
1210      p->use_cnt  = 0;
1211      p->removed  = 1;
1212    }
1213    return p;
1214  }
1215  return NULL;
1216}
1217
1218static int hash_add_file(mm_cache_entry *p TSRMLS_DC) {
1219  int f;
1220  int ret = 0;
1221  char s[MAXPATHLEN];
1222  mm_file_header hdr;
1223
1224#ifdef EACCELERATOR_USE_INODE
1225  if (!eaccelerator_inode_key(s, p->st_dev, p->st_ino TSRMLS_CC)) {
1226    return 0;
1227  }
1228#else
1229  if (!eaccelerator_md5(s, "/eaccelerator-", p->realfilename TSRMLS_CC)) {
1230    return 0;
1231  }
1232#endif
1233
1234  unlink(s);
1235  f = open(s, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, S_IRUSR | S_IWUSR);
1236  if (f > 0) {
1237    EACCELERATOR_FLOCK(f, LOCK_EX);
1238    strcpy(hdr.magic,"EACCELERATOR");
1239    hdr.eaccelerator_version = binary_eaccelerator_version;
1240    hdr.zend_version    = binary_zend_version;
1241    hdr.php_version     = binary_php_version;
1242    hdr.size  = p->size;
1243    hdr.mtime = p->mtime;
1244    p->next = p;
1245    hdr.crc32 = eaccelerator_crc32((const char*)p,p->size);
1246    ret = (write(f, &hdr, sizeof(hdr)) == sizeof(hdr));
1247    if (ret) ret = (write(f, p, p->size) == p->size);
1248    EACCELERATOR_FLOCK(f, LOCK_UN);
1249    close(f);
1250  }
1251  return ret;
1252}
1253
1254typedef union align_union {
1255  double d;
1256  void *v;
1257  int (*func)(int);
1258  long l;
1259} align_union;
1260
1261#if (defined (__GNUC__) && __GNUC__ >= 2)
1262#define EACCELERATOR_PLATFORM_ALIGNMENT (__alignof__ (align_test))
1263#else
1264#define EACCELERATOR_PLATFORM_ALIGNMENT (sizeof(align_union))
1265#endif
1266
1267#define EACCELERATOR_ALIGN(n) (n) = (void*)((((size_t)(n)-1) & ~(EACCELERATOR_PLATFORM_ALIGNMENT-1)) + EACCELERATOR_PLATFORM_ALIGNMENT)
1268
1269/******************************************************************************/
1270
1271#ifndef DEBUG
1272inline
1273#endif
1274static
1275void calc_string(char* str, int len TSRMLS_DC) {
1276  if (len > MAX_DUP_STR_LEN || zend_hash_add(&MMCG(strings), str, len, &str, sizeof(char*), NULL) == SUCCESS) {
1277    EACCELERATOR_ALIGN(MMCG(mem));
1278    MMCG(mem) += len;
1279  }
1280}
1281
1282static void calc_zval(zval* z TSRMLS_DC);
1283static void calc_class_entry(zend_class_entry* from TSRMLS_DC);
1284
1285typedef void (*calc_bucket_t)(void* TSRMLS_DC);
1286
1287#define calc_hash_ex(from, start, calc_bucket) \
1288  calc_hash_int(from, start, calc_bucket TSRMLS_CC)
1289
1290#define calc_hash(from, calc_bucket) \
1291  calc_hash_ex(from, (from)->pListHead, calc_bucket)
1292
1293#define calc_zval_hash(from) \
1294  calc_hash(from, (calc_bucket_t)calc_zval_ptr)
1295
1296#define calc_zval_hash_ex(from, start) \
1297  calc_hash_ex(from, start, (calc_bucket_t)calc_zval_ptr)
1298
1299
1300static void calc_zval_ptr(zval** from TSRMLS_DC) {
1301  EACCELERATOR_ALIGN(MMCG(mem));
1302  MMCG(mem) += sizeof(zval);
1303  calc_zval(*from TSRMLS_CC);
1304}
1305
1306#ifdef ZEND_ENGINE_2
1307static void calc_property_info(zend_property_info* from TSRMLS_DC) {
1308  EACCELERATOR_ALIGN(MMCG(mem));
1309  MMCG(mem) += sizeof(zend_property_info);
1310  calc_string(from->name, from->name_length+1 TSRMLS_CC);
1311}
1312
1313static void calc_class_entry_ptr(zend_class_entry** from TSRMLS_DC) {
1314  calc_class_entry(*from TSRMLS_CC);
1315}
1316#endif
1317
1318static void calc_hash_int(HashTable* source, Bucket* start, calc_bucket_t calc_bucket TSRMLS_DC) {
1319  Bucket* p;
1320
1321  if (source->nNumOfElements > 0) {
1322    if (!MMCG(compress)) {
1323      EACCELERATOR_ALIGN(MMCG(mem));
1324      MMCG(mem) += source->nTableSize * sizeof(Bucket*);
1325    }
1326    p = start;
1327    while (p) {
1328      EACCELERATOR_ALIGN(MMCG(mem));
1329      MMCG(mem) += offsetof(Bucket,arKey)+p->nKeyLength;
1330      calc_bucket(p->pData TSRMLS_CC);
1331      p = p->pListNext;
1332    }
1333  }
1334}
1335
1336static void calc_zval(zval* zv TSRMLS_DC) {
1337  switch (zv->type & ~IS_CONSTANT_INDEX) {
1338    case IS_CONSTANT:
1339    case IS_STRING:
1340      if (zv->value.str.val == NULL ||
1341          zv->value.str.val == empty_string ||
1342          zv->value.str.len == 0) {
1343      } else {
1344        calc_string(zv->value.str.val, zv->value.str.len+1 TSRMLS_CC);
1345      }
1346      break;
1347    case IS_ARRAY:
1348    case IS_CONSTANT_ARRAY:
1349      if (zv->value.ht == NULL || zv->value.ht == &EG(symbol_table)) {
1350      } else {
1351        EACCELERATOR_ALIGN(MMCG(mem));
1352        MMCG(mem) += sizeof(HashTable);
1353        calc_zval_hash(zv->value.ht);
1354      }
1355      break;
1356    case IS_OBJECT:
1357#ifndef ZEND_ENGINE_2
1358      if (zv->value.obj.ce != NULL) {
1359        zend_class_entry *ce = zv->value.obj.ce;
1360        if (!MMCG(compress)) {
1361          debug_printf("[%d] EACCELERATOR can't cache objects\n", getpid());
1362          zend_bailout();
1363        }
1364        while (ce != NULL) {
1365          if (ce->type !=  ZEND_USER_CLASS && strcmp(ce->name,"stdClass") != 0) {
1366            debug_printf("[%d] EACCELERATOR can't cache objects\n", getpid());
1367            zend_bailout();
1368          }
1369          ce = ce->parent;
1370        }
1371        calc_string(zv->value.obj.ce->name, zv->value.obj.ce->name_length+1 TSRMLS_CC);
1372      }
1373      if (zv->value.obj.properties != NULL) {
1374        EACCELERATOR_ALIGN(MMCG(mem));
1375        MMCG(mem) += sizeof(HashTable);
1376        calc_zval_hash(zv->value.obj.properties);
1377      }
1378#endif
1379      return;
1380    case IS_RESOURCE:
1381      debug_printf("[%d] EACCELERATOR can't cache resources\n", getpid());
1382      zend_bailout();
1383    default:
1384      break;
1385  }
1386}
1387
1388static void calc_op_array(zend_op_array* from TSRMLS_DC) {
1389  zend_op *opline;
1390  zend_op *end;
1391
1392  if (from->type == ZEND_INTERNAL_FUNCTION) {
1393    EACCELERATOR_ALIGN(MMCG(mem));
1394    MMCG(mem) += sizeof(zend_internal_function);
1395  } else if (from->type == ZEND_USER_FUNCTION) {
1396    EACCELERATOR_ALIGN(MMCG(mem));
1397    MMCG(mem) += sizeof(eaccelerator_op_array);
1398  } else {
1399    debug_printf("[%d] EACCELERATOR can't cache function \"%s\"\n", getpid(), from->function_name);
1400    zend_bailout();
1401  }
1402#ifdef ZEND_ENGINE_2
1403  if (from->num_args > 0) {
1404    zend_uint i;
1405    EACCELERATOR_ALIGN(MMCG(mem));
1406    MMCG(mem) += from->num_args * sizeof(zend_arg_info);
1407    for (i = 0; i < from->num_args; i++) {
1408      if (from->arg_info[i].name) {
1409        calc_string(from->arg_info[i].name,from->arg_info[i].name_len+1 TSRMLS_CC);
1410      }
1411      if (from->arg_info[i].class_name) {
1412        calc_string(from->arg_info[i].class_name,from->arg_info[i].class_name_len+1 TSRMLS_CC);
1413      }
1414    }
1415  }
1416#else
1417  if (from->arg_types != NULL) {
1418    calc_string((char*)from->arg_types, (from->arg_types[0]+1) * sizeof(zend_uchar) TSRMLS_CC);
1419  }
1420#endif
1421  if (from->function_name != NULL) {
1422    calc_string(from->function_name, strlen(from->function_name)+1 TSRMLS_CC);
1423  }
1424#ifdef ZEND_ENGINE_2
1425  if (from->scope != NULL)
1426  {
1427    // HOESH: the same problem?
1428    Bucket* q = CG(class_table)->pListHead;
1429    while (q != NULL)
1430        {
1431      if (*(zend_class_entry**)q->pData == from->scope)
1432          {
1433        calc_string(q->arKey, q->nKeyLength TSRMLS_CC);
1434        break;
1435      }
1436      q = q->pListNext;
1437    }
1438  }
1439#endif
1440  if (from->type == ZEND_INTERNAL_FUNCTION) {
1441    return;
1442  }
1443
1444  if (from->opcodes != NULL) {
1445    EACCELERATOR_ALIGN(MMCG(mem));
1446    MMCG(mem) += from->last * sizeof(zend_op);
1447
1448    opline = from->opcodes;
1449    end = opline + from->last;
1450    MMCG(compress) = 0;
1451    for (;opline < end; opline++) {
1452/*
1453      if (opline->result.op_type == IS_CONST) calc_zval(&opline->result.u.constant  TSRMLS_CC);
1454*/
1455      if (opline->op1.op_type    == IS_CONST) calc_zval(&opline->op1.u.constant TSRMLS_CC);
1456      if (opline->op2.op_type    == IS_CONST) calc_zval(&opline->op2.u.constant TSRMLS_CC);
1457    }
1458    MMCG(compress) = 1;
1459  }
1460  if (from->brk_cont_array != NULL) {
1461    EACCELERATOR_ALIGN(MMCG(mem));
1462    MMCG(mem) += sizeof(zend_brk_cont_element) * from->last_brk_cont;
1463  }
1464#ifdef ZEND_ENGINE_2
1465        /* HOESH: try & catch support */
1466        if (from->try_catch_array != NULL)
1467        {
1468                EACCELERATOR_ALIGN(MMCG(mem));
1469                MMCG(mem) += sizeof(zend_try_catch_element) * from->last_try_catch;
1470        }
1471#endif
1472  if (from->static_variables != NULL) {
1473    EACCELERATOR_ALIGN(MMCG(mem));
1474    MMCG(mem) += sizeof(HashTable);
1475    calc_zval_hash(from->static_variables);
1476  }
1477  if (from->filename != NULL) {
1478    calc_string(from->filename, strlen(from->filename)+1 TSRMLS_CC);
1479  }
1480#ifdef ZEND_ENGINE_2
1481  if (from->doc_comment != NULL) {
1482    calc_string(from->doc_comment, from->doc_comment_len+1 TSRMLS_CC);
1483  }
1484#endif
1485}
1486
1487static void calc_class_entry(zend_class_entry* from TSRMLS_DC) {
1488  int i;
1489
1490  if (from->type != ZEND_USER_CLASS) {
1491    debug_printf("[%d] EACCELERATOR can't cache internal class \"%s\"\n", getpid(), from->name);
1492    zend_bailout();
1493  }
1494/*
1495  if (from->builtin_functions) {
1496    debug_printf("[%d] EACCELERATOR can't cache class \"%s\" because of it has "
1497        "some builtin_functions\n", getpid(), from->name);
1498    zend_bailout();
1499  }
1500*/
1501  EACCELERATOR_ALIGN(MMCG(mem));
1502  MMCG(mem) += sizeof(eaccelerator_class_entry);
1503
1504  if (from->name != NULL) {
1505    calc_string(from->name, from->name_length+1 TSRMLS_CC);
1506  }
1507  if (from->parent != NULL && from->parent->name) {
1508    calc_string(from->parent->name, from->parent->name_length + 1  TSRMLS_CC);
1509  }
1510#ifdef ZEND_ENGINE_2
1511#if 0
1512  // what's problem. why from->interfaces[i] == 0x5a5a5a5a ?
1513  for (i=0; i<from->num_interfaces; i++) {
1514    if (from->interfaces[i]) {
1515      calc_string(from->interfaces[i]->name, from->interfaces[i]->name_length);
1516    }
1517  }
1518#endif
1519  if (from->filename != NULL) {
1520    calc_string(from->filename, strlen(from->filename)+1 TSRMLS_CC);
1521  }
1522  if (from->doc_comment != NULL) {
1523    calc_string(from->doc_comment, from->doc_comment_len+1 TSRMLS_CC);
1524  }
1525
1526  calc_zval_hash(&from->constants_table);
1527  calc_zval_hash(&from->default_properties);
1528  calc_hash(&from->properties_info, (calc_bucket_t)calc_property_info);
1529  if (from->static_members != NULL) {
1530    EACCELERATOR_ALIGN(MMCG(mem));
1531    MMCG(mem) += sizeof(HashTable);
1532    calc_zval_hash(from->static_members);
1533  }
1534#else
1535  calc_zval_hash(&from->default_properties);
1536#endif
1537  calc_hash(&from->function_table, (calc_bucket_t)calc_op_array);
1538}
1539
1540static int calc_size(char* key, zend_op_array* op_array,
1541                     Bucket* f, Bucket *c TSRMLS_DC) {
1542  Bucket *b;
1543  char   *x;
1544  int len = strlen(key);
1545  MMCG(compress) = 1;
1546  MMCG(mem) = NULL;
1547
1548  zend_hash_init(&MMCG(strings), 0, NULL, NULL, 0);
1549  MMCG(mem) += offsetof(mm_cache_entry,realfilename)+len+1;
1550  zend_hash_add(&MMCG(strings), key, len+1, &key, sizeof(char*), NULL);
1551  b = c;
1552  while (b != NULL) {
1553    EACCELERATOR_ALIGN(MMCG(mem));
1554    MMCG(mem) += offsetof(mm_fc_entry,htabkey)+b->nKeyLength;
1555    x = b->arKey;
1556    zend_hash_add(&MMCG(strings), b->arKey, b->nKeyLength, &x, sizeof(char*), NULL);
1557    b = b->pListNext;
1558  }
1559  b = f;
1560  while (b != NULL) {
1561    EACCELERATOR_ALIGN(MMCG(mem));
1562    MMCG(mem) += offsetof(mm_fc_entry,htabkey)+b->nKeyLength;
1563    x = b->arKey;
1564    zend_hash_add(&MMCG(strings), b->arKey, b->nKeyLength, &x, sizeof(char*), NULL);
1565    b = b->pListNext;
1566  }
1567  while (c != NULL) {
1568#ifdef ZEND_ENGINE_2
1569    calc_class_entry(*(zend_class_entry**)c->pData TSRMLS_CC);
1570#else
1571    calc_class_entry((zend_class_entry*)c->pData TSRMLS_CC);
1572#endif
1573    c = c->pListNext;
1574  }
1575  while (f != NULL) {
1576    calc_op_array((zend_op_array*)f->pData TSRMLS_CC);
1577    f = f->pListNext;
1578  }
1579  calc_op_array(op_array TSRMLS_CC);
1580  EACCELERATOR_ALIGN(MMCG(mem));
1581  zend_hash_destroy(&MMCG(strings));
1582  return (long)MMCG(mem);
1583}
1584
1585/******************************************************************************/
1586
1587static inline char* store_string(char* str, int len TSRMLS_DC) {
1588  char *p;
1589  if (len > MAX_DUP_STR_LEN) {
1590    EACCELERATOR_ALIGN(MMCG(mem));
1591    p = (char*)MMCG(mem);
1592    MMCG(mem) += len;
1593    memcpy(p, str, len);
1594  } else if (zend_hash_find(&MMCG(strings), str, len, (void*)&p) == SUCCESS) {
1595    p = *(char**)p;
1596  } else {
1597    EACCELERATOR_ALIGN(MMCG(mem));
1598    p = (char*)MMCG(mem);
1599    MMCG(mem) += len;
1600    memcpy(p, str, len);
1601    zend_hash_add(&MMCG(strings), str, len, (void*)&p, sizeof(char*), NULL);
1602  }
1603  return p;
1604}
1605
1606static void store_zval(zval* z TSRMLS_DC);
1607static eaccelerator_class_entry* store_class_entry(zend_class_entry* from TSRMLS_DC);
1608
1609typedef void* (*store_bucket_t)(void* TSRMLS_DC);
1610
1611#define store_hash_ex(to, from, start, store_bucket) \
1612  store_hash_int(to, from, start, store_bucket TSRMLS_CC)
1613
1614#define store_hash(to, from, store_bucket) \
1615  store_hash_ex(to, from, (from)->pListHead, store_bucket)
1616
1617#define store_zval_hash(to, from) \
1618  store_hash(to, from, (store_bucket_t)store_zval_ptr)
1619
1620#define store_zval_hash_ex(to, from, start) \
1621  store_hash_ex(to, from, start, (store_bucket_t)store_zval_ptr)
1622
1623static zval* store_zval_ptr(zval* from TSRMLS_DC) {
1624  zval* to;
1625  EACCELERATOR_ALIGN(MMCG(mem));
1626  to = (zval*)MMCG(mem);
1627  MMCG(mem) += sizeof(zval);
1628  memcpy(to, from, sizeof(zval));
1629  store_zval(to TSRMLS_CC);
1630  return to;
1631}
1632
1633#ifdef ZEND_ENGINE_2
1634static zend_property_info* store_property_info(zend_property_info* from TSRMLS_DC) {
1635  zend_property_info* to;
1636  EACCELERATOR_ALIGN(MMCG(mem));
1637  to = (zend_property_info*)MMCG(mem);
1638  MMCG(mem) += sizeof(zend_property_info);
1639  memcpy(to, from, sizeof(zend_property_info));
1640  to->name = store_string(from->name, from->name_length+1 TSRMLS_CC);
1641  return to;
1642}
1643
1644static eaccelerator_class_entry* store_class_entry_ptr(zend_class_entry** from TSRMLS_DC) {
1645  return store_class_entry(*from TSRMLS_CC);
1646}
1647#endif
1648
1649static void store_hash_int(HashTable* target, HashTable* source, Bucket* start, store_bucket_t copy_bucket TSRMLS_DC) {
1650  Bucket *p, *np, *prev_p;
1651
1652  memcpy(target, source, sizeof(HashTable));
1653
1654  if (source->nNumOfElements > 0) {
1655    if (!MMCG(compress)) {
1656      EACCELERATOR_ALIGN(MMCG(mem));
1657      target->arBuckets = (Bucket **)MMCG(mem);
1658      MMCG(mem) += target->nTableSize * sizeof(Bucket*);
1659      memset(target->arBuckets, 0, target->nTableSize * sizeof(Bucket*));
1660    }
1661
1662    target->pDestructor = NULL;
1663    target->persistent  = 1;
1664    target->pListHead   = NULL;
1665    target->pListTail   = NULL;
1666
1667    p = start;
1668    prev_p = NULL;
1669    np = NULL;
1670    while (p) {
1671      EACCELERATOR_ALIGN(MMCG(mem));
1672      np = (Bucket*)MMCG(mem);
1673      MMCG(mem) += offsetof(Bucket,arKey)+p->nKeyLength;
1674
1675      if (!MMCG(compress)) {
1676        int nIndex = p->h % source->nTableSize;
1677        if(target->arBuckets[nIndex]) {
1678          np->pNext = target->arBuckets[nIndex];
1679          np->pLast = NULL;
1680          np->pNext->pLast = np;
1681        } else {
1682          np->pNext = NULL;
1683          np->pLast = NULL;
1684        }
1685        target->arBuckets[nIndex] = np;
1686      }
1687      np->h = p->h;
1688      np->nKeyLength = p->nKeyLength;
1689
1690      if (p->pDataPtr == NULL) {
1691        np->pData    = copy_bucket(p->pData TSRMLS_CC);
1692        np->pDataPtr = NULL;
1693      } else {
1694        np->pDataPtr = copy_bucket(p->pDataPtr TSRMLS_CC);
1695        np->pData    = &np->pDataPtr;
1696      }
1697
1698      np->pListLast = prev_p;
1699      np->pListNext = NULL;
1700
1701      memcpy(np->arKey, p->arKey, p->nKeyLength);
1702
1703      if (prev_p) {
1704        prev_p->pListNext = np;
1705      } else {
1706        target->pListHead = np;
1707      }
1708      prev_p = np;
1709      p = p->pListNext;
1710    }
1711    target->pListTail = np;
1712    target->pInternalPointer = target->pListHead;
1713  }
1714}
1715
1716static void store_zval(zval* zv TSRMLS_DC) {
1717  switch (zv->type & ~IS_CONSTANT_INDEX) {
1718    case IS_CONSTANT:
1719    case IS_STRING:
1720      if (zv->value.str.val == NULL ||
1721          zv->value.str.val == empty_string ||
1722          zv->value.str.len == 0) {
1723        zv->value.str.val = empty_string;
1724        zv->value.str.len = 0;
1725      } else {
1726        zv->value.str.val = store_string(zv->value.str.val, zv->value.str.len+1 TSRMLS_CC);
1727      }
1728      break;
1729    case IS_ARRAY:
1730    case IS_CONSTANT_ARRAY:
1731      if (zv->value.ht == NULL || zv->value.ht == &EG(symbol_table)) {
1732      } else {
1733        HashTable* p;
1734        EACCELERATOR_ALIGN(MMCG(mem));
1735        p = (HashTable*)MMCG(mem);
1736        MMCG(mem) += sizeof(HashTable);
1737        store_zval_hash(p, zv->value.ht);
1738        zv->value.ht = p;
1739      }
1740      break;
1741    case IS_OBJECT:
1742      if (!MMCG(compress)) {
1743        return;
1744      }
1745#ifndef ZEND_ENGINE_2
1746      if (zv->value.obj.ce != NULL) {
1747        char *s = store_string(zv->value.obj.ce->name, zv->value.obj.ce->name_length+1 TSRMLS_CC);
1748        zend_str_tolower(s, zv->value.obj.ce->name_length);
1749        zv->value.obj.ce = (zend_class_entry*)s;
1750      }
1751      if (zv->value.obj.properties != NULL) {
1752        HashTable* p;
1753        EACCELERATOR_ALIGN(MMCG(mem));
1754        p = (HashTable*)MMCG(mem);
1755        MMCG(mem) += sizeof(HashTable);
1756        store_zval_hash(p, zv->value.obj.properties);
1757        zv->value.obj.properties = p;
1758      }
1759#endif
1760    default:
1761      break;
1762  }
1763}
1764
1765static eaccelerator_op_array* store_op_array(zend_op_array* from TSRMLS_DC) {
1766  eaccelerator_op_array *to;
1767  zend_op *opline;
1768  zend_op *end;
1769
1770#ifdef DEBUG
1771  pad(TSRMLS_C);
1772  fprintf(F_fp, "[%d] store_op_array: %s [scope=%s]\n", getpid(),
1773    from->function_name ? from->function_name : "(top)", from->scope ? from->scope->name : "NULL");
1774  fflush(F_fp);
1775#endif
1776
1777  if (from->type == ZEND_INTERNAL_FUNCTION) {
1778    EACCELERATOR_ALIGN(MMCG(mem));
1779    to = (eaccelerator_op_array*)MMCG(mem);
1780    MMCG(mem) += offsetof(eaccelerator_op_array,opcodes);
1781  } else if (from->type == ZEND_USER_FUNCTION) {
1782    EACCELERATOR_ALIGN(MMCG(mem));
1783    to = (eaccelerator_op_array*)MMCG(mem);
1784    MMCG(mem) += sizeof(eaccelerator_op_array);
1785  } else {
1786    return NULL;
1787  }
1788
1789  to->type = from->type;
1790#ifdef ZEND_ENGINE_2
1791  to->num_args = from->num_args;
1792  to->required_num_args = from->required_num_args;
1793  if (from->num_args > 0) {
1794    zend_uint i;
1795    EACCELERATOR_ALIGN(MMCG(mem));
1796    to->arg_info = (zend_arg_info*)MMCG(mem);
1797    MMCG(mem) += from->num_args * sizeof(zend_arg_info);
1798    for (i = 0; i < from->num_args; i++) {
1799      if (from->arg_info[i].name) {
1800        to->arg_info[i].name = store_string(from->arg_info[i].name,from->arg_info[i].name_len+1 TSRMLS_CC);
1801        to->arg_info[i].name_len = from->arg_info[i].name_len;
1802      }
1803      if (from->arg_info[i].class_name) {
1804        to->arg_info[i].class_name = store_string(from->arg_info[i].class_name,from->arg_info[i].class_name_len+1 TSRMLS_CC);
1805        to->arg_info[i].class_name_len = from->arg_info[i].class_name_len;
1806      }
1807      to->arg_info[i].allow_null        = from->arg_info[i].allow_null;
1808      to->arg_info[i].pass_by_reference = from->arg_info[i].pass_by_reference;
1809      to->arg_info[i].return_reference = from->arg_info[i].return_reference;
1810    }
1811  }
1812  to->pass_rest_by_reference = from->pass_rest_by_reference;
1813#else
1814  if (from->arg_types != NULL) {
1815    to->arg_types = (unsigned char*)
1816      store_string((char*)from->arg_types, (from->arg_types[0]+1) * sizeof(zend_uchar) TSRMLS_CC);
1817  }
1818#endif
1819  if (from->function_name != NULL)
1820  {
1821        /*
1822         * HOESH: converting to lowercase. this helps to find
1823         * class methods in function_table without each time tolower...
1824         */
1825        to->function_name = store_string(from->function_name, strlen(from->function_name)+1  TSRMLS_CC);
1826        // XXX: revert
1827    // zend_str_tolower(to->function_name, strlen(from->function_name));
1828  }
1829#ifdef ZEND_ENGINE_2
1830  to->fn_flags         = from->fn_flags;
1831  to->scope_name = NULL;
1832  to->scope_name_len = 0;
1833  if (from->scope != NULL)
1834  {
1835        // HOESH: why? use from->scope->name & from->scope->name_len instead.
1836        // Keep internal class behavior on mind!
1837    Bucket* q = CG(class_table)->pListHead;
1838    while (q != NULL)
1839        {
1840      if (*(zend_class_entry**)q->pData == from->scope)
1841          {
1842        to->scope_name = store_string(q->arKey, q->nKeyLength TSRMLS_CC);
1843        to->scope_name_len = q->nKeyLength - 1;
1844#ifdef DEBUG
1845        pad(TSRMLS_C); fprintf(F_fp, "[%d]                 find scope '%s' in CG(class_table) save hashkey '%s' [%08x] as to->scope_name\n",
1846            getpid(), from->scope->name ? from->scope->name : "NULL", q->arKey, to->scope_name); fflush(F_fp);
1847#endif
1848        break;
1849      }
1850      q = q->pListNext;
1851    }
1852    if (to->scope_name == NULL)
1853    {
1854#ifdef DEBUG
1855      pad(TSRMLS_C); fprintf(F_fp, "[%d]                 could not find scope '%s' in CG(class_table), saving it to NULL\n", getpid(), from->scope->name ? from->scope->name : "NULL"); fflush(F_fp);
1856#endif
1857    }
1858  }
1859#endif
1860  if (from->type == ZEND_INTERNAL_FUNCTION) {
1861    return to;
1862  }
1863  to->opcodes          = from->opcodes;
1864  to->last             = from->last;
1865  to->T                = from->T;
1866  to->brk_cont_array   = from->brk_cont_array;
1867  to->last_brk_cont    = from->last_brk_cont;
1868#ifdef ZEND_ENGINE_2
1869        /* HOESH: try & catch support */
1870        to->try_catch_array   = from->try_catch_array;
1871        to->last_try_catch    = from->last_try_catch;
1872  to->uses_this        = from->uses_this;
1873#else
1874  to->uses_globals     = from->uses_globals;
1875#endif
1876  to->static_variables = from->static_variables;
1877  to->return_reference = from->return_reference;
1878  to->filename         = from->filename;
1879
1880  if (from->opcodes != NULL) {
1881    EACCELERATOR_ALIGN(MMCG(mem));
1882    to->opcodes = (zend_op*)MMCG(mem);
1883    MMCG(mem) += from->last * sizeof(zend_op);
1884    memcpy(to->opcodes, from->opcodes, from->last * sizeof(zend_op));
1885
1886    opline = to->opcodes;
1887    end = opline + to->last;
1888    MMCG(compress) = 0;
1889    for (;opline < end; opline++) {
1890/*
1891      if (opline->result.op_type == IS_CONST) store_zval(&opline->result.u.constant  TSRMLS_CC);
1892*/
1893      if (opline->op1.op_type    == IS_CONST) store_zval(&opline->op1.u.constant TSRMLS_CC);
1894      if (opline->op2.op_type    == IS_CONST) store_zval(&opline->op2.u.constant TSRMLS_CC);
1895#ifdef ZEND_ENGINE_2
1896      switch (opline->opcode) {
1897        case ZEND_JMP:
1898          opline->op1.u.jmp_addr = to->opcodes + (opline->op1.u.jmp_addr - from->opcodes);
1899          break;
1900        case ZEND_JMPZ:
1901        case ZEND_JMPNZ:
1902        case ZEND_JMPZ_EX:
1903        case ZEND_JMPNZ_EX:
1904          opline->op2.u.jmp_addr = to->opcodes + (opline->op2.u.jmp_addr - from->opcodes);
1905          break;
1906      }
1907#endif
1908    }
1909    MMCG(compress) = 1;
1910  }
1911  if (from->brk_cont_array != NULL) {
1912    EACCELERATOR_ALIGN(MMCG(mem));
1913    to->brk_cont_array = (zend_brk_cont_element*)MMCG(mem);
1914    MMCG(mem) += sizeof(zend_brk_cont_element) * from->last_brk_cont;
1915    memcpy(to->brk_cont_array, from->brk_cont_array,
1916           sizeof(zend_brk_cont_element) * from->last_brk_cont);
1917  } else {
1918    to->last_brk_cont  = 0;
1919  }
1920#ifdef ZEND_ENGINE_2
1921        /* HOESH: try & catch support */
1922        if (from->try_catch_array != NULL)
1923        {
1924                EACCELERATOR_ALIGN(MMCG(mem));
1925                to->try_catch_array = (zend_try_catch_element*)MMCG(mem);
1926                MMCG(mem) += sizeof(zend_try_catch_element) * from->last_try_catch;
1927                memcpy(to->try_catch_array, from->try_catch_array,
1928                        sizeof(zend_try_catch_element) * from->last_try_catch);
1929        }
1930        else
1931        {
1932                to->last_try_catch  = 0;
1933        }
1934#endif
1935  if (from->static_variables != NULL) {
1936    EACCELERATOR_ALIGN(MMCG(mem));
1937    to->static_variables = (HashTable*)MMCG(mem);
1938    MMCG(mem) += sizeof(HashTable);
1939    store_zval_hash(to->static_variables, from->static_variables);
1940  }
1941  if (from->filename != NULL) {
1942    to->filename =
1943      store_string(to->filename, strlen(from->filename)+1 TSRMLS_CC);
1944  }
1945#ifdef ZEND_ENGINE_2
1946  to->line_start      = from->line_start;
1947  to->line_end        = from->line_end;
1948  to->doc_comment_len = from->doc_comment_len;
1949  if (from->doc_comment != NULL) {
1950    to->doc_comment = store_string(from->doc_comment, from->doc_comment_len+1 TSRMLS_CC);
1951  }
1952#endif
1953  return to;
1954}
1955
1956static eaccelerator_class_entry* store_class_entry(zend_class_entry* from TSRMLS_DC) {
1957  eaccelerator_class_entry *to;
1958  int i;
1959
1960  EACCELERATOR_ALIGN(MMCG(mem));
1961  to = (eaccelerator_class_entry*)MMCG(mem);
1962  MMCG(mem) += sizeof(eaccelerator_class_entry);
1963  to->type        = from->type;
1964  to->name        = NULL;
1965  to->name_length = from->name_length;
1966  to->parent      = NULL;
1967#ifdef ZEND_ENGINE_2
1968  to->ce_flags    = from->ce_flags;
1969  to->static_members = NULL;
1970  to->num_interfaces = from->num_interfaces;
1971
1972#if 0
1973  // i need to check more. why this field is null.
1974  //
1975  for (i=0; i<from->num_interfaces; i++) {
1976    if (from->interfaces[i]) {
1977      to->interfaces[i] = store_string(from->interfaces[i]->name, from->interfaces[i]->name_length);
1978    }
1979  }
1980#endif
1981
1982#endif
1983
1984#ifdef DEBUG
1985  pad(TSRMLS_C);
1986  fprintf(F_fp, "[%d] store_class_entry: %s parent was '%s'\n", getpid(), from->name? from->name : "(top)", from->parent ? from->parent->name : "NULL");
1987  fflush(F_fp);
1988  MMCG(xpad)++;
1989#endif
1990
1991  if (from->name != NULL) {
1992    to->name = store_string(from->name, from->name_length+1 TSRMLS_CC);
1993        //XXX: revert
1994    // zend_str_tolower(to->name, from->name_length);
1995  }
1996  if (from->parent != NULL && from->parent->name) {
1997    to->parent = store_string(from->parent->name, from->parent->name_length+1 TSRMLS_CC);
1998    //XXX: revert
1999    // zend_str_tolower(to->parent, from->parent->name_length);
2000  }
2001
2002/*
2003  if (!from->constants_updated) {
2004    zend_hash_apply_with_argument(&from->default_properties, (apply_func_arg_t) zval_update_constant, (void *) 1 TSRMLS_CC);
2005    to->constants_updated = 1;
2006  }
2007*/
2008#ifdef ZEND_ENGINE_2
2009  to->line_start                 = from->line_start;
2010  to->line_end                   = from->line_end;
2011  to->doc_comment_len            = from->doc_comment_len;
2012  to->iterator_funcs             = from->iterator_funcs;
2013  to->create_object              = from->create_object;
2014  to->get_iterator               = from->get_iterator;
2015  to->interface_gets_implemented = from->interface_gets_implemented;
2016
2017  if (from->filename != NULL) {
2018    to->filename = store_string(from->filename, strlen(from->filename)+1 TSRMLS_CC);
2019  }
2020  if (from->doc_comment != NULL) {
2021    to->doc_comment = store_string(from->doc_comment, from->doc_comment_len+1 TSRMLS_CC);
2022  }
2023
2024  store_zval_hash(&to->constants_table, &from->constants_table);
2025  store_zval_hash(&to->default_properties, &from->default_properties);
2026  store_hash(&to->properties_info, &from->properties_info, (store_bucket_t)store_property_info);
2027  if (from->static_members != NULL) {
2028    EACCELERATOR_ALIGN(MMCG(mem));
2029    to->static_members = (HashTable*)MMCG(mem);
2030    MMCG(mem) += sizeof(HashTable);
2031    store_zval_hash(to->static_members, from->static_members);
2032  }
2033#else
2034  store_zval_hash(&to->default_properties, &from->default_properties);
2035#endif
2036  store_hash(&to->function_table, &from->function_table, (store_bucket_t)store_op_array);
2037
2038#ifdef DEBUG
2039  MMCG(xpad)--;
2040#endif
2041
2042  return to;
2043}
2044
2045static mm_cache_entry* eaccelerator_store_int(
2046                         char* key, int len,
2047                         zend_op_array* op_array,
2048                         Bucket* f, Bucket *c TSRMLS_DC) {
2049  mm_cache_entry *p;
2050  mm_fc_entry    *fc;
2051  mm_fc_entry    *q;
2052  char *x;
2053
2054#ifdef DEBUG
2055  pad(TSRMLS_C); fprintf(F_fp, "[%d] eaccelerator_store_int: key='%s'\n", getpid(), key); fflush(F_fp);
2056#endif
2057
2058  MMCG(compress) = 1;
2059  zend_hash_init(&MMCG(strings), 0, NULL, NULL, 0);
2060  p = (mm_cache_entry*)MMCG(mem);
2061  MMCG(mem) += offsetof(mm_cache_entry,realfilename)+len+1;
2062
2063  p->nhits    = 0;
2064  p->use_cnt  = 0;
2065  p->removed  = 0;
2066  p->f_head   = NULL;
2067  p->c_head   = NULL;
2068  memcpy(p->realfilename, key, len+1);
2069  x = p->realfilename;
2070  zend_hash_add(&MMCG(strings), key, len+1, &x, sizeof(char*), NULL);
2071
2072  q = NULL;
2073  while (c != NULL) {
2074#ifdef DEBUG
2075  pad(TSRMLS_C); fprintf(F_fp, "[%d] eaccelerator_store_int:     class hashkey=", getpid()); binary_print(c->arKey, c->nKeyLength); fflush(F_fp);
2076#endif
2077    EACCELERATOR_ALIGN(MMCG(mem));
2078    fc = (mm_fc_entry*)MMCG(mem);
2079    MMCG(mem) += offsetof(mm_fc_entry,htabkey)+c->nKeyLength;
2080    memcpy(fc->htabkey, c->arKey, c->nKeyLength);
2081    fc->htablen = c->nKeyLength;
2082    fc->next = NULL;
2083#ifdef ZEND_ENGINE_2
2084    fc->fc = *(zend_class_entry**)c->pData;
2085#else
2086    fc->fc = c->pData;
2087#endif
2088    c = c->pListNext;
2089    x = fc->htabkey;
2090    zend_hash_add(&MMCG(strings), fc->htabkey, fc->htablen, &x, sizeof(char*), NULL);
2091    if (q == NULL) {
2092      p->c_head = fc;
2093    } else {
2094      q->next = fc;
2095    }
2096    q = fc;
2097  }
2098
2099  q = NULL;
2100  while (f != NULL) {
2101#ifdef DEBUG
2102  pad(TSRMLS_C); fprintf(F_fp, "[%d] eaccelerator_store_int:     function hashkey='%s'\n", getpid(), f->arKey); fflush(F_fp);
2103#endif
2104    EACCELERATOR_ALIGN(MMCG(mem));
2105    fc = (mm_fc_entry*)MMCG(mem);
2106    MMCG(mem) += offsetof(mm_fc_entry,htabkey)+f->nKeyLength;
2107    memcpy(fc->htabkey, f->arKey, f->nKeyLength);
2108    fc->htablen = f->nKeyLength;
2109    fc->next = NULL;
2110    fc->fc = f->pData;
2111    f = f->pListNext;
2112    x = fc->htabkey;
2113    zend_hash_add(&MMCG(strings), fc->htabkey, fc->htablen, &x, sizeof(char*), NULL);
2114    if (q == NULL) {
2115      p->f_head = fc;
2116    } else {
2117      q->next = fc;
2118    }
2119    q = fc;
2120  }
2121
2122  q = p->c_head;
2123  while (q != NULL) {
2124#ifdef ZEND_ENGINE_2
2125    q->fc = store_class_entry((zend_class_entry*)q->fc TSRMLS_CC);
2126#else
2127    q->fc = store_class_entry((zend_class_entry*)q->fc TSRMLS_CC);
2128#endif
2129    q = q->next;
2130  }
2131
2132  q = p->f_head;
2133  while (q != NULL) {
2134    q->fc = store_op_array((zend_op_array*)q->fc TSRMLS_CC);
2135    q = q->next;
2136  }
2137  p->op_array = store_op_array(op_array TSRMLS_CC);
2138
2139  zend_hash_destroy(&MMCG(strings));
2140  return p;
2141}
2142
2143/* called after succesful compilation, from eaccelerator_compile file */
2144static int eaccelerator_store(char* key, struct stat *buf, int nreloads,
2145                         zend_op_array* op_array,
2146                         Bucket* f, Bucket *c TSRMLS_DC) {
2147  mm_cache_entry *p;
2148  int len = strlen(key);
2149  int use_shm = 1;
2150  int ret = 0;
2151  int size = 0;
2152
2153  zend_try {
2154    size = calc_size(key, op_array, f, c TSRMLS_CC);
2155  } zend_catch {
2156    size =  0;
2157  } zend_end_try();
2158  if (size == 0) {
2159    return 0;
2160  }
2161  EACCELERATOR_UNPROTECT();
2162  MMCG(mem) = eaccelerator_malloc(size);
2163  if (MMCG(mem) == NULL) {
2164    MMCG(mem) = eaccelerator_malloc2(size TSRMLS_CC);
2165  }
2166  if (!MMCG(mem) && !eaccelerator_scripts_shm_only) {
2167    EACCELERATOR_PROTECT();
2168    MMCG(mem) = emalloc(size);
2169    use_shm = 0;
2170  }
2171  if (MMCG(mem)) {
2172    memset(MMCG(mem), 0, size);
2173    p = eaccelerator_store_int(key, len, op_array, f, c TSRMLS_CC);
2174    p->mtime    = buf->st_mtime;
2175    p->filesize = buf->st_size;
2176    p->size     = size;
2177    p->nreloads = nreloads;
2178#ifdef EACCELERATOR_USE_INODE
2179    p->st_dev   = buf->st_dev;
2180    p->st_ino   = buf->st_ino;
2181#endif
2182    if (use_shm) {
2183      if (eaccelerator_shm_ttl > 0) {
2184        p->ttl = time(0) + eaccelerator_shm_ttl;
2185      } else {
2186        p->ttl = 0;
2187      }
2188      if (!eaccelerator_scripts_shm_only) {
2189        hash_add_file(p TSRMLS_CC);
2190      }
2191      hash_add_mm(p);
2192      EACCELERATOR_PROTECT();
2193      ret = 1;
2194    } else {
2195      ret =  hash_add_file(p TSRMLS_CC);
2196      efree(p);
2197    }
2198  }
2199  return ret;
2200}
2201
2202/******************************************************************************/
2203
2204static void restore_zval(zval * TSRMLS_DC);
2205static zend_class_entry* restore_class_entry(zend_class_entry* to, eaccelerator_class_entry *from TSRMLS_DC);
2206
2207typedef void* (*restore_bucket_t)(void* TSRMLS_DC);
2208
2209#define restore_zval_hash(target, source) \
2210  restore_hash(target, source, (restore_bucket_t)restore_zval_ptr TSRMLS_CC)
2211
2212static zval* restore_zval_ptr(zval* from TSRMLS_DC) {
2213  zval* p;
2214  ALLOC_ZVAL(p);
2215  memcpy(p, from, sizeof(zval));
2216  restore_zval(p TSRMLS_CC);
2217  return p;
2218}
2219
2220#ifdef ZEND_ENGINE_2
2221static zend_property_info* restore_property_info(zend_property_info* from TSRMLS_DC) {
2222  zend_property_info* to = emalloc(sizeof(zend_property_info));
2223  memcpy(to, from, sizeof(zend_property_info));
2224  to->name = emalloc(from->name_length+1);
2225  memcpy(to->name, from->name, from->name_length+1);
2226  return to;
2227}
2228
2229static zend_class_entry* restore_class_entry_ptr(eaccelerator_class_entry *from TSRMLS_DC) {
2230  return restore_class_entry(NULL, from TSRMLS_CC);
2231}
2232#endif
2233
2234static HashTable* restore_hash(HashTable *target, HashTable *source, restore_bucket_t copy_bucket TSRMLS_DC)
2235{
2236  Bucket *p, *np, *prev_p;
2237  int nIndex;
2238
2239  if (target == NULL) {
2240    ALLOC_HASHTABLE(target);
2241  }
2242  memcpy(target, source, sizeof(HashTable));
2243  target->arBuckets = (Bucket **) emalloc(target->nTableSize * sizeof(Bucket*));
2244  memset(target->arBuckets, 0, target->nTableSize * sizeof(Bucket*));
2245  target->pDestructor = NULL;
2246  target->persistent  = 0;
2247  target->pListHead   = NULL;
2248  target->pListTail   = NULL;
2249
2250  p = source->pListHead;
2251  prev_p = NULL;
2252  np = NULL;
2253  while (p) {
2254    np = (Bucket *) emalloc(offsetof(Bucket,arKey) + p->nKeyLength);
2255/*    np = (Bucket *) emalloc(sizeof(Bucket) + p->nKeyLength);*/
2256    nIndex = p->h % source->nTableSize;
2257    if(target->arBuckets[nIndex]) {
2258      np->pNext = target->arBuckets[nIndex];
2259      np->pLast = NULL;
2260      np->pNext->pLast = np;
2261    } else {
2262      np->pNext = NULL;
2263      np->pLast = NULL;
2264    }
2265    target->arBuckets[nIndex] = np;
2266    np->h = p->h;
2267    np->nKeyLength = p->nKeyLength;
2268
2269    if (p->pDataPtr == NULL) {
2270      np->pData    = copy_bucket(p->pData TSRMLS_CC);
2271      np->pDataPtr = NULL;
2272    } else {
2273      np->pDataPtr = copy_bucket(p->pDataPtr TSRMLS_CC);
2274      np->pData    = &np->pDataPtr;
2275    }
2276    np->pListLast = prev_p;
2277    np->pListNext = NULL;
2278
2279    memcpy(np->arKey, p->arKey, p->nKeyLength);
2280
2281    if (prev_p) {
2282      prev_p->pListNext = np;
2283    } else {
2284      target->pListHead = np;
2285    }
2286    prev_p = np;
2287    p = p->pListNext;
2288  }
2289  target->pListTail = np;
2290  target->pInternalPointer = target->pListHead;
2291  return target;
2292}
2293
2294static void restore_zval(zval *zv TSRMLS_DC)
2295{
2296  switch (zv->type & ~IS_CONSTANT_INDEX) {
2297    case IS_CONSTANT:
2298    case IS_STRING:
2299      if (zv->value.str.val == NULL || zv->value.str.val == empty_string || zv->value.str.len == 0) {
2300        zv->value.str.val = empty_string;
2301        return;
2302      } else {
2303        char *p = emalloc(zv->value.str.len+1);
2304        memcpy(p, zv->value.str.val, zv->value.str.len+1);
2305        zv->value.str.val = p;
2306      }
2307      return;
2308
2309    case IS_ARRAY:
2310    case IS_CONSTANT_ARRAY:
2311      if (zv->value.ht != NULL && zv->value.ht != &EG(symbol_table)) {
2312        zv->value.ht = restore_zval_hash(NULL, zv->value.ht);
2313        zv->value.ht->pDestructor = ZVAL_PTR_DTOR;
2314      }
2315      return;
2316    case IS_OBJECT: {
2317#ifndef ZEND_ENGINE_2
2318      zend_bool incomplete_class = 0;
2319      char* class_name = (char*)zv->value.obj.ce;
2320      int   name_len = 0;
2321      if (!MMCG(compress)) {
2322        return;
2323      }
2324      if (class_name != NULL) {
2325        zend_class_entry *ce = NULL;
2326        name_len = strlen(class_name);
2327        if (zend_hash_find(CG(class_table), (void*)class_name, name_len+1,
2328            (void **)&ce) != SUCCESS) {
2329          char *lowercase_name = estrndup(INCOMPLETE_CLASS, sizeof(INCOMPLETE_CLASS));
2330          zend_str_tolower(lowercase_name, sizeof(INCOMPLETE_CLASS));
2331          if (zend_hash_find(CG(class_table),lowercase_name, sizeof(INCOMPLETE_CLASS),
2332            (void **)&ce) != SUCCESS) {
2333            efree(lowercase_name);
2334            zend_error(E_ERROR, "EACCELERATOR can't restore object's class \"%s\"", class_name);
2335          } else {
2336            efree(lowercase_name);
2337            zv->value.obj.ce = ce;
2338            incomplete_class = 1;
2339          }
2340        } else {
2341          zv->value.obj.ce = ce;
2342        }
2343      }
2344      if (zv->value.obj.properties != NULL) {
2345        zv->value.obj.properties = restore_zval_hash(NULL, zv->value.obj.properties);
2346        zv->value.obj.properties->pDestructor = ZVAL_PTR_DTOR;
2347        /* Clearing references */
2348        {
2349          Bucket* p = zv->value.obj.properties->pListHead;
2350          while (p != NULL) {
2351            ((zval*)(p->pDataPtr))->refcount = 1;
2352            p = p->pListNext;
2353          }
2354        }
2355      }
2356      if (incomplete_class && class_name != NULL) {
2357        zval *val;
2358        MAKE_STD_ZVAL(val);
2359        Z_TYPE_P(val)   = IS_STRING;
2360        Z_STRVAL_P(val) = estrndup(class_name, name_len);
2361        Z_STRLEN_P(val) = name_len;
2362        zend_hash_update(Z_OBJPROP_P(zv), MAGIC_MEMBER, sizeof(MAGIC_MEMBER), &val, sizeof(val), NULL);
2363      }
2364#endif
2365      return;
2366    }
2367  }
2368}
2369
2370static void call_op_array_ctor_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC) {
2371  if (extension->op_array_ctor) {
2372    extension->op_array_ctor(op_array);
2373  }
2374}
2375
2376static zend_op_array* restore_op_array(zend_op_array *to, eaccelerator_op_array *from TSRMLS_DC) {
2377  zend_function* function;
2378
2379#ifdef DEBUG
2380  pad(TSRMLS_C);
2381  fprintf(F_fp, "[%d] restore_op_array: %s\n", getpid(),
2382    from->function_name? from->function_name : "(top)");
2383  fflush(F_fp);
2384#endif
2385
2386  if (from->type == ZEND_INTERNAL_FUNCTION) {
2387    if (to == NULL) {
2388      to = emalloc(sizeof(zend_internal_function));
2389    }
2390    memset(to, 0, sizeof(zend_internal_function));
2391  } else {
2392    if (to == NULL) {
2393      to = emalloc(sizeof(zend_op_array));
2394    }
2395    memset(to, 0, sizeof(zend_op_array));
2396    if (ZendOptimizer) {
2397      zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) call_op_array_ctor_handler, to TSRMLS_CC);
2398    }
2399  }
2400  to->type             = from->type;
2401#ifdef ZEND_ENGINE_2
2402  /* this is internal function's case
2403   * struct zend_internal_function
2404        zend_uchar type;
2405        char *function_name;           
2406        zend_class_entry *scope;
2407        zend_uint fn_flags;     
2408        union _zend_function *prototype;
2409        zend_uint num_args;
2410        zend_uint required_num_args;
2411        zend_arg_info *arg_info;
2412        zend_bool pass_rest_by_reference;
2413        unsigned char return_reference;
2414    */
2415  /*
2416   * typedef struct _zend_internal_function {
2417   * // Common elements
2418   *    zend_uchar type;
2419   *    char *function_name;           
2420   *    zend_class_entry *scope;
2421   *    zend_uint fn_flags;     
2422   *    union _zend_function *prototype;
2423   *    zend_uint num_args;
2424   *    zend_uint required_num_args;
2425   *    zend_arg_info *arg_info;
2426   *    zend_bool pass_rest_by_reference;
2427   *    unsigned char return_reference;
2428   * // END of common elements
2429   *
2430   *    void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
2431   * } zend_internal_function;
2432   */
2433  to->num_args = from->num_args;
2434  to->required_num_args      = from->required_num_args;
2435  to->arg_info = from->arg_info;
2436  to->pass_rest_by_reference = from->pass_rest_by_reference;
2437#else
2438  to->arg_types        = from->arg_types;
2439#endif
2440  to->function_name    = from->function_name;
2441
2442#ifdef ZEND_ENGINE_2
2443 
2444  int    fname_len;
2445  char  *fname_lc;
2446
2447  if (to->function_name)
2448  {
2449    fname_len = strlen(to->function_name);
2450    fname_lc  = zend_str_tolower_dup(to->function_name, fname_len);
2451  }
2452
2453  to->fn_flags         = from->fn_flags;
2454
2455  /* segv74:
2456   * to->scope = MMCG(class_entry)
2457   *
2458   * if  from->scope_name == NULL,
2459   *     ; MMCG(class) == NULL  : we are in function or outside function.
2460   *     ; MMCG(class) != NULL  : inherited method not defined in current file, should have to find.
2461   *                              just LINK (zend_op_array *) to to original entry in parent,
2462   *                              but, with what? !!! I don't know PARENT CLASS NAME !!!!
2463   *
2464   *
2465   * if  from->scope_name != NULL,
2466   *     ; we are in class member function
2467   *
2468   *     ; we have to find appropriate (zend_class_entry*) to->scope for name from->scope_name
2469   *     ; if we find in CG(class_table), link to it.
2470   *     ; if fail, it should be MMCG(class_entry)
2471   *   
2472   * am I right here ? ;-(
2473   */
2474  if (from->scope_name != NULL)
2475  {
2476        char  *from_scope_lc = zend_str_tolower_dup(from->scope_name, from->scope_name_len);
2477        if (zend_hash_find(CG(class_table), (void *)from_scope_lc, from->scope_name_len+1, (void **)&to->scope) != SUCCESS)
2478    {
2479#ifdef DEBUG
2480      pad(TSRMLS_C); fprintf(F_fp, "[%d]                   can't find '%s' in hash. use MMCG(class_entry).\n", getpid(), from_scope_lc); fflush(F_fp);
2481#endif
2482          to->scope = MMCG(class_entry);
2483    }
2484    else
2485    {
2486#ifdef DEBUG
2487      pad(TSRMLS_C); fprintf(F_fp, "[%d]                   found '%s' in hash\n", getpid(), from_scope_lc); fflush(F_fp);
2488#endif
2489      to->scope = *(zend_class_entry **)(to->scope);
2490    }
2491    efree(from_scope_lc);
2492  }
2493  else
2494  {
2495#ifdef DEBUG
2496      pad(TSRMLS_C); fprintf(F_fp, "[%d]                   from is NULL\n", getpid()); fflush(F_fp);
2497#endif
2498    if (MMCG(class_entry))
2499    {
2500      zend_class_entry *p;
2501
2502      for (p = MMCG(class_entry)->parent; p; p = p->parent)
2503      {
2504#ifdef DEBUG
2505      pad(TSRMLS_C); fprintf(F_fp, "[%d]                   checking parent '%s' have '%s'\n", getpid(), p->name, fname_lc); fflush(F_fp);
2506#endif
2507                if (zend_hash_find(&p->function_table, fname_lc, fname_len+1, (void **) &function)==SUCCESS)
2508        {
2509#ifdef DEBUG
2510      pad(TSRMLS_C); fprintf(F_fp, "[%d]                                   '%s' has '%s' of scope '%s'\n", getpid(), p->name, fname_lc, function->common.scope->name); fflush(F_fp);
2511#endif
2512          to->scope = function->common.scope;
2513          break;
2514        }
2515      }
2516    }
2517    else
2518      to->scope = NULL;
2519  }
2520
2521#ifdef DEBUG
2522  pad(TSRMLS_C);
2523  fprintf(F_fp, "[%d]                   %s's scope is '%s'\n", getpid(),
2524    from->function_name ? from->function_name : "(top)", to->scope ? to->scope->name : "NULL");
2525  fflush(F_fp);
2526#endif
2527#if 0
2528        if (to->scope != NULL)
2529        {
2530                unsigned int len = strlen(to->function_name);
2531                char *lcname = zend_str_tolower_dup(to->function_name, len);
2532                char *lc_to_name = zend_str_tolower_dup(to->scope->name, to->scope->name_length);
2533                /*
2534                 * HOESH: this one probably the old style constructor,
2535                 * so we set this as the constructor for the scope if
2536                 * 0) it doesn't exists yet,
2537                 * or, if the constructor is inherited from the parent:
2538                 * A) the constructor is internal function
2539                 * B) the constructor's scope name doesn't match the oparray's scope name
2540                 *
2541                 * remember lcname & len can be used as scope name info after the match!
2542                 */
2543
2544    /* segv74: I got a question.
2545     *
2546     *         I think that, this code is reconstructing zend_class_entry thing.
2547     *         is it right doing this here?
2548     *
2549     *         IMHO, we can do this job in restore_class_entry().
2550     *         it's not good for readablity, and dosen't have performace gain.
2551     */
2552#ifdef DEBUG
2553  pad(TSRMLS_C);
2554  fprintf(F_fp, "        scope: %s[%d], method name: %s[%d] (%d) : to->scope->constructor=0x%08x\n",
2555      lcname, to->scope->name_length, lc_to_name, len, memcmp(lc_to_name, lcname, len), to->scope->constructor);
2556  fflush(F_fp);
2557#endif
2558                if  (
2559                                to->scope->name_length == len &&
2560                                memcmp(lc_to_name, lcname, len) == 0 &&
2561                                (
2562                                        to->scope->constructor == NULL || // case 0)
2563                                        to->scope->constructor->type == ZEND_INTERNAL_FUNCTION || // case A)
2564                                        to->scope->constructor->op_array.scope->name_length != len || // case B)
2565                                        memcmp(to->scope->constructor->op_array.scope->name, lcname, len) != 0
2566                                )
2567                        )
2568                {
2569#ifdef DEBUG
2570  pad(TSRMLS_C);
2571  fprintf(F_fp, "------>    matched\n");
2572  fflush(F_fp);
2573#endif
2574                        to->scope->constructor = (zend_function*)to;
2575                }
2576                /* HOESH: To avoid unnecessary lookups */
2577                else if (*lcname == '_' && *(lcname+1) == '_')
2578                {
2579                        if (len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1 &&
2580                                memcmp(lcname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)) == 0)
2581                        {
2582                                to->scope->constructor = (zend_function*)to;
2583                        }
2584                        else if (len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1 &&
2585                                memcmp(lcname, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)) == 0)
2586                        {
2587                                to->scope->destructor = (zend_function*)to;
2588                        }
2589                        else if (len == sizeof(ZEND_CLONE_FUNC_NAME)-1 &&
2590                                memcmp(lcname, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)) == 0)
2591                        {
2592                                to->scope->clone = (zend_function*)to;
2593                        }
2594                        else if (len == sizeof(ZEND_GET_FUNC_NAME)-1 &&
2595                                memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)) == 0)
2596                        {
2597                                to->scope->__get = (zend_function*)to;
2598                        }
2599                        else if (len == sizeof(ZEND_SET_FUNC_NAME)-1 &&
2600                                memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)) == 0)
2601                        {
2602                                to->scope->__set = (zend_function*)to;
2603                        }
2604                        else if (len == sizeof(ZEND_CALL_FUNC_NAME)-1 &&
2605                                memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)) == 0)
2606                        {
2607                                to->scope->__call = (zend_function*)to;
2608                        }
2609                }
2610                efree(lcname);
2611        efree(lc_to_name);
2612        }
2613#endif
2614#endif
2615  if (from->type == ZEND_INTERNAL_FUNCTION)
2616  {
2617        zend_class_entry* ce = MMCG(class_entry);
2618#ifdef DEBUG
2619    pad(TSRMLS_C); fprintf(F_fp, "[%d]                   [internal function from=%08x,to=%08x] ce='%s' [%08x]\n", getpid(), from, to, ce->name, ce); fflush(F_fp);
2620    if (ce)
2621    {
2622      pad(TSRMLS_C); fprintf(F_fp, "[%d]                                       ce->parent='%s' [%08x]\n", getpid(), ce->parent->name, ce->parent); fflush(F_fp);
2623    }
2624#endif
2625    if (ce != NULL &&
2626                ce->parent != NULL &&
2627                zend_hash_find(&ce->parent->function_table,
2628#ifdef ZEND_ENGINE_2
2629                        fname_lc, fname_len+1,
2630#else
2631                        to->function_name, strlen(to->function_name)+1,
2632#endif
2633                        (void **) &function)==SUCCESS &&
2634                function->type == ZEND_INTERNAL_FUNCTION)
2635        {
2636#ifdef DEBUG
2637      pad(TSRMLS_C); fprintf(F_fp, "[%d]                                       found in function table\n", getpid()); fflush(F_fp);
2638#endif
2639                ((zend_internal_function*)(to))->handler = ((zend_internal_function*) function)->handler;
2640    }
2641        else
2642        {
2643      /*??? FIXME. I don't know how to fix handler. */
2644                /*
2645                 * HOESH TODO: must solve this somehow, to avoid returnin
2646                 * damaged structure...
2647                 */
2648#ifdef DEBUG
2649      pad(TSRMLS_C); fprintf(F_fp, "[%d]                                       can't find\n", getpid()); fflush(F_fp);
2650#endif
2651    }
2652    return to;
2653  }
2654  to->opcodes          = from->opcodes;
2655  to->last = to->size  = from->last;
2656  to->T                = from->T;
2657  to->brk_cont_array   = from->brk_cont_array;
2658  to->last_brk_cont    = from->last_brk_cont;
2659/*
2660  to->current_brk_cont = -1;
2661  to->static_variables = from->static_variables;
2662  to->start_op         = to->opcodes;
2663  to->backpatch_count  = 0;
2664*/
2665  to->return_reference = from->return_reference;
2666  to->done_pass_two    = 1;
2667  to->filename         = from->filename;
2668#ifdef ZEND_ENGINE_2
2669        /* HOESH: try & catch support */
2670        to->try_catch_array   = from->try_catch_array;
2671        to->last_try_catch    = from->last_try_catch;
2672  to->uses_this        = from->uses_this;
2673
2674  to->line_start      = from->line_start;
2675  to->line_end        = from->line_end;
2676  to->doc_comment_len = from->doc_comment_len;
2677  to->doc_comment     = from->doc_comment;
2678/*???
2679  if (from->doc_comment != NULL) {
2680    to->doc_comment = emalloc(from->doc_comment_len+1);
2681    memcpy(to->doc_comment, from->doc_comment, from->doc_comment_len+1);
2682  }
2683*/
2684#else
2685  to->uses_globals     = from->uses_globals;
2686#endif
2687  if (from->static_variables) {
2688    to->static_variables = restore_zval_hash(NULL, from->static_variables);
2689    to->static_variables->pDestructor = ZVAL_PTR_DTOR;
2690#ifndef ZEND_ENGINE_2
2691    if (MMCG(class_entry) != NULL) {
2692      Bucket* p = to->static_variables->pListHead;
2693      while (p != NULL) {
2694        ((zval*)(p->pDataPtr))->refcount = 1;
2695        p = p->pListNext;
2696      }
2697    }
2698#endif
2699  }
2700
2701  /* disable deletion in destroy_op_array */
2702  ++MMCG(refcount_helper);
2703  to->refcount = &MMCG(refcount_helper);
2704
2705  return to;
2706}
2707
2708static zend_op_array* restore_op_array_ptr(eaccelerator_op_array *from TSRMLS_DC) {
2709  return restore_op_array(NULL, from TSRMLS_CC);
2710}
2711
2712static zend_class_entry* restore_class_entry(zend_class_entry* to, eaccelerator_class_entry *from TSRMLS_DC)
2713{
2714  zend_class_entry *old;
2715  zend_function     *f;
2716  int   fname_len;
2717  char *fname_lc;
2718
2719#ifdef DEBUG
2720  pad(TSRMLS_C);
2721  fprintf(F_fp, "[%d] retore_class_entry: %s\n", getpid(), from->name? from->name : "(top)");
2722  fflush(F_fp);
2723  MMCG(xpad)++;
2724#endif
2725  if (to == NULL) {
2726    to = emalloc(sizeof(zend_class_entry));
2727  }
2728  memset(to, 0, sizeof(zend_class_entry));
2729  to->type        = from->type;
2730/*
2731  to->name        = NULL;
2732  to->name_length = from->name_length;
2733  to->constants_updated = 0;
2734  to->parent      = NULL;
2735*/
2736#ifdef ZEND_ENGINE_2
2737  to->ce_flags    = from->ce_flags;
2738/*
2739  to->static_members = NULL;
2740*/
2741  to->num_interfaces = from->num_interfaces;
2742  //to->num_interfaces = 0;
2743  if (to->num_interfaces > 0) {
2744    to->interfaces = (zend_class_entry **) emalloc(sizeof(zend_class_entry *)*to->num_interfaces);
2745    // XXX:
2746    //
2747    // should find out class entry. what the hell !!!
2748    memset(to->interfaces, 0, sizeof(zend_class_entry *)*to->num_interfaces);
2749  } else {
2750    to->interfaces = NULL;
2751  }
2752
2753  to->iterator_funcs             = from->iterator_funcs;
2754  to->create_object              = from->create_object;
2755  to->get_iterator               = from->get_iterator;
2756  to->interface_gets_implemented = from->interface_gets_implemented;
2757/*
2758  to->create_object = NULL;
2759*/
2760#endif
2761
2762  if (from->name != NULL) {
2763    to->name_length = from->name_length;
2764    to->name = emalloc(from->name_length+1);
2765    memcpy(to->name, from->name, from->name_length+1);
2766  }
2767
2768  if (from->parent != NULL)
2769  {
2770    int   name_len = strlen(from->parent);
2771#ifdef ZEND_ENGINE_2   
2772    char *name_lc  = zend_str_tolower_dup(from->parent, name_len);
2773
2774    if (zend_hash_find(CG(class_table), (void *)name_lc, name_len+1, (void **)&to->parent) != SUCCESS)
2775#else
2776    if (zend_hash_find(CG(class_table), (void *)from->parent, name_len+1, (void **)&to->parent) != SUCCESS)
2777#endif
2778    {
2779      debug_printf("[%d] EACCELERATOR can't restore parent class "
2780          "\"%s\" of class \"%s\"\n", getpid(), (char*)from->parent, to->name);
2781      to->parent = NULL;
2782    }
2783        else
2784        {
2785#ifdef ZEND_ENGINE_2
2786          /*
2787           * HOESH: not sure this is a clean solution on kwestlake's
2788           * problem... Fact: zend_hash_find returned **, but we
2789           * expected * - I've tested this against autoload and
2790           * everything seems to be oK.
2791           */
2792          to->parent = *(zend_class_entry**)to->parent;
2793          /*
2794           * HOESH: ahh, this is really needed. ;)
2795           */
2796          to->constructor  = to->parent->constructor;
2797          to->destructor  = to->parent->destructor;
2798          to->clone  = to->parent->clone;
2799          to->__get  = to->parent->__get;
2800      to->__set  = to->parent->__set;
2801      to->__call = to->parent->__call;
2802          to->create_object = to->parent->create_object;
2803    }
2804    efree(name_lc);
2805#else
2806          to->handle_property_get  = to->parent->handle_property_get;
2807      to->handle_property_set  = to->parent->handle_property_set;
2808      to->handle_function_call = to->parent->handle_function_call;
2809    }
2810#endif
2811  }
2812  else
2813  {
2814#ifdef DEBUG
2815    pad(TSRMLS_C); fprintf(F_fp, "[%d] parent = NULL\n", getpid()); fflush(F_fp);
2816#endif
2817    to->parent = NULL;
2818  }
2819
2820  old = MMCG(class_entry);
2821  MMCG(class_entry) = to;
2822
2823#ifdef ZEND_ENGINE_2
2824  to->refcount = 1;
2825
2826  to->line_start      = from->line_start;
2827  to->line_end        = from->line_end;
2828  to->doc_comment_len = from->doc_comment_len;
2829  if (from->filename != NULL) {
2830    size_t len = strlen(from->filename)+1;
2831    to->filename = emalloc(len);
2832    memcpy(to->filename, from->filename, len);
2833  }
2834  if (from->doc_comment != NULL) {
2835    to->doc_comment = emalloc(from->doc_comment_len+1);
2836    memcpy(to->doc_comment, from->doc_comment, from->doc_comment_len+1);
2837  }
2838
2839  restore_zval_hash(&to->constants_table, &from->constants_table);
2840  to->constants_table.pDestructor = ZVAL_PTR_DTOR;
2841  restore_zval_hash(&to->default_properties, &from->default_properties);
2842  to->default_properties.pDestructor = ZVAL_PTR_DTOR;
2843  restore_hash(&to->properties_info, &from->properties_info, (restore_bucket_t)restore_property_info TSRMLS_CC);
2844  if (from->static_members != NULL) {
2845    ALLOC_HASHTABLE(to->static_members);
2846    restore_zval_hash(to->static_members, from->static_members);
2847    to->static_members->pDestructor = ZVAL_PTR_DTOR;
2848/*
2849  } else {
2850    ALLOC_HASHTABLE(to->static_members);
2851    zend_hash_init_ex(to->static_members, 0, NULL, ZVAL_PTR_DTOR, 0, 0);
2852*/
2853  }
2854/*??? FIXME
2855    to->properties_info.pDestructor = (dtor_func_t) zend_destroy_property_info;
2856*/
2857#else
2858  to->refcount = emalloc(sizeof(*to->refcount));
2859  *to->refcount = 1;
2860
2861  restore_zval_hash(&to->default_properties, &from->default_properties);
2862  to->default_properties.pDestructor = ZVAL_PTR_DTOR;
2863  /* Clearing references */
2864  {
2865    Bucket* p = to->default_properties.pListHead;
2866    while (p != NULL) {
2867      ((zval*)(p->pDataPtr))->refcount = 1;
2868      p = p->pListNext;
2869    }
2870  }
2871#endif
2872  restore_hash(&to->function_table, &from->function_table, (restore_bucket_t)restore_op_array_ptr TSRMLS_CC);
2873  to->function_table.pDestructor = ZEND_FUNCTION_DTOR;
2874
2875#ifdef ZEND_ENGINE_2
2876  int   cname_len = to->name_length;
2877  char *cname_lc  = zend_str_tolower_dup(to->name, cname_len);
2878
2879  Bucket *p = to->function_table.pListHead;
2880  while (p != NULL) {
2881    f         = p->pData;
2882    fname_len = strlen(f->common.function_name);
2883    fname_lc  = zend_str_tolower_dup(f->common.function_name, fname_len);
2884
2885    if (fname_len == cname_len && !memcmp(fname_lc, cname_lc, fname_len))
2886      to->constructor = (zend_function*)f;
2887    else if (fname_lc[0] == '_' && fname_lc[1] == '_')
2888    {
2889      if (fname_len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1 && memcmp(fname_lc, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)) == 0)
2890        to->constructor = (zend_function*)f;
2891      else if (fname_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1 && memcmp(fname_lc, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)) == 0)
2892        to->destructor = (zend_function*)f;
2893      else if (fname_len == sizeof(ZEND_CLONE_FUNC_NAME)-1 && memcmp(fname_lc, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)) == 0)
2894        to->clone = (zend_function*)f;
2895      else if (fname_len == sizeof(ZEND_GET_FUNC_NAME)-1 && memcmp(fname_lc, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)) == 0)
2896        to->__get = (zend_function*)f;
2897      else if (fname_len == sizeof(ZEND_SET_FUNC_NAME)-1 && memcmp(fname_lc, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)) == 0)
2898        to->__set = (zend_function*)f;
2899      else if (fname_len == sizeof(ZEND_CALL_FUNC_NAME)-1 && memcmp(fname_lc, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)) == 0)
2900        to->__call = (zend_function*)f;
2901    }
2902    efree(fname_lc);
2903    p = p->pListNext;
2904  }
2905  efree(cname_lc);
2906
2907#endif
2908  MMCG(class_entry) = old;
2909
2910#ifdef DEBUG
2911  MMCG(xpad)--;
2912#endif
2913
2914  return to;
2915}
2916
2917static void restore_function(mm_fc_entry *p TSRMLS_DC) {
2918  zend_op_array op_array;
2919
2920  if ((p->htabkey[0] == '\000') &&
2921      zend_hash_exists(CG(function_table), p->htabkey, p->htablen)) {
2922    return;
2923  }
2924  if (restore_op_array(&op_array, (eaccelerator_op_array *)p->fc TSRMLS_CC) != NULL) {
2925    if (zend_hash_add(CG(function_table), p->htabkey, p->htablen,
2926        &op_array, sizeof(zend_op_array), NULL) == FAILURE) {
2927      CG(in_compilation) = 1;
2928      CG(compiled_filename) = MMCG(mem);
2929#ifdef ZEND_ENGINE_2
2930      CG(zend_lineno) = op_array.line_start;
2931#else
2932      CG(zend_lineno) = op_array.opcodes[0].lineno;
2933#endif
2934      zend_error(E_ERROR, "Cannot redeclare %s()", p->htabkey);
2935    }
2936  }
2937}
2938
2939/*
2940 * Class handling.
2941 */
2942static void restore_class(mm_fc_entry *p TSRMLS_DC) {
2943#ifdef ZEND_ENGINE_2
2944  zend_class_entry *ce;
2945#else
2946  zend_class_entry ce;
2947#endif
2948
2949  if ((p->htabkey[0] == '\000') &&
2950      zend_hash_exists(CG(class_table), p->htabkey, p->htablen)) {
2951    return;
2952  }
2953#ifdef ZEND_ENGINE_2
2954  ce = restore_class_entry(NULL, (eaccelerator_class_entry *)p->fc TSRMLS_CC);
2955  if (ce != NULL)
2956#else
2957  if (restore_class_entry(&ce, (eaccelerator_class_entry *)p->fc TSRMLS_CC) != NULL)
2958#endif
2959  {
2960#ifdef ZEND_ENGINE_2
2961    if (zend_hash_add(CG(class_table), p->htabkey, p->htablen,
2962                      &ce, sizeof(zend_class_entry*), NULL) == FAILURE)
2963#else
2964    if (zend_hash_add(CG(class_table), p->htabkey, p->htablen,
2965                      &ce, sizeof(zend_class_entry), NULL) == FAILURE)
2966#endif
2967    {
2968      CG(in_compilation) = 1;
2969      CG(compiled_filename) = MMCG(mem);
2970#ifdef ZEND_ENGINE_2
2971      CG(zend_lineno) = ce->line_start;
2972#else
2973      CG(zend_lineno) = 0;
2974#endif
2975      zend_error(E_ERROR, "Cannot redeclare class %s", p->htabkey);
2976    }
2977  }
2978
2979}
2980
2981/*
2982 * Try to restore a file from the cache.
2983 */
2984static zend_op_array* eaccelerator_restore(char *realname, struct stat *buf,
2985                                      int *nreloads, time_t compile_time TSRMLS_DC) {
2986  mm_cache_entry *p;
2987  zend_op_array *op_array = NULL;
2988
2989  *nreloads = 1;
2990  EACCELERATOR_UNPROTECT();
2991  p = hash_find_mm(realname, buf, nreloads,
2992                   ((eaccelerator_shm_ttl > 0)?(compile_time + eaccelerator_shm_ttl):0));
2993  if (p == NULL && !eaccelerator_scripts_shm_only) {
2994    p = hash_find_file(realname, buf TSRMLS_CC);
2995  }
2996  EACCELERATOR_PROTECT();
2997  if (p != NULL && p->op_array != NULL) {
2998    MMCG(class_entry) = NULL;
2999    op_array = restore_op_array(NULL, p->op_array TSRMLS_CC);
3000    if (op_array != NULL) {
3001      mm_fc_entry *e;
3002      mm_used_entry *used = emalloc(sizeof(mm_used_entry));
3003      used->entry  = p;
3004      used->next   = (mm_used_entry*)MMCG(used_entries);
3005      MMCG(used_entries) = (void*)used;
3006      MMCG(mem) = op_array->filename;
3007      for (e = p->c_head; e!=NULL; e = e->next) {
3008        restore_class(e TSRMLS_CC);
3009      }
3010      for (e = p->f_head; e!=NULL; e = e->next) {
3011        restore_function(e TSRMLS_CC);
3012      }
3013      MMCG(mem) = p->realfilename;
3014    }
3015  }
3016  return op_array;
3017}
3018
3019/*
3020 * Only files matching user specified conditions should be cached.
3021 *
3022 * TODO - check the algorithm (fl)
3023 */
3024
3025static int match(const char* name, const char* pat) {
3026  char p,k;
3027  int ok, neg;
3028
3029  while (1) {
3030    p = *pat++;
3031    if (p == '\0') {
3032      return (*name == '\0');
3033    } else if (p == '*') {
3034      if (*pat == '\0') {
3035        return 1;
3036      }
3037      do {
3038        if (match(name, pat)) {
3039          return 1;
3040        }
3041      } while (*name++ != '\0');
3042      return 0;
3043    } else if (p == '?') {
3044      if (*name++ == '\0') {
3045        return 0;
3046      }
3047    } else if (p == '[') {
3048      ok = 0;
3049      if ((k = *name++) == '\0') {
3050        return 0;
3051      }
3052      if ((neg = (*pat == '!')) != '\0') {
3053        ++pat;
3054      }
3055      while ((p = *pat++) != ']') {
3056        if (*pat == '-') {
3057          if (p <= k && k <= pat[1]) {
3058            ok = 1;
3059          }
3060          pat += 2;
3061        } else {
3062          if (p == '\\') {
3063            p = *pat++;
3064            if (p == '\0') {
3065              p ='\\';
3066              pat--;
3067            }
3068          }
3069          if (p == k) {
3070            ok = 1;
3071          }
3072        }
3073      }
3074      if (ok == neg) {
3075        return 0;
3076      }
3077    } else {
3078      if (p == '\\') {
3079        p = *pat++;
3080        if (p == '\0') {
3081          p ='\\';
3082          pat--;
3083        }
3084      }
3085      if (*name++ != p) {
3086        return 0;
3087      }
3088    }
3089  }
3090  return (*name == '\0');
3091}
3092
3093static int eaccelerator_ok_to_cache(char *realname TSRMLS_DC) {
3094  mm_cond_entry *p;
3095  int ok;
3096
3097  if (MMCG(cond_list) == NULL) {
3098    return 1;
3099  }
3100
3101  /* if "realname" matches to any pattern started with "!" then ignore it */
3102  for (p = MMCG(cond_list); p != NULL; p = p->next) {
3103    if (p->not && match(realname, p->str)) {
3104      return 0;
3105    }
3106  }
3107
3108  /* else if it matches to any pattern not started with "!" then accept it */
3109  ok = 1;
3110  for (p = MMCG(cond_list); p != NULL; p = p->next) {
3111    if (!p->not) {
3112      ok = 0;
3113      if (match(realname, p->str)) {
3114        return 1;
3115      }
3116    }
3117  }
3118  return ok;
3119}
3120
3121/******************************************************************************/
3122static char* eaccelerator_realpath(const char* name, char* realname TSRMLS_DC) {
3123/* ???TODO it is possibe to cache name->realname mapping to avoid lstat() calls */
3124#if ZEND_MODULE_API_NO >= 20001222
3125  return VCWD_REALPATH(name, realname);
3126#else
3127  return V_REALPATH(name, realname);
3128#endif
3129}
3130
3131static int eaccelerator_stat(zend_file_handle *file_handle,
3132                        char* realname, struct stat* buf TSRMLS_DC) {
3133#ifdef EACCELERATOR_USE_INODE
3134#ifndef ZEND_WIN32
3135  if (file_handle->type == ZEND_HANDLE_FP && file_handle->handle.fp != NULL) {
3136    if (fstat(fileno(file_handle->handle.fp), buf) == 0 &&
3137       S_ISREG(buf->st_mode)) {
3138      if (file_handle->opened_path != NULL) {
3139        strcpy(realname,file_handle->opened_path);
3140      }
3141      return 0;
3142    }
3143  } else
3144#endif
3145  if (file_handle->opened_path != NULL) {
3146    if (stat(file_handle->opened_path, buf) == 0 &&
3147        S_ISREG(buf->st_mode)) {
3148       strcpy(realname,file_handle->opened_path);
3149       return 0;
3150    }
3151  } else if (PG(include_path) == NULL ||
3152             file_handle->filename[0] == '.' ||
3153             IS_SLASH(file_handle->filename[0]) ||
3154             IS_ABSOLUTE_PATH(file_handle->filename,strlen(file_handle->filename))) {
3155    if (stat(file_handle->filename, buf) == 0 &&
3156        S_ISREG(buf->st_mode)) {
3157       return 0;
3158    }
3159  } else {
3160    char* ptr = PG(include_path);
3161    char* end;
3162    int   len;
3163    char  tryname[MAXPATHLEN];
3164    int   filename_len = strlen(file_handle->filename);
3165
3166    while (ptr && *ptr) {
3167      end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
3168      if (end != NULL) {
3169        len = end-ptr;
3170        end++;
3171      } else {
3172        len = strlen(ptr);
3173        end = ptr+len;
3174      }
3175      if (len+filename_len+2 < MAXPATHLEN) {
3176        memcpy(tryname, ptr, len);
3177        tryname[len] = '/';
3178        memcpy(tryname+len+1, file_handle->filename, filename_len);
3179        tryname[len+filename_len+1] = '\0';
3180        if (stat(tryname, buf) == 0 &&
3181            S_ISREG(buf->st_mode)) {
3182          return 0;
3183        }
3184      }
3185      ptr = end;
3186    }
3187  }
3188  return -1;
3189#else
3190  if (file_handle->opened_path != NULL) {
3191    strcpy(realname,file_handle->opened_path);
3192#ifndef ZEND_WIN32
3193    if (file_handle->type == ZEND_HANDLE_FP && file_handle->handle.fp != NULL) {
3194      if (!eaccelerator_check_mtime) {
3195        return 0;
3196      } else if (fstat(fileno(file_handle->handle.fp), buf) == 0 &&
3197                 S_ISREG(buf->st_mode)) {
3198        return 0;
3199      } else {
3200        return -1;
3201      }
3202    } else {
3203      if (!eaccelerator_check_mtime) {
3204        return 0;
3205      } else if (stat(realname, buf) == 0 &&
3206                 S_ISREG(buf->st_mode)) {
3207        return 0;
3208      } else {
3209        return -1;
3210      }
3211    }
3212#else
3213    if (!eaccelerator_check_mtime) {
3214      return 0;
3215    } else if (stat(realname, buf) == 0 &&
3216               S_ISREG(buf->st_mode)) {
3217      return 0;
3218    } else {
3219      return -1;
3220    }
3221#endif
3222  } else if (file_handle->filename == NULL) {
3223    return -1;
3224  } else if (PG(include_path) == NULL ||
3225             file_handle->filename[0] == '.' ||
3226             IS_SLASH(file_handle->filename[0]) ||
3227             IS_ABSOLUTE_PATH(file_handle->filename,strlen(file_handle->filename))) {
3228    if (eaccelerator_realpath(file_handle->filename, realname TSRMLS_CC)) {
3229      if (!eaccelerator_check_mtime) {
3230        return 0;
3231      } else if (stat(realname, buf) == 0 &&
3232                 S_ISREG(buf->st_mode)) {
3233        return 0;
3234      } else {
3235        return -1;
3236      }
3237    }
3238  } else {
3239    char* ptr = PG(include_path);
3240    char* end;
3241    int   len;
3242    char  tryname[MAXPATHLEN];
3243    int   filename_len = strlen(file_handle->filename);
3244
3245    while (ptr && *ptr) {
3246      end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
3247      if (end != NULL) {
3248        len = end-ptr;
3249        end++;
3250      } else {
3251        len = strlen(ptr);
3252        end = ptr+len;
3253      }
3254      if (len+filename_len+2 < MAXPATHLEN) {
3255        memcpy(tryname, ptr, len);
3256        tryname[len] = '/';
3257        memcpy(tryname+len+1, file_handle->filename, filename_len);
3258        tryname[len+filename_len+1] = '\0';
3259        if (eaccelerator_realpath(tryname, realname TSRMLS_CC)) {
3260#ifdef ZEND_WIN32
3261          if (stat(realname, buf) == 0 &&
3262              S_ISREG(buf->st_mode)) {
3263            return 0;
3264          }
3265#else
3266          if (!eaccelerator_check_mtime) {
3267            return 0;
3268          } else if (stat(realname, buf) == 0 &&
3269                     S_ISREG(buf->st_mode)) {
3270            return 0;
3271          } else {
3272            return -1;
3273          }
3274#endif
3275        }
3276      }
3277      ptr = end;
3278    }
3279  }
3280  return -1;
3281#endif
3282}
3283
3284/*
3285 * Intercept compilation of PHP file.  If we already have the file in
3286 * our cache, restore it.  Otherwise call the original Zend compilation
3287 * function and store the compiled zend_op_array in out cache.
3288 * This function is called again for each PHP file included in the
3289 * main PHP file.
3290 */
3291ZEND_DLEXPORT zend_op_array* eaccelerator_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) {
3292  zend_op_array *t;
3293  struct stat buf;
3294  char  realname[MAXPATHLEN];
3295  int   nreloads;
3296  time_t compile_time;
3297
3298#ifdef EACCELERATOR_USE_INODE
3299  realname[0] = '\000';
3300#endif
3301#if defined(DEBUG) || defined(TEST_PERFORMANCE)
3302#ifdef TEST_PERFORMANCE
3303  struct timeval tv_start;
3304  fprintf(F_fp, "[%d] Enter COMPILE\n",getpid()); fflush(F_fp);
3305  start_time(&tv_start);
3306#endif
3307  fprintf(F_fp, "[%d] Enter COMPILE\n",getpid()); fflush(F_fp);
3308  fprintf(F_fp, "[%d] compile_file: \"%s\"\n",getpid(), file_handle->filename); fflush(F_fp);
3309  MMCG(xpad)+=2;
3310#endif
3311  if (!MMCG(enabled) ||
3312      (eaccelerator_mm_instance == NULL) ||
3313      !eaccelerator_mm_instance->enabled ||
3314      file_handle == NULL ||
3315      file_handle->filename == NULL ||
3316      eaccelerator_stat(file_handle, realname, &buf TSRMLS_CC) != 0 ||
3317      buf.st_mtime >= (compile_time = time(0)) ||
3318#ifdef EACCELERATOR_USE_INODE
3319      0) {
3320#else
3321      !eaccelerator_ok_to_cache(realname TSRMLS_CC)) {
3322#endif
3323#if defined(DEBUG) || defined(TEST_PERFORMANCE)
3324    fprintf(F_fp, "\t[%d] compile_file: compiling\n",getpid()); fflush(F_fp);
3325#endif
3326    t = mm_saved_zend_compile_file(file_handle, type TSRMLS_CC);
3327#if defined(DEBUG) || defined(TEST_PERFORMANCE)
3328#ifdef TEST_PERFORMANCE
3329    fprintf(F_fp, "\t[%d] compile_file: end (%ld)\n",getpid(),elapsed_time(&tv_start)); fflush(F_fp);
3330#else
3331    fprintf(F_fp, "\t[%d] compile_file: end\n",getpid()); fflush(F_fp);
3332#endif
3333    MMCG(xpad)-=2;
3334#endif
3335#if defined(DEBUG)
3336    fprintf(F_fp, "[%d] Leave COMPILE\n",getpid()); fflush(F_fp);
3337#endif
3338    return t;
3339  }
3340
3341  t = eaccelerator_restore(realname, &buf, &nreloads, compile_time TSRMLS_CC);
3342
3343// segv74: really cheap work around to auto_global problem.
3344//         it makes just in time to every time.
3345#ifdef ZEND_ENGINE_2
3346  zend_is_auto_global("_GET", sizeof("_SERVER")-1 TSRMLS_CC);
3347  zend_is_auto_global("_POST", sizeof("_SERVER")-1 TSRMLS_CC);
3348  zend_is_auto_global("_COOKIE", sizeof("_SERVER")-1 TSRMLS_CC);
3349  zend_is_auto_global("_SERVER", sizeof("_SERVER")-1 TSRMLS_CC);
3350  zend_is_auto_global("_ENV", sizeof("_ENV")-1 TSRMLS_CC);
3351  zend_is_auto_global("_REQUEST", sizeof("_REQUEST")-1 TSRMLS_CC);
3352  zend_is_auto_global("_FILES", sizeof("_SERVER")-1 TSRMLS_CC);
3353#endif
3354  if (t != NULL) {
3355    if (eaccelerator_debug > 0) {
3356      debug_printf("[%d] EACCELERATOR hit: \"%s\"\n", getpid(), t->filename);
3357    }
3358    /* restored from cache */
3359
3360    zend_llist_add_element(&CG(open_files), file_handle);
3361#ifdef ZEND_ENGINE_2
3362    if (file_handle->opened_path == NULL && file_handle->type != ZEND_HANDLE_STREAM) {
3363      file_handle->handle.stream.handle = (void*)1;
3364#else
3365    if (file_handle->opened_path == NULL && file_handle->type != ZEND_HANDLE_FP) {
3366      int dummy = 1;
3367      file_handle->opened_path = MMCG(mem);
3368      zend_hash_add(&EG(included_files), file_handle->opened_path, strlen(file_handle->opened_path)+1, (void *)&dummy, sizeof(int), NULL);
3369      file_handle->handle.fp = NULL;
3370#endif
3371/*??? I don't understud way estrdup is not need
3372      file_handle->opened_path = estrdup(MMCG(mem));
3373*/
3374    }
3375#if defined(DEBUG) || defined(TEST_PERFORMANCE)
3376#ifdef TEST_PERFORMANCE
3377    fprintf(F_fp, "\t[%d] compile_file: restored (%ld)\n",getpid(),elapsed_time(&tv_start)); fflush(F_fp);
3378#else
3379    fprintf(F_fp, "\t[%d] compile_file: restored\n",getpid()); fflush(F_fp);
3380#endif
3381    MMCG(xpad)-=2;
3382#endif
3383#if defined(DEBUG)
3384    fprintf(F_fp, "[%d] Leave COMPILE\n",getpid()); fflush(F_fp);
3385    //dprint_compiler_retval(t, 1);
3386#endif
3387    return t;
3388  } else {
3389    /* not in cache or must be recompiled */
3390    Bucket *function_table_tail;
3391    Bucket *class_table_tail;
3392    HashTable* orig_function_table;
3393    HashTable* orig_class_table;
3394    HashTable* orig_eg_class_table;
3395    HashTable tmp_function_table;
3396    HashTable tmp_class_table;
3397    zend_function tmp_func;
3398    zend_class_entry tmp_class;
3399    int bailout;
3400
3401#if defined(DEBUG) || defined(TEST_PERFORMANCE)
3402    fprintf(F_fp, "\t[%d] compile_file: marking\n",getpid()); fflush(F_fp);
3403    if (CG(class_table) != EG(class_table))
3404    {
3405      fprintf(F_fp, "\t[%d] oops, CG(class_table)[%08x] != EG(class_table)[%08x]\n", getpid(), CG(class_table), EG(class_table));
3406      //log_hashkeys("CG(class_table)\n", CG(class_table));
3407      //log_hashkeys("EG(class_table)\n", EG(class_table));
3408    }
3409    else
3410      fprintf(F_fp, "\t[%d] OKAY. That what I thought, CG(class_table)[%08x] == EG(class_table)[%08x]\n", getpid(), CG(class_table), EG(class_table));
3411      //log_hashkeys("CG(class_table)\n", CG(class_table));
3412#endif
3413
3414    zend_hash_init_ex(&tmp_function_table, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0);
3415    zend_hash_copy(&tmp_function_table, &eaccelerator_global_function_table, NULL, &tmp_func, sizeof(zend_function));
3416    orig_function_table = CG(function_table);
3417    CG(function_table) = &tmp_function_table;
3418
3419    zend_hash_init_ex(&tmp_class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0);
3420    zend_hash_copy(&tmp_class_table, &eaccelerator_global_class_table, NULL, &tmp_class, sizeof(zend_class_entry));
3421
3422    orig_class_table = CG(class_table);;
3423    CG(class_table) = &tmp_class_table;
3424#ifdef ZEND_ENGINE_2
3425    orig_eg_class_table = EG(class_table);;
3426    EG(class_table) = &tmp_class_table;
3427#endif
3428
3429    /* Storing global pre-compiled functions and classes */
3430    function_table_tail = CG(function_table)->pListTail;
3431    class_table_tail = CG(class_table)->pListTail;
3432
3433#if defined(DEBUG) || defined(TEST_PERFORMANCE)
3434#ifdef TEST_PERFORMANCE
3435    fprintf(F_fp, "\t[%d] compile_file: compiling (%ld)\n",getpid(),elapsed_time(&tv_start)); fflush(F_fp);
3436#else
3437    fprintf(F_fp, "\t[%d] compile_file: compiling tmp_class_table=%d class_table=%d\n", getpid(), tmp_class_table.nNumOfElements, orig_class_table->nNumOfElements); fflush(F_fp);
3438#endif
3439#endif
3440    if (MMCG(optimizer_enabled) && eaccelerator_mm_instance->optimizer_enabled) {
3441      MMCG(compiler) = 1;
3442    }
3443
3444    bailout = 0;
3445    zend_try {
3446      t = mm_saved_zend_compile_file(file_handle, type TSRMLS_CC);
3447    } zend_catch {
3448      CG(function_table) = orig_function_table;
3449      CG(class_table) = orig_class_table;
3450#ifdef ZEND_ENGINE_2
3451      EG(class_table) = orig_eg_class_table;
3452#endif
3453      bailout = 1;
3454    } zend_end_try();
3455    if (bailout) {
3456      zend_bailout();
3457    }
3458#if defined(DEBUG)
3459    //log_hashkeys("class_table\n", CG(class_table));
3460#endif
3461
3462/*???
3463    if (file_handle->opened_path == NULL && t != NULL) {
3464      file_handle->opened_path = t->filename;
3465    }
3466*/
3467    MMCG(compiler) = 0;
3468    if (t != NULL &&
3469        file_handle->opened_path != NULL &&
3470#ifdef EACCELERATOR_USE_INODE
3471        eaccelerator_ok_to_cache(file_handle->opened_path TSRMLS_CC)) {
3472#else
3473        (eaccelerator_check_mtime ||
3474         ((stat(file_handle->opened_path, &buf) == 0) && S_ISREG(buf.st_mode)))) {
3475#endif
3476#if defined(DEBUG) || defined(TEST_PERFORMANCE)
3477#ifdef TEST_PERFORMANCE
3478      fprintf(F_fp, "\t[%d] compile_file: storing in cache (%ld)\n",getpid(),elapsed_time(&tv_start)); fflush(F_fp);
3479#else
3480      fprintf(F_fp, "\t[%d] compile_file: storing in cache\n",getpid()); fflush(F_fp);
3481#endif
3482#endif
3483#ifdef WITH_EACCELERATOR_LOADER
3484      if (t->last >= 3 &&
3485          t->opcodes[0].opcode == ZEND_SEND_VAL &&
3486          t->opcodes[1].opcode == ZEND_DO_FCALL &&
3487          t->opcodes[2].opcode == ZEND_RETURN &&
3488          t->opcodes[1].op1.op_type == IS_CONST &&
3489          t->opcodes[1].op1.u.constant.type == IS_STRING &&
3490          t->opcodes[1].op1.u.constant.value.str.len == sizeof("eaccelerator_load")-1 &&
3491          (memcmp(t->opcodes[1].op1.u.constant.value.str.val, "eaccelerator_load", sizeof("eaccelerator_load")-1) == 0) &&
3492          t->opcodes[0].op1.op_type == IS_CONST &&
3493          t->opcodes[0].op1.u.constant.type == IS_STRING) {
3494        zend_op_array* new_t;
3495        zend_bool old_in_compilation = CG(in_compilation);
3496        char* old_filename = CG(compiled_filename);
3497        int old_lineno = CG(zend_lineno);
3498
3499        CG(in_compilation) = 1;
3500        zend_set_compiled_filename(t->filename TSRMLS_CC);
3501        CG(zend_lineno) = t->opcodes[1].lineno;
3502        new_t = eaccelerator_load(
3503          t->opcodes[0].op1.u.constant.value.str.val,
3504          t->opcodes[0].op1.u.constant.value.str.len TSRMLS_CC);
3505        CG(in_compilation) = old_in_compilation;
3506        CG(compiled_filename) = old_filename;
3507        CG(zend_lineno) = old_lineno;
3508        if (new_t != NULL) {
3509#ifdef ZEND_ENGINE_2
3510          destroy_op_array(t TSRMLS_CC);
3511#else
3512          destroy_op_array(t);
3513#endif
3514          efree(t);
3515          t = new_t;
3516        }
3517      }
3518#endif
3519      function_table_tail = function_table_tail?function_table_tail->pListNext:
3520                                                CG(function_table)->pListHead;
3521      class_table_tail = class_table_tail?class_table_tail->pListNext:
3522                                          CG(class_table)->pListHead;
3523      if (eaccelerator_store(file_handle->opened_path, &buf, nreloads, t,
3524                        function_table_tail, class_table_tail TSRMLS_CC)) {
3525        if (eaccelerator_debug > 0) {
3526          debug_printf("[%d] EACCELERATOR %s: \"%s\"\n", getpid(),
3527              (nreloads == 1) ? "cached" : "re-cached", file_handle->opened_path);
3528        }
3529      } else {
3530        if (eaccelerator_debug > 0) {
3531          debug_printf("[%d] EACCELERATOR cann't cache: \"%s\"\n", getpid(), file_handle->opened_path);
3532        }
3533      }
3534    } else {
3535      function_table_tail = function_table_tail?function_table_tail->pListNext:
3536                                                CG(function_table)->pListHead;
3537      class_table_tail = class_table_tail?class_table_tail->pListNext:
3538                                          CG(class_table)->pListHead;
3539    }
3540    CG(function_table) = orig_function_table;
3541    CG(class_table) = orig_class_table;
3542#ifdef ZEND_ENGINE_2
3543    EG(class_table) = orig_eg_class_table;
3544#ifdef DEBUG
3545    fprintf(F_fp, "\t[%d] restoring CG(class_table)[%08x] != EG(class_table)[%08x]\n", getpid(), CG(class_table), EG(class_table));
3546#endif
3547#endif
3548    while (function_table_tail != NULL) {
3549      zend_op_array *op_array = (zend_op_array*)function_table_tail->pData;
3550      if (op_array->type == ZEND_USER_FUNCTION) {
3551        if (zend_hash_add(CG(function_table),
3552                          function_table_tail->arKey,
3553                          function_table_tail->nKeyLength,
3554                          op_array, sizeof(zend_op_array), NULL) == FAILURE &&
3555            function_table_tail->arKey[0] != '\000') {
3556          CG(in_compilation) = 1;
3557          CG(compiled_filename) = file_handle->opened_path;
3558#ifdef ZEND_ENGINE_2
3559          CG(zend_lineno) = op_array->line_start;
3560#else
3561          CG(zend_lineno) = op_array->opcodes[0].lineno;
3562#endif
3563          zend_error(E_ERROR, "Cannot redeclare %s()", function_table_tail->arKey);
3564        }
3565      }
3566      function_table_tail = function_table_tail->pListNext;
3567    }
3568    while (class_table_tail != NULL) {
3569#ifdef ZEND_ENGINE_2
3570      zend_class_entry **ce = (zend_class_entry**)class_table_tail->pData;
3571      if ((*ce)->type == ZEND_USER_CLASS) {
3572        if (zend_hash_add(CG(class_table),
3573                          class_table_tail->arKey,
3574                          class_table_tail->nKeyLength,
3575                          ce, sizeof(zend_class_entry*), NULL) == FAILURE &&
3576            class_table_tail->arKey[0] != '\000') {
3577          CG(in_compilation) = 1;
3578          CG(compiled_filename) = file_handle->opened_path;
3579          CG(zend_lineno) = (*ce)->line_start;
3580#else
3581      zend_class_entry *ce = (zend_class_entry*)class_table_tail->pData;
3582      if (ce->type == ZEND_USER_CLASS) {
3583        if (ce->parent != NULL) {
3584          if (zend_hash_find(CG(class_table), (void*)ce->parent->name, ce->parent->name_length+1, (void **)&ce->parent) != SUCCESS)
3585                  {
3586            ce->parent = NULL;
3587          }
3588        }
3589        if (zend_hash_add(CG(class_table),
3590                          class_table_tail->arKey,
3591                          class_table_tail->nKeyLength,
3592                          ce, sizeof(zend_class_entry), NULL) == FAILURE &&
3593            class_table_tail->arKey[0] != '\000') {
3594          CG(in_compilation) = 1;
3595          CG(compiled_filename) = file_handle->opened_path;
3596          CG(zend_lineno) = 0;
3597#endif
3598          zend_error(E_ERROR, "Cannot redeclare class %s", class_table_tail->arKey);
3599        }
3600      }
3601      class_table_tail = class_table_tail->pListNext;
3602    }
3603    tmp_function_table.pDestructor = NULL;
3604    tmp_class_table.pDestructor = NULL;
3605    zend_hash_destroy(&tmp_function_table);
3606    zend_hash_destroy(&tmp_class_table);
3607  }
3608#if defined(DEBUG) || defined(TEST_PERFORMANCE)
3609#ifdef TEST_PERFORMANCE
3610  fprintf(F_fp, "\t[%d] compile_file: end (%ld)\n",getpid(),elapsed_time(&tv_start)); fflush(F_fp);
3611#else
3612  fprintf(F_fp, "\t[%d] compile_file: end\n",getpid()); fflush(F_fp);
3613#endif
3614  MMCG(xpad)-=2;
3615  fflush(F_fp);
3616#endif
3617#if defined(DEBUG)
3618  fprintf(F_fp, "[%d] Leave COMPILE\n",getpid()); fflush(F_fp);
3619  //dprint_compiler_retval(t, 0);
3620#endif
3621  return t;
3622}
3623
3624#ifdef PROFILE_OPCODES
3625static void profile_execute(zend_op_array *op_array TSRMLS_DC)
3626{
3627  int i;
3628  struct timeval tv_start;
3629  long usec;
3630
3631  for (i=0;i<MMCG(profile_level);i++)
3632    fputs("  ", F_fp);
3633  fprintf(F_fp,"enter: %s:%s\n", op_array->filename, op_array->function_name);
3634  fflush(F_fp);
3635  start_time(&tv_start);
3636  MMCG(self_time)[MMCG(profile_level)] = 0;
3637  MMCG(profile_level)++;
3638#ifdef WITH_EACCELERATOR_EXECUTOR
3639  eaccelerator_execute(op_array TSRMLS_CC);
3640#else
3641  mm_saved_zend_execute(op_array TSRMLS_CC);
3642#endif
3643  usec = elapsed_time(&tv_start);
3644  MMCG(profile_level)--;
3645  if (MMCG(profile_level) > 0)
3646    MMCG(self_time)[MMCG(profile_level)-1] += usec;
3647  for (i=0;i<MMCG(profile_level);i++)
3648    fputs("  ", F_fp);
3649  fprintf(F_fp,"leave: %s:%s (%ld,%ld)\n", op_array->filename, op_array->function_name, usec, usec-MMCG(self_time)[MMCG(profile_level)]);
3650  fflush(F_fp);
3651}
3652
3653ZEND_DLEXPORT zend_op_array* profile_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) {
3654  zend_op_array *t;
3655  int i;
3656  struct timeval tv_start;
3657  long usec;
3658
3659  start_time(&tv_start);
3660  MMCG(self_time)[MMCG(profile_level)] = 0;
3661  t = eaccelerator_compile_file(file_handle, type TSRMLS_CC);
3662  usec = elapsed_time(&tv_start);
3663  if (MMCG(profile_level) > 0)
3664    MMCG(self_time)[MMCG(profile_level)-1] += usec;
3665  for (i=0;i<MMCG(profile_level);i++)
3666    fputs("  ", F_fp);
3667  fprintf(F_fp,"compile: %s (%ld)\n", file_handle->filename, usec);
3668  fflush(F_fp);
3669  return t;
3670}
3671
3672#endif  /* #ifdef PROFILE_OPCODES */
3673
3674/* Format Bytes */
3675static void format_size(char* s, unsigned int size, int legend) {
3676  unsigned int i = 0;
3677  unsigned int n = 0;
3678  char ch;
3679  do {
3680    if ((n != 0) && (n % 3 == 0)) {
3681      s[i++] = ',';
3682    }
3683    s[i++] = (char)((int)'0' + (size % 10));
3684    n++;
3685    size = size / 10;
3686  } while (size != 0);
3687  s[i] = '\0';
3688  n = 0; i--;
3689  while (n < i) {
3690    ch = s[n];
3691    s[n] = s[i];
3692    s[i] = ch;
3693    n++, i--;
3694  }
3695  if (legend) {
3696    strcat(s, " Bytes");
3697  }
3698}
3699
3700PHP_MINFO_FUNCTION(eaccelerator) {
3701  char s[32];
3702
3703  php_info_print_table_start();
3704  php_info_print_table_header(2, "eAccelerator support", "enabled");
3705  php_info_print_table_row(2, "Version", EACCELERATOR_VERSION);
3706  php_info_print_table_row(2, "Caching Enabled", (MMCG(enabled) && (eaccelerator_mm_instance != NULL) && eaccelerator_mm_instance->enabled)?"true":"false");
3707  php_info_print_table_row(2, "Optimizer Enabled", (MMCG(optimizer_enabled) && (eaccelerator_mm_instance != NULL) && eaccelerator_mm_instance->optimizer_enabled)?"true":"false");
3708  if (eaccelerator_mm_instance != NULL) {
3709    size_t available;
3710    EACCELERATOR_UNPROTECT();
3711    available = mm_available(eaccelerator_mm_instance->mm);
3712    EACCELERATOR_LOCK_RD();
3713    EACCELERATOR_PROTECT();
3714    format_size(s, eaccelerator_mm_instance->total, 1);
3715    php_info_print_table_row(2, "Memory Size", s);
3716    format_size(s, available, 1);
3717    php_info_print_table_row(2, "Memory Available", s);
3718    format_size(s, eaccelerator_mm_instance->total - available, 1);
3719    php_info_print_table_row(2, "Memory Allocated", s);
3720    snprintf(s, 32, "%u", eaccelerator_mm_instance->hash_cnt);
3721    php_info_print_table_row(2, "Cached Scripts", s);
3722    snprintf(s, 32, "%u", eaccelerator_mm_instance->rem_cnt);
3723    php_info_print_table_row(2, "Removed Scripts", s);
3724    snprintf(s, 32, "%u", eaccelerator_mm_instance->user_hash_cnt);
3725    php_info_print_table_row(2, "Cached Keys", s);
3726    EACCELERATOR_UNPROTECT();
3727    EACCELERATOR_UNLOCK_RD();
3728    EACCELERATOR_PROTECT();
3729  }
3730  php_info_print_table_end();
3731
3732  DISPLAY_INI_ENTRIES();
3733}
3734
3735/* User Cache Routines (put, get, rm, gc) */
3736
3737static char* build_key(const char* key, int key_len, int *xlen TSRMLS_DC) {
3738  int len = strlen(MMCG(hostname));
3739  if (len > 0) {
3740    char* xkey;
3741    *xlen = len + key_len + 1;
3742    xkey = emalloc((*xlen)+1);
3743    memcpy(xkey, MMCG(hostname), len);
3744    xkey[len] = ':';
3745    memcpy(xkey+len+1, key, key_len+1);
3746    return xkey;
3747  } else {
3748    *xlen = key_len;
3749    return (char*)key;
3750  }
3751}
3752
3753static int eaccelerator_lock(const char* key, int key_len TSRMLS_DC) {
3754  int xlen;
3755  char* xkey;
3756  mm_lock_entry* x;
3757  mm_lock_entry** p;
3758  int ok = 0;
3759
3760  if (eaccelerator_mm_instance == NULL) {
3761    return 0;
3762  }
3763  xkey = build_key(key, key_len, &xlen TSRMLS_CC);
3764  EACCELERATOR_UNPROTECT();
3765  x = eaccelerator_malloc(offsetof(mm_lock_entry,key)+xlen+1);
3766  if (x == NULL) {
3767    EACCELERATOR_PROTECT();
3768    if (xlen != key_len) {efree(xkey);}
3769    return 0;
3770  }
3771  x->pid = getpid();
3772#ifdef ZTS
3773  x->thread = tsrm_thread_id();
3774#endif
3775  x->next = NULL;
3776  memcpy(x->key, xkey, xlen+1);
3777  while (1) {
3778    EACCELERATOR_LOCK_RW();
3779    p = &eaccelerator_mm_instance->locks;
3780    while ((*p) != NULL) {
3781      if (strcmp((*p)->key,x->key) == 0) {
3782#ifdef ZTS
3783        if (x->pid == (*p)->pid && x->thread == (*p)->thread) {
3784#else
3785        if (x->pid == (*p)->pid) {
3786#endif
3787          ok = 1;
3788          eaccelerator_free_nolock(x);
3789        }
3790        break;
3791      }
3792      p = &(*p)->next;
3793    }
3794    if ((*p) == NULL) {
3795      *p = x;
3796      ok = 1;
3797    }
3798    EACCELERATOR_UNLOCK_RW();
3799    if (ok) {
3800      break;
3801    } else {
3802#ifdef ZEND_WIN32
3803      Sleep(100);
3804/*???
3805#elif defined(HAVE_SCHED_YIELD)
3806      sched_yield();
3807*/
3808#else
3809      struct timeval t;
3810      t.tv_sec = 0;
3811      t.tv_usec = 100;
3812      select(0, NULL, NULL, NULL, &t);
3813#endif
3814    }
3815  }
3816  EACCELERATOR_PROTECT();
3817  if (xlen != key_len) {efree(xkey);}
3818  return 1;
3819}
3820
3821static int eaccelerator_unlock(const char* key, int key_len TSRMLS_DC) {
3822  int xlen;
3823  char* xkey;
3824  mm_lock_entry** p;
3825
3826  if (eaccelerator_mm_instance == NULL) {
3827    return 0;
3828  }
3829  xkey = build_key(key, key_len, &xlen TSRMLS_CC);
3830  EACCELERATOR_UNPROTECT();
3831  EACCELERATOR_LOCK_RW();
3832  p = &eaccelerator_mm_instance->locks;
3833  while ((*p) != NULL) {
3834    if (strcmp((*p)->key,xkey) == 0) {
3835#ifdef ZTS
3836      if ((*p)->pid == getpid() && (*p)->thread == tsrm_thread_id()) {
3837#else
3838      if ((*p)->pid == getpid()) {
3839#endif
3840         mm_lock_entry *x = (*p);
3841        *p = (*p)->next;
3842        eaccelerator_free_nolock(x);
3843      } else {
3844        EACCELERATOR_UNLOCK_RW();
3845        EACCELERATOR_PROTECT();
3846        if (xlen != key_len) {efree(xkey);}
3847        return 0;
3848      }
3849      break;
3850    }
3851    p = &(*p)->next;
3852  }
3853  EACCELERATOR_UNLOCK_RW();
3854  EACCELERATOR_PROTECT();
3855  if (xlen != key_len) {efree(xkey);}
3856  return 1;
3857}
3858
3859int eaccelerator_put(const char* key, int key_len, zval* val, time_t ttl, eaccelerator_cache_place where TSRMLS_DC) {
3860  mm_user_cache_entry *p, *q;
3861  unsigned int slot;
3862  long size;
3863  int use_shm = 1;
3864  int ret = 0;
3865  char s[MAXPATHLEN];
3866  int xlen;
3867  char* xkey;
3868
3869  xkey = build_key(key, key_len, &xlen TSRMLS_CC);
3870  MMCG(compress) = 1;
3871  MMCG(mem) = NULL;
3872  zend_hash_init(&MMCG(strings), 0, NULL, NULL, 0);
3873  EACCELERATOR_ALIGN(MMCG(mem));
3874  MMCG(mem) += offsetof(mm_user_cache_entry, key)+xlen+1;
3875  calc_zval(val TSRMLS_CC);
3876  zend_hash_destroy(&MMCG(strings));
3877
3878  size = (long)MMCG(mem);
3879
3880  MMCG(mem) = NULL;
3881  if (eaccelerator_mm_instance != NULL &&
3882      (where == eaccelerator_shm_and_disk ||
3883       where == eaccelerator_shm ||
3884       where == eaccelerator_shm_only)) {
3885    EACCELERATOR_UNPROTECT();
3886    if (eaccelerator_shm_max == 0 || size <= eaccelerator_shm_max) {
3887      MMCG(mem) = eaccelerator_malloc(size);
3888      if (MMCG(mem) == NULL) {
3889        MMCG(mem) = eaccelerator_malloc2(size TSRMLS_CC);
3890      }
3891    }
3892    if (MMCG(mem) == NULL) {
3893      EACCELERATOR_PROTECT();
3894    }
3895  }
3896  if (MMCG(mem) == NULL &&
3897      (where == eaccelerator_shm_and_disk ||
3898       where == eaccelerator_shm ||
3899       where == eaccelerator_disk_only)) {
3900    use_shm = 0;
3901    MMCG(mem) = emalloc(size);
3902  }
3903  if (MMCG(mem)) {
3904    zend_hash_init(&MMCG(strings), 0, NULL, NULL, 0);
3905    EACCELERATOR_ALIGN(MMCG(mem));
3906    q = (mm_user_cache_entry*)MMCG(mem);
3907    q->size = size;
3908    MMCG(mem) += offsetof(mm_user_cache_entry,key)+xlen+1;
3909    q->hv = hash_mm(xkey, xlen);;
3910    memcpy(q->key, xkey, xlen+1);
3911    memcpy(&q->value, val, sizeof(zval));
3912    q->ttl = ttl?time(0)+ttl:0;
3913    store_zval(&q->value TSRMLS_CC);
3914    zend_hash_destroy(&MMCG(strings));
3915
3916    /* storing to file */
3917    if ((where == eaccelerator_shm_and_disk ||
3918         ((where == eaccelerator_shm) && !use_shm) ||
3919         where == eaccelerator_disk_only) &&
3920        eaccelerator_md5(s, "/eaccelerator-user-", q->key TSRMLS_CC)) {
3921      int f;
3922      unlink(s);
3923      f = open(s, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, S_IRUSR | S_IWUSR);
3924      if (f > 0) {
3925        mm_file_header hdr;
3926        EACCELERATOR_FLOCK(f, LOCK_EX);
3927        strcpy(hdr.magic,"EACCELERATOR");
3928        hdr.eaccelerator_version = binary_eaccelerator_version;
3929        hdr.zend_version    = binary_zend_version;
3930        hdr.php_version     = binary_php_version;
3931        hdr.size  = q->size;
3932        hdr.mtime = q->ttl;
3933        q->next = q;
3934        hdr.crc32 = eaccelerator_crc32((const char*)q,q->size);
3935        if (write(f, &hdr, sizeof(hdr)) == sizeof(hdr)) {
3936          write(f, q, q->size);
3937          EACCELERATOR_FLOCK(f, LOCK_UN);
3938          close(f);
3939          ret = 1;
3940        } else {
3941          EACCELERATOR_FLOCK(f, LOCK_UN);
3942          close(f);
3943          unlink(s);
3944        }
3945      }
3946      if (!use_shm) {
3947        efree(q);
3948      }
3949    }
3950
3951    if ((where == eaccelerator_shm_and_disk ||
3952         where == eaccelerator_shm ||
3953         where == eaccelerator_shm_only) && use_shm) {
3954      /* storing to shared memory */
3955      slot = q->hv & MM_USER_HASH_MAX;
3956      EACCELERATOR_LOCK_RW();
3957      eaccelerator_mm_instance->user_hash_cnt++;
3958      q->next = eaccelerator_mm_instance->user_hash[slot];
3959      eaccelerator_mm_instance->user_hash[slot] = q;
3960      p = q->next;
3961      while (p != NULL) {
3962        if ((p->hv == q->hv) && (strcmp(p->key, xkey) == 0)) {
3963          eaccelerator_mm_instance->user_hash_cnt--;
3964          q->next = p->next;
3965          eaccelerator_free_nolock(p);
3966          break;
3967        }
3968        q = p;
3969        p = p->next;
3970      }
3971      EACCELERATOR_UNLOCK_RW();
3972      EACCELERATOR_PROTECT();
3973      ret = 1;
3974    }
3975  }
3976  if (xlen != key_len) {efree(xkey);}
3977  return ret;
3978}
3979
3980int eaccelerator_get(const char* key, int key_len, zval* return_value, eaccelerator_cache_place where  TSRMLS_DC) {
3981  unsigned int hv, slot;
3982  char s[MAXPATHLEN];
3983  int xlen;
3984  char* xkey;
3985
3986  xkey = build_key(key, key_len, &xlen TSRMLS_CC);
3987  hv = hash_mm(xkey,xlen);
3988  slot = hv & MM_USER_HASH_MAX;
3989
3990  if (eaccelerator_mm_instance != NULL &&
3991      (where == eaccelerator_shm_and_disk ||
3992       where == eaccelerator_shm ||
3993       where == eaccelerator_shm_only)) {
3994    mm_user_cache_entry *p, *q;
3995    mm_user_cache_entry *x = NULL;
3996    EACCELERATOR_UNPROTECT();
3997    EACCELERATOR_LOCK_RW();
3998    q = NULL;
3999    p = eaccelerator_mm_instance->user_hash[slot];
4000    while (p != NULL) {
4001      if ((p->hv == hv) && (strcmp(p->key, xkey) == 0)) {
4002        x = p;
4003        if (p->ttl != 0 && p->ttl < time(0)) {
4004          if (q == NULL) {
4005            eaccelerator_mm_instance->user_hash[slot] = p->next;
4006          } else {
4007            q->next = p->next;
4008          }
4009          eaccelerator_mm_instance->user_hash_cnt--;
4010          eaccelerator_free_nolock(x);
4011          x = NULL;
4012        }
4013        break;
4014      }
4015      q = p;
4016      p = p->next;
4017    }
4018    EACCELERATOR_UNLOCK_RW();
4019    EACCELERATOR_PROTECT();
4020    if (x) {
4021      memcpy(return_value, &x->value, sizeof(zval));
4022      restore_zval(return_value TSRMLS_CC);
4023      if (xlen != key_len) {efree(xkey);}
4024      return 1;
4025    }
4026  }
4027
4028  /* key is not found in shared memory try to load it from file */
4029  if ((where == eaccelerator_shm_and_disk ||
4030       where == eaccelerator_shm ||
4031       where == eaccelerator_disk_only) &&
4032      eaccelerator_md5(s, "/eaccelerator-user-", xkey TSRMLS_CC)) {
4033    time_t t = time(0);
4034    int use_shm = 1;
4035    int ret = 0;
4036    int f;
4037
4038    if ((f = open(s, O_RDONLY | O_BINARY)) > 0) {
4039      mm_file_header hdr;
4040
4041      EACCELERATOR_FLOCK(f, LOCK_SH);
4042      if (read(f, &hdr, sizeof(hdr)) != sizeof(hdr) ||
4043          strncmp(hdr.magic,"EACCELERATOR",8) != 0 ||
4044          hdr.eaccelerator_version != binary_eaccelerator_version ||
4045          hdr.zend_version != binary_zend_version ||
4046          hdr.php_version != binary_php_version) {
4047        EACCELERATOR_FLOCK(f, LOCK_UN);
4048        close(f);
4049        unlink(s);
4050        if (xlen != key_len) {efree(xkey);}
4051        return 0;
4052      }
4053      if (hdr.mtime == 0 || hdr.mtime > t) {
4054        /* try to put it into shared memory */
4055        mm_user_cache_entry *p = NULL;
4056        if (eaccelerator_mm_instance != NULL &&
4057            (where == eaccelerator_shm_and_disk ||
4058             where == eaccelerator_shm)) {
4059          if (eaccelerator_shm_max == 0 || hdr.size <= eaccelerator_shm_max) {
4060            EACCELERATOR_UNPROTECT();
4061            p = eaccelerator_malloc(hdr.size);
4062            if (p == NULL) {
4063              p = eaccelerator_malloc2(hdr.size TSRMLS_CC);
4064            }
4065            if (p == NULL) {
4066              EACCELERATOR_PROTECT();
4067            }
4068          }
4069        }
4070        if (p == NULL) {
4071          p = emalloc(hdr.size);
4072          use_shm = 0;
4073        }
4074        if (p != NULL) {
4075          if (read(f, p, hdr.size) == hdr.size &&
4076              hdr.size == p->size &&
4077              hdr.crc32 == eaccelerator_crc32((const char*)p,p->size)) {
4078            MMCG(mem) = (char*)((long)p - (long)p->next);
4079            MMCG(compress) = 1;
4080            fixup_zval(&p->value TSRMLS_CC);
4081
4082            if (strcmp(xkey,p->key) != 0) {
4083              if (use_shm) {
4084                eaccelerator_free(p);
4085              } else {
4086                efree(p);
4087              }
4088              EACCELERATOR_FLOCK(f, LOCK_UN);
4089              close(f);
4090              unlink(s);
4091              if (use_shm) EACCELERATOR_PROTECT();
4092              if (xlen != key_len) {efree(xkey);}
4093              return 0;
4094            }
4095
4096            memcpy(return_value, &p->value, sizeof(zval));
4097            restore_zval(return_value TSRMLS_CC);
4098            ret = 1;
4099            if (use_shm) {
4100              /* put it into shared memory */
4101              mm_user_cache_entry *q,*prev;
4102
4103              p->hv = hv;
4104              EACCELERATOR_LOCK_RW();
4105              p->next = eaccelerator_mm_instance->user_hash[slot];
4106              eaccelerator_mm_instance->user_hash[slot] = p;
4107              eaccelerator_mm_instance->user_hash_cnt++;
4108              prev = p;
4109              q = p->next;
4110              while (q != NULL) {
4111                if ((q->hv == hv) && (strcmp(q->key, xkey) == 0)) {
4112                  prev->next = q->next;
4113                  eaccelerator_mm_instance->user_hash_cnt--;
4114                  eaccelerator_free_nolock(q);
4115                  break;
4116                }
4117                prev = q;
4118                q = q->next;
4119              }
4120              EACCELERATOR_UNLOCK_RW();
4121            } else {
4122              efree(p);
4123            }
4124            EACCELERATOR_FLOCK(f, LOCK_UN);
4125            close(f);
4126          } else {
4127            if (use_shm) {
4128              eaccelerator_free(p);
4129            } else {
4130              efree(p);
4131            }
4132            EACCELERATOR_FLOCK(f, LOCK_UN);
4133            close(f);
4134            unlink(s);
4135          }
4136        }
4137        if (use_shm) EACCELERATOR_PROTECT();
4138      } else {
4139        EACCELERATOR_FLOCK(f, LOCK_UN);
4140        close(f);
4141        unlink(s);
4142      }
4143      if (xlen != key_len) {efree(xkey);}
4144      return ret;
4145    }
4146  }
4147  if (xlen != key_len) {efree(xkey);}
4148  return 0;
4149}
4150
4151int eaccelerator_rm(const char* key, int key_len, eaccelerator_cache_place where  TSRMLS_DC) {
4152  unsigned int hv, slot;
4153  mm_user_cache_entry *p, *q;
4154  char s[MAXPATHLEN];
4155  int xlen;
4156  char* xkey;
4157
4158  xkey = build_key(key, key_len, &xlen TSRMLS_CC);
4159  /* removing file */
4160  if ((where == eaccelerator_shm_and_disk ||
4161       where == eaccelerator_shm ||
4162       where == eaccelerator_disk_only) &&
4163      eaccelerator_md5(s, "/eaccelerator-user-", xkey TSRMLS_CC)) {
4164    unlink(s);
4165  }
4166
4167  /* removing from shared memory */
4168  if (eaccelerator_mm_instance != NULL &&
4169      (where == eaccelerator_shm_and_disk ||
4170       where == eaccelerator_shm ||
4171       where == eaccelerator_shm_only)) {
4172    hv = hash_mm(xkey, xlen);
4173    slot = hv & MM_USER_HASH_MAX;
4174
4175    EACCELERATOR_UNPROTECT();
4176    EACCELERATOR_LOCK_RW();
4177    q = NULL;
4178    p = eaccelerator_mm_instance->user_hash[slot];
4179    while (p != NULL) {
4180      if ((p->hv == hv) && (strcmp(p->key, xkey) == 0)) {
4181        if (q == NULL) {
4182          eaccelerator_mm_instance->user_hash[slot] = p->next;
4183        } else {
4184          q->next = p->next;
4185        }
4186        eaccelerator_mm_instance->user_hash_cnt--;
4187        eaccelerator_free_nolock(p);
4188        break;
4189      }
4190      q = p;
4191      p = p->next;
4192    }
4193    EACCELERATOR_UNLOCK_RW();
4194    EACCELERATOR_PROTECT();
4195  }
4196  if (xlen != key_len) {efree(xkey);}
4197  return 1;
4198}
4199
4200size_t eaccelerator_gc(TSRMLS_D) {
4201  size_t size = 0;
4202  unsigned int i;
4203  time_t t = time(0);
4204
4205  if (eaccelerator_mm_instance == NULL) {
4206    return 0;
4207  }
4208  EACCELERATOR_UNPROTECT();
4209  EACCELERATOR_LOCK_RW();
4210  for (i = 0; i < MM_USER_HASH_SIZE; i++) {
4211    mm_user_cache_entry** p = &eaccelerator_mm_instance->user_hash[i];
4212    while (*p != NULL) {
4213      if ((*p)->ttl != 0 && (*p)->ttl < t) {
4214        mm_user_cache_entry *r = *p;
4215        *p = (*p)->next;
4216        eaccelerator_mm_instance->user_hash_cnt--;
4217        size += r->size;
4218        eaccelerator_free_nolock(r);
4219      } else {
4220        p = &(*p)->next;
4221      }
4222    }
4223  }
4224  EACCELERATOR_UNLOCK_RW();
4225  EACCELERATOR_PROTECT();
4226  return size;
4227}
4228
4229PHP_FUNCTION(eaccelerator_lock) {
4230  char *key;
4231  int  key_len;
4232
4233  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
4234                          "s", &key, &key_len) == FAILURE) {
4235    return;
4236  }
4237  if (eaccelerator_lock(key, key_len TSRMLS_CC)) {
4238    RETURN_TRUE;
4239  } else {
4240    RETURN_FALSE;
4241  }
4242}
4243
4244PHP_FUNCTION(eaccelerator_unlock) {
4245  char *key;
4246  int  key_len;
4247
4248  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
4249                          "s", &key, &key_len) == FAILURE) {
4250    return;
4251  }
4252  if (eaccelerator_unlock(key, key_len TSRMLS_CC)) {
4253    RETURN_TRUE;
4254  } else {
4255    RETURN_FALSE;
4256  }
4257}
4258
4259PHP_FUNCTION(eaccelerator_put) {
4260  char   *key;
4261  int    key_len;
4262  zval   *val;
4263  time_t ttl = 0;
4264  long   where = eaccelerator_keys_cache_place;
4265
4266  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
4267                          "sz|ll", &key, &key_len, &val, &ttl, &where) == FAILURE) {
4268    return;
4269  }
4270  if (eaccelerator_put(key, key_len, val, ttl, where TSRMLS_CC)) {
4271    RETURN_TRUE;
4272  } else {
4273    RETURN_FALSE;
4274  }
4275}
4276
4277PHP_FUNCTION(eaccelerator_get) {
4278  char *key;
4279  int  key_len;
4280  long where = eaccelerator_keys_cache_place;
4281
4282  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
4283                          "s|l", &key, &key_len, &where) == FAILURE) {
4284    return;
4285  }
4286  if (eaccelerator_get(key, key_len, return_value, where TSRMLS_CC)) {
4287    return;
4288  } else {
4289    RETURN_NULL();
4290  }
4291}
4292
4293PHP_FUNCTION(eaccelerator_rm) {
4294  char *key;
4295  int  key_len;
4296  long where = eaccelerator_keys_cache_place;
4297
4298  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
4299                          "s|l", &key, &key_len, &where) == FAILURE) {
4300    return;
4301  }
4302  if (eaccelerator_rm(key, key_len, where TSRMLS_CC)) {
4303    RETURN_TRUE;
4304  } else {
4305    RETURN_FALSE;
4306  }
4307}
4308
4309PHP_FUNCTION(eaccelerator_gc) {
4310  if(ZEND_NUM_ARGS() != 0) {
4311    WRONG_PARAM_COUNT;
4312  }
4313  eaccelerator_gc(TSRMLS_C);
4314  RETURN_TRUE;
4315}
4316
4317#ifdef WITH_EACCELERATOR_SESSIONS
4318
4319static int do_session_unlock(TSRMLS_D) {
4320  if (MMCG(session) != NULL) {
4321    eaccelerator_unlock(MMCG(session),strlen(MMCG(session)) TSRMLS_CC);
4322    efree(MMCG(session));
4323    MMCG(session) = NULL;
4324  }
4325  return 1;
4326}
4327
4328static int do_session_lock(const char* sess_name TSRMLS_DC) {
4329  if (MMCG(session) != NULL) {
4330    if (strcmp(MMCG(session),sess_name) == 0) {
4331      return 1;
4332    } else {
4333      do_session_unlock(TSRMLS_C);
4334    }
4335  }
4336  if (eaccelerator_lock(sess_name, strlen(sess_name) TSRMLS_CC)) {
4337    MMCG(session) = estrdup(sess_name);
4338    return 1;
4339  } else {
4340    return 0;
4341  }
4342}
4343
4344#ifdef HAVE_PHP_SESSIONS_SUPPORT
4345
4346PS_OPEN_FUNC(eaccelerator) {
4347  if (eaccelerator_mm_instance == NULL) {
4348    return FAILURE;
4349  }
4350  PS_SET_MOD_DATA((void *)1);
4351  return SUCCESS;
4352}
4353
4354PS_CLOSE_FUNC(eaccelerator) {
4355  if (eaccelerator_mm_instance == NULL) {
4356    return FAILURE;
4357  }
4358  do_session_unlock(TSRMLS_C);
4359  return SUCCESS;
4360}
4361
4362PS_READ_FUNC(eaccelerator) {
4363  char *skey;
4364  int  len;
4365  zval ret;
4366
4367  len = sizeof("sess_") + strlen(key);
4368  skey = do_alloca(len + 1);
4369  strcpy(skey,"sess_");
4370  strcat(skey,key);
4371  do_session_lock(skey TSRMLS_CC);
4372  if (eaccelerator_get(skey, len, &ret, eaccelerator_sessions_cache_place TSRMLS_CC) &&
4373      ret.type == IS_STRING) {
4374    *val = estrdup(ret.value.str.val);
4375    *vallen = ret.value.str.len;
4376    zval_dtor(&ret);
4377  } else {
4378    *val = emalloc(1);
4379    (*val)[0] = '\0';
4380    *vallen = 0;
4381  }
4382  free_alloca(skey);
4383  return SUCCESS;
4384}
4385
4386PS_WRITE_FUNC(eaccelerator) {
4387  char *skey;
4388  int  len;
4389  char *tmp;
4390  time_t ttl;
4391  zval sval;
4392
4393  len = sizeof("sess_") + strlen(key);
4394  skey = do_alloca(len + 1);
4395  strcpy(skey,"sess_");
4396  strcat(skey,key);
4397  if (cfg_get_string("session.gc_maxlifetime", &tmp)==FAILURE) {
4398    ttl = 1440;
4399  } else {
4400    ttl = atoi(tmp);
4401  }
4402  sval.type = IS_STRING;
4403  sval.value.str.val = (char*)val;
4404  sval.value.str.len = vallen;
4405
4406  do_session_lock(skey TSRMLS_CC);
4407  if (eaccelerator_put(skey, len, &sval, ttl, eaccelerator_sessions_cache_place TSRMLS_CC)) {
4408    free_alloca(skey);
4409    return SUCCESS;
4410  } else {
4411    free_alloca(skey);
4412    return FAILURE;
4413  }
4414}
4415
4416PS_DESTROY_FUNC(eaccelerator) {
4417  char *skey;
4418  int  len;
4419
4420  len = sizeof("sess_") + strlen(key);
4421  skey = do_alloca(len + 1);
4422  strcpy(skey,"sess_");
4423  strcat(skey,key);
4424  if (eaccelerator_rm(skey, len, eaccelerator_sessions_cache_place TSRMLS_CC)) {
4425    free_alloca(skey);
4426    return SUCCESS;
4427  } else {
4428    free_alloca(skey);
4429    return FAILURE;
4430  }
4431}
4432
4433PS_GC_FUNC(eaccelerator) {
4434  if (eaccelerator_mm_instance == NULL) {
4435    return FAILURE;
4436  }
4437  eaccelerator_gc(TSRMLS_C);
4438  return SUCCESS;
4439}
4440
4441#ifdef PS_CREATE_SID_ARGS
4442PS_CREATE_SID_FUNC(eaccelerator) {
4443  static char hexconvtab[] = "0123456789abcdef";
4444  PHP_MD5_CTX context;
4445  unsigned char digest[16];
4446  char buf[256];
4447  struct timeval tv;
4448  int i;
4449  int j = 0;
4450  unsigned char c;
4451
4452  long entropy_length;
4453  char *entropy_file;
4454
4455  if (cfg_get_string("session.entropy_length", &entropy_file)==FAILURE) {
4456    entropy_length = 0;
4457  } else {
4458    entropy_length = atoi(entropy_file);
4459  }
4460  if (cfg_get_string("session.entropy_file", &entropy_file)==FAILURE) {
4461    entropy_file = empty_string;
4462  }
4463
4464  gettimeofday(&tv, NULL);
4465  PHP_MD5Init(&context);
4466
4467  sprintf(buf, "%ld%ld%0.8f", tv.tv_sec, tv.tv_usec, php_combined_lcg(TSRMLS_C) * 10);
4468  PHP_MD5Update(&context, buf, strlen(buf));
4469
4470  if (entropy_length > 0) {
4471    int fd;
4472
4473    fd = VCWD_OPEN(entropy_file, O_RDONLY);
4474    if (fd >= 0) {
4475      unsigned char buf[2048];
4476      int n;
4477      int to_read = entropy_length;
4478
4479      while (to_read > 0) {
4480        n = read(fd, buf, MIN(to_read, sizeof(buf)));
4481        if (n <= 0) break;
4482        PHP_MD5Update(&context, buf, n);
4483        to_read -= n;
4484      }
4485      close(fd);
4486    }
4487  }
4488
4489  PHP_MD5Final(digest, &context);
4490
4491  for (i = 0; i < 16; i++) {
4492    c = digest[i];
4493    buf[j++] = hexconvtab[c >> 4];
4494    buf[j++] = hexconvtab[c & 15];
4495  }
4496  buf[j] = '\0';
4497
4498  if (newlen)
4499    *newlen = j;
4500  return estrdup(buf);
4501}
4502#endif
4503
4504static ps_module ps_mod_eaccelerator = {
4505#ifdef PS_CREATE_SID_ARGS
4506  PS_MOD_SID(eaccelerator)
4507#else
4508  PS_MOD(eaccelerator)
4509#endif
4510};
4511
4512#else
4513
4514PHP_FUNCTION(_eaccelerator_session_open) {
4515  if (eaccelerator_mm_instance == NULL) {
4516    RETURN_FALSE;
4517  }
4518  RETURN_TRUE;
4519}
4520
4521PHP_FUNCTION(_eaccelerator_session_close) {
4522  if (eaccelerator_mm_instance == NULL) {
4523    RETURN_FALSE;
4524  }
4525  do_session_unlock(TSRMLS_C);
4526  RETURN_TRUE;
4527}
4528
4529PHP_FUNCTION(_eaccelerator_session_read) {
4530  zval **arg_key;
4531  char *key;
4532  int  len;
4533
4534  if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg_key) == FAILURE) {
4535    WRONG_PARAM_COUNT;
4536  }
4537  len = sizeof("sess_") + (*arg_key)->value.str.len;
4538  key = do_alloca(len + 1);
4539  strcpy(key,"sess_");
4540  strcat(key,(*arg_key)->value.str.val);
4541  do_session_lock(key TSRMLS_CC);
4542  if (eaccelerator_get(key, len, return_value, eaccelerator_sessions_cache_place TSRMLS_CC)) {
4543    free_alloca(key);
4544    return;
4545  } else {
4546    free_alloca(key);
4547    RETURN_EMPTY_STRING();
4548  }
4549}
4550
4551PHP_FUNCTION(_eaccelerator_session_write) {
4552  zval **arg_key, **arg_val;
4553  char *key;
4554  int  len;
4555  char *tmp;
4556  time_t ttl;
4557
4558  if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &arg_key, &arg_val) == FAILURE) {
4559    WRONG_PARAM_COUNT;
4560  }
4561  len = sizeof("sess_") + (*arg_key)->value.str.len;
4562  key = do_alloca(len + 1);
4563  strcpy(key,"sess_");
4564  strcat(key,(*arg_key)->value.str.val);
4565  if (cfg_get_string("session.gc_maxlifetime", &tmp)==FAILURE) {
4566    ttl = 1440;
4567  } else {
4568    ttl = atoi(tmp);
4569  }
4570  do_session_lock(key TSRMLS_CC);
4571  if (eaccelerator_put(key, len, *arg_val, ttl, eaccelerator_sessions_cache_place TSRMLS_CC)) {
4572    free_alloca(key);
4573    RETURN_TRUE;
4574  } else {
4575    free_alloca(key);
4576    RETURN_FALSE;
4577  }
4578}
4579
4580PHP_FUNCTION(_eaccelerator_session_destroy) {
4581  zval **arg_key;
4582  char *key;
4583  int  len;
4584
4585  if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg_key) == FAILURE) {
4586    WRONG_PARAM_COUNT;
4587  }
4588  len = sizeof("sess_") + (*arg_key)->value.str.len;
4589  key = do_alloca(len + 1);
4590  strcpy(key,"sess_");
4591  strcat(key,(*arg_key)->value.str.val);
4592  if (eaccelerator_rm(key, len, eaccelerator_sessions_cache_place TSRMLS_CC)) {
4593    free_alloca(key);
4594    RETURN_TRUE;
4595  } else {
4596    free_alloca(key);
4597    RETURN_FALSE;
4598  }
4599}
4600
4601PHP_FUNCTION(_eaccelerator_session_gc) {
4602  if (eaccelerator_mm_instance == NULL) {
4603    RETURN_FALSE;
4604  }
4605  eaccelerator_gc(TSRMLS_C);
4606  RETURN_TRUE;
4607}
4608#endif /* HAVE_PHP_SESSIONS_SUPPORT */
4609
4610
4611static int eaccelerator_set_session_handlers(TSRMLS_D) {
4612  zval func;
4613  zval retval;
4614  int ret = 1;
4615#ifdef HAVE_PHP_SESSIONS_SUPPORT
4616  zval param;
4617  zval *params[1];
4618/*
4619  if (php_session_register_module(&ps_mod_eaccelerator) != 0) {
4620    return 0;
4621  }
4622*/
4623  if (eaccelerator_sessions_cache_place == eaccelerator_none) {
4624    return 0;
4625  }
4626  ZVAL_STRING(&func, "session_module_name", 0);
4627  INIT_ZVAL(param);
4628  params[0] = &param;
4629  ZVAL_STRING(params[0], "eaccelerator", 0);
4630  if (call_user_function(EG(function_table), NULL, &func, &retval,
4631        1, params TSRMLS_CC) == FAILURE) {
4632    ret = 0;
4633  }
4634  zval_dtor(&retval);
4635  return ret;
4636#else
4637  zval *params[6];
4638  int i;
4639
4640  if (eaccelerator_sessions_cache_place == eaccelerator_none) {
4641    return 0;
4642  }
4643  if (eaccelerator_mm_instance == NULL) {
4644    return 0;
4645  }
4646  if (!zend_hash_exists(EG(function_table), "session_set_save_handler", sizeof("session_set_save_handler"))) {
4647    return 0;
4648  }
4649
4650  ZVAL_STRING(&func, "session_set_save_handler", 0);
4651  MAKE_STD_ZVAL(params[0]);
4652  ZVAL_STRING(params[0], "_eaccelerator_session_open", 1);
4653  MAKE_STD_ZVAL(params[1]);
4654  ZVAL_STRING(params[1], "_eaccelerator_session_close", 1);
4655  MAKE_STD_ZVAL(params[2]);
4656  ZVAL_STRING(params[2], "_eaccelerator_session_read", 1);
4657  MAKE_STD_ZVAL(params[3]);
4658  ZVAL_STRING(params[3], "_eaccelerator_session_write", 1);
4659  MAKE_STD_ZVAL(params[4]);
4660  ZVAL_STRING(params[4], "_eaccelerator_session_destroy", 1);
4661  MAKE_STD_ZVAL(params[5]);
4662  ZVAL_STRING(params[5], "_eaccelerator_session_gc", 1);
4663  if (call_user_function(EG(function_table), NULL, &func, &retval,
4664        6, params TSRMLS_CC) == FAILURE) {
4665    ret = 0;
4666  }
4667  zval_dtor(&retval);
4668  for (i = 0; i < 6; i++) zval_ptr_dtor(&params[i]);
4669  return ret;
4670#endif
4671}
4672
4673PHP_FUNCTION(eaccelerator_set_session_handlers) {
4674  if (eaccelerator_set_session_handlers(TSRMLS_C)) {
4675    RETURN_TRUE;
4676  } else {
4677    RETURN_FALSE;
4678  }
4679}
4680
4681#endif
4682
4683#ifdef WITH_EACCELERATOR_CRASH
4684PHP_FUNCTION(eaccelerator_crash) {
4685  char *x = NULL;
4686  strcpy(x,"Hello");
4687}
4688#endif
4689
4690PHP_FUNCTION(eaccelerator);
4691
4692/******************************************************************************/
4693/*
4694 * Begin of dynamic loadable module interfaces.
4695 * There are two interfaces:
4696 *  - standard php module,
4697 *  - zend extension.
4698 */
4699PHP_INI_MH(eaccelerator_filter) {
4700  mm_cond_entry *p, *q;
4701  char *s = new_value;
4702  char *ss;
4703  int  not;
4704  for (p = MMCG(cond_list); p != NULL; p = q) {
4705    q = p->next;
4706    if (p->str) {
4707      free(p->str);
4708    }
4709    free(p);
4710  }
4711  MMCG(cond_list) = NULL;
4712  while (*s) {
4713    for (; *s == ' ' || *s == '\t'; s++)
4714      ;
4715    if (*s == 0)
4716      break;
4717    if (*s == '!') {
4718      s++;
4719      not = 1;
4720    } else {
4721      not = 0;
4722    }
4723    ss = s;
4724    for (; *s && *s != ' ' && *s != '\t'; s++)
4725      ;
4726    if ((s > ss) && *ss) {
4727      p = (mm_cond_entry *)malloc(sizeof(mm_cond_entry));
4728      if (p == NULL)
4729        break;
4730      p->not = not;
4731      p->len = s-ss;
4732      p->str = malloc(p->len+1);
4733      memcpy(p->str, ss, p->len);
4734      p->str[p->len] = 0;
4735      p->next = MMCG(cond_list);
4736      MMCG(cond_list) = p;
4737    }
4738  }
4739  return SUCCESS;
4740}
4741
4742static PHP_INI_MH(eaccelerator_OnUpdateLong) {
4743  long *p = (long*)mh_arg1;
4744  *p = zend_atoi(new_value, new_value_length);
4745  return SUCCESS;
4746}
4747
4748static PHP_INI_MH(eaccelerator_OnUpdateBool) {
4749  zend_bool *p = (zend_bool*)mh_arg1;
4750  if (strncasecmp("on", new_value, sizeof("on"))) {
4751    *p = (zend_bool) atoi(new_value);
4752  } else {
4753    *p = (zend_bool) 1;
4754  }
4755  return SUCCESS;
4756}
4757
4758static PHP_INI_MH(eaccelerator_OnUpdateCachePlace) {
4759  eaccelerator_cache_place *p = (eaccelerator_cache_place*)mh_arg1;
4760  if (strncasecmp("shm_and_disk", new_value, sizeof("shm_and_disk")) == 0) {
4761    *p = eaccelerator_shm_and_disk;
4762  } else if (strncasecmp("shm", new_value, sizeof("shm")) == 0) {
4763    *p = eaccelerator_shm;
4764  } else if (strncasecmp("shm_only", new_value, sizeof("shm_only")) == 0) {
4765    *p = eaccelerator_shm_only;
4766  } else if (strncasecmp("disk_only", new_value, sizeof("disk_only")) == 0) {
4767    *p = eaccelerator_disk_only;
4768  } else if (strncasecmp("none", new_value, sizeof("none")) == 0) {
4769    *p = eaccelerator_none;
4770  }
4771  return SUCCESS;
4772}
4773
4774#ifndef ZEND_ENGINE_2
4775#define OnUpdateLong OnUpdateInt
4776#endif
4777
4778PHP_INI_BEGIN()
4779STD_PHP_INI_ENTRY("eaccelerator.enable",         "1", PHP_INI_ALL, OnUpdateBool, enabled, zend_eaccelerator_globals, eaccelerator_globals)
4780STD_PHP_INI_ENTRY("eaccelerator.optimizer",      "1", PHP_INI_ALL, OnUpdateBool, optimizer_enabled, zend_eaccelerator_globals, eaccelerator_globals)
4781STD_PHP_INI_ENTRY("eaccelerator.compress",       "1", PHP_INI_ALL, OnUpdateBool, compression_enabled, zend_eaccelerator_globals, eaccelerator_globals)
4782STD_PHP_INI_ENTRY("eaccelerator.compress_level", "9", PHP_INI_ALL, OnUpdateLong, compress_level, zend_eaccelerator_globals, eaccelerator_globals)                 
4783ZEND_INI_ENTRY1("eaccelerator.shm_size",         "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &eaccelerator_shm_size)
4784ZEND_INI_ENTRY1("eaccelerator.shm_max",          "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &eaccelerator_shm_max)
4785ZEND_INI_ENTRY1("eaccelerator.shm_ttl",          "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &eaccelerator_shm_ttl)
4786ZEND_INI_ENTRY1("eaccelerator.shm_prune_period", "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &eaccelerator_shm_prune_period)
4787ZEND_INI_ENTRY1("eaccelerator.debug",            "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &eaccelerator_debug)
4788ZEND_INI_ENTRY1("eaccelerator.check_mtime",      "1", PHP_INI_SYSTEM, eaccelerator_OnUpdateBool, &eaccelerator_check_mtime)
4789ZEND_INI_ENTRY1("eaccelerator.shm_only",         "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateBool, &eaccelerator_scripts_shm_only)
4790ZEND_INI_ENTRY1("eaccelerator.keys",             "shm_and_disk", PHP_INI_SYSTEM, eaccelerator_OnUpdateCachePlace, &eaccelerator_keys_cache_place)
4791ZEND_INI_ENTRY1("eaccelerator.sessions",         "shm_and_disk", PHP_INI_SYSTEM, eaccelerator_OnUpdateCachePlace, &eaccelerator_sessions_cache_place)
4792ZEND_INI_ENTRY1("eaccelerator.content",          "shm_and_disk", PHP_INI_SYSTEM, eaccelerator_OnUpdateCachePlace, &eaccelerator_content_cache_place)
4793STD_PHP_INI_ENTRY("eaccelerator.cache_dir",      "/tmp/eaccelerator", PHP_INI_SYSTEM, OnUpdateString,
4794                  cache_dir, zend_eaccelerator_globals, eaccelerator_globals)
4795PHP_INI_ENTRY("eaccelerator.filter",             "",  PHP_INI_ALL, eaccelerator_filter)
4796PHP_INI_END()
4797
4798static void eaccelerator_clean_request(TSRMLS_D) {
4799  mm_used_entry  *p = (mm_used_entry*)MMCG(used_entries);
4800  if (eaccelerator_mm_instance != NULL) {
4801    EACCELERATOR_UNPROTECT();
4802    mm_unlock(eaccelerator_mm_instance->mm);
4803    if (p != NULL || eaccelerator_mm_instance->locks != NULL) {
4804      EACCELERATOR_LOCK_RW();
4805      while (p != NULL) {
4806        p->entry->use_cnt--;
4807        if (p->entry->removed && p->entry->use_cnt <= 0) {
4808          if (eaccelerator_mm_instance->removed == p->entry) {
4809            eaccelerator_mm_instance->removed = p->entry->next;
4810            eaccelerator_mm_instance->rem_cnt--;
4811            eaccelerator_free_nolock(p->entry);
4812            p->entry = NULL;
4813          } else {
4814            mm_cache_entry *q = eaccelerator_mm_instance->removed;
4815            while (q != NULL && q->next != p->entry) {
4816              q = q->next;
4817            }
4818            if (q != NULL) {
4819              q->next = p->entry->next;
4820              eaccelerator_mm_instance->rem_cnt--;
4821              eaccelerator_free_nolock(p->entry);
4822              p->entry = NULL;
4823            }
4824          }
4825        }
4826        p = p->next;
4827      }
4828      if (eaccelerator_mm_instance->locks != NULL) {
4829        pid_t    pid    = getpid();
4830#ifdef ZTS
4831        THREAD_T thread = tsrm_thread_id();
4832#endif
4833        mm_lock_entry** p = &eaccelerator_mm_instance->locks;
4834        while ((*p) != NULL) {
4835#ifdef ZTS
4836          if ((*p)->pid == pid && (*p)->thread == thread) {
4837#else
4838          if ((*p)->pid == pid) {
4839#endif
4840            mm_lock_entry* x = *p;
4841            *p = (*p)->next;
4842            eaccelerator_free_nolock(x);
4843          } else {
4844            p = &(*p)->next;
4845          }
4846        }
4847      }
4848      EACCELERATOR_UNLOCK_RW();
4849    }
4850    EACCELERATOR_PROTECT();
4851    p = (mm_used_entry*)MMCG(used_entries);
4852    while (p != NULL) {
4853      mm_used_entry* r = p;
4854      p = p->next;
4855      if (r->entry != NULL && r->entry->use_cnt < 0) {
4856        efree(r->entry);
4857      }
4858      efree(r);
4859    }
4860  }
4861  MMCG(used_entries) = NULL;
4862  MMCG(in_request) = 0;
4863}
4864
4865static void __attribute__((destructor)) eaccelerator_clean_shutdown(void) {
4866  if (eaccelerator_mm_instance != NULL) {
4867    TSRMLS_FETCH();
4868    if (MMCG(in_request)) {
4869      fflush(stdout);
4870      fflush(stderr);
4871      eaccelerator_clean_request(TSRMLS_C);
4872      if (eaccelerator_debug > 0) {
4873        if (EG(active_op_array)) {
4874          fprintf(stderr, "[%d] EACCELERATOR: PHP unclean shutdown on opline %ld of %s() at %s:%u\n\n",
4875            getpid(),
4876            (long)(active_opline-EG(active_op_array)->opcodes),
4877            get_active_function_name(TSRMLS_C),
4878            zend_get_executed_filename(TSRMLS_C),
4879            zend_get_executed_lineno(TSRMLS_C));
4880        }  else {
4881          fprintf(stderr, "[%d] EACCELERATOR: PHP unclean shutdown\n\n",getpid());
4882        }
4883      }
4884    }
4885  }
4886}
4887
4888#ifdef WITH_EACCELERATOR_CRASH_DETECTION
4889static void eaccelerator_crash_handler(int dummy) {
4890  TSRMLS_FETCH();
4891  fflush(stdout);
4892  fflush(stderr);
4893#ifdef SIGSEGV
4894  if (MMCG(original_sigsegv_handler) != eaccelerator_crash_handler) {
4895    signal(SIGSEGV, MMCG(original_sigsegv_handler));
4896  } else {
4897    signal(SIGSEGV, SIG_DFL);
4898  }
4899#endif
4900#ifdef SIGFPE
4901  if (MMCG(original_sigfpe_handler) != eaccelerator_crash_handler) {
4902    signal(SIGFPE, MMCG(original_sigfpe_handler));
4903  } else {
4904    signal(SIGFPE, SIG_DFL);
4905  }
4906#endif
4907#ifdef SIGBUS
4908  if (MMCG(original_sigbus_handler) != eaccelerator_crash_handler) {
4909    signal(SIGBUS, MMCG(original_sigbus_handler));
4910  } else {
4911    signal(SIGBUS, SIG_DFL);
4912  }
4913#endif
4914#ifdef SIGILL
4915  if (MMCG(original_sigill_handler) != eaccelerator_crash_handler) {
4916    signal(SIGILL, MMCG(original_sigill_handler));
4917  } else {
4918    signal(SIGILL, SIG_DFL);
4919  }
4920#endif
4921#ifdef SIGABRT
4922  if (MMCG(original_sigabrt_handler) != eaccelerator_crash_handler) {
4923    signal(SIGABRT, MMCG(original_sigabrt_handler));
4924  } else {
4925    signal(SIGABRT, SIG_DFL);
4926  }
4927#endif
4928  eaccelerator_clean_request(TSRMLS_C);
4929  if (EG(active_op_array)) {
4930    fprintf(stderr, "[%d] EACCELERATOR: PHP crashed on opline %ld of %s() at %s:%u\n\n",
4931      getpid(),
4932      (long)(active_opline-EG(active_op_array)->opcodes),
4933      get_active_function_name(TSRMLS_C),
4934      zend_get_executed_filename(TSRMLS_C),
4935      zend_get_executed_lineno(TSRMLS_C));
4936  } else {
4937    fprintf(stderr, "[%d] EACCELERATOR: PHP crashed\n\n",getpid());
4938  }
4939#if !defined(WIN32) && !defined(NETWARE)
4940  kill(getpid(), dummy);
4941#else
4942  raise(dummy);
4943#endif
4944}
4945#endif
4946
4947static void eaccelerator_init_globals(zend_eaccelerator_globals *eaccelerator_globals)
4948{
4949  eaccelerator_globals->used_entries      = NULL;
4950  eaccelerator_globals->enabled           = 1;
4951  eaccelerator_globals->cache_dir         = NULL;
4952  eaccelerator_globals->optimizer_enabled = 1;
4953  eaccelerator_globals->compiler          = 0;
4954  eaccelerator_globals->encoder           = 0;
4955  eaccelerator_globals->cond_list         = NULL;
4956  eaccelerator_globals->content_headers   = NULL;
4957#ifdef WITH_EACCELERATOR_SESSIONS
4958  eaccelerator_globals->session           = NULL;
4959#endif
4960  eaccelerator_globals->hostname[0]       = '\000';
4961  eaccelerator_globals->in_request        = 0;
4962}
4963
4964static void eaccelerator_globals_dtor(zend_eaccelerator_globals *eaccelerator_globals)
4965{
4966  mm_cond_entry *p, *q;
4967
4968  for (p = eaccelerator_globals->cond_list; p != NULL; p = q) {
4969    q = p->next;
4970    if (p->str) {
4971      free(p->str);
4972    }
4973    free(p);
4974  }
4975  eaccelerator_globals->cond_list = NULL;
4976}
4977
4978static void register_eaccelerator_as_zend_extension();
4979static int eaccelerator_set_session_handlers();
4980
4981static int eaccelerator_check_php_version(TSRMLS_D) {
4982  zval v;
4983  int ret = 0;
4984  if (zend_get_constant("PHP_VERSION", sizeof("PHP_VERSION")-1, &v TSRMLS_CC)) {
4985    if (Z_TYPE(v) == IS_STRING &&
4986        Z_STRLEN(v) == sizeof(PHP_VERSION)-1 &&
4987        strcmp(Z_STRVAL(v),PHP_VERSION) == 0) {
4988      ret = 1;
4989    } else {
4990      zend_error(E_CORE_WARNING,"[%s] This build of \"%s\" was compiled for PHP version %s. Rebuild it for your PHP version (%s) or download precompiled binaries.\n", EACCELERATOR_EXTENSION_NAME,EACCELERATOR_EXTENSION_NAME,PHP_VERSION,Z_STRVAL(v));
4991    }
4992    zval_dtor(&v);
4993  } else {
4994    zend_error(E_CORE_WARNING,"[%s] This build of \"%s\" was compiled for PHP version %s. Rebuild it for your PHP version.\n", EACCELERATOR_EXTENSION_NAME,EACCELERATOR_EXTENSION_NAME,PHP_VERSION);
4995  }
4996  return ret;
4997}
4998
4999PHP_MINIT_FUNCTION(eaccelerator) {
5000  if (type == MODULE_PERSISTENT) {
5001#ifndef ZEND_WIN32
5002    if (strcmp(sapi_module.name,"apache") == 0) {
5003      /* Is the parent process - init */
5004/*
5005      sleep(1);
5006      if (getppid() != 1) {
5007*/
5008      if (getpid() != getpgrp()) {
5009        return SUCCESS;
5010      }
5011    }
5012#endif
5013#ifdef WITH_EACCELERATOR_LOADER
5014    if (zend_hash_exists(&module_registry, EACCELERATOR_LOADER_EXTENSION_NAME, sizeof(EACCELERATOR_LOADER_EXTENSION_NAME))) {
5015      zend_error(E_CORE_WARNING,"Extension \"%s\" is not need with \"%s\". Remove it from php.ini\n", EACCELERATOR_LOADER_EXTENSION_NAME, EACCELERATOR_EXTENSION_NAME);
5016      zend_hash_del(&module_registry, EACCELERATOR_LOADER_EXTENSION_NAME, sizeof(EACCELERATOR_LOADER_EXTENSION_NAME));
5017    }
5018#endif
5019  }
5020  if (!eaccelerator_check_php_version(TSRMLS_C)) {
5021    return FAILURE;
5022  }
5023/*??? FIXME
5024  ZEND_INIT_MODULE_GLOBALS(eaccelerator, eaccelerator_init_globals, eaccelerator_globals_dtor);
5025*/
5026  ZEND_INIT_MODULE_GLOBALS(eaccelerator, eaccelerator_init_globals, NULL);
5027  REGISTER_INI_ENTRIES();
5028  REGISTER_STRING_CONSTANT("EACCELERATOR_VERSION", EACCELERATOR_VERSION, CONST_CS | CONST_PERSISTENT);
5029  REGISTER_LONG_CONSTANT("EACCELERATOR_SHM_AND_DISK", eaccelerator_shm_and_disk, CONST_CS | CONST_PERSISTENT);
5030  REGISTER_LONG_CONSTANT("EACCELERATOR_SHM", eaccelerator_shm, CONST_CS | CONST_PERSISTENT);
5031  REGISTER_LONG_CONSTANT("EACCELERATOR_SHM_ONLY", eaccelerator_shm_only, CONST_CS | CONST_PERSISTENT);
5032  REGISTER_LONG_CONSTANT("EACCELERATOR_DISK_ONLY", eaccelerator_disk_only, CONST_CS | CONST_PERSISTENT);
5033  REGISTER_LONG_CONSTANT("EACCELERATOR_NONE", eaccelerator_none, CONST_CS | CONST_PERSISTENT);
5034  binary_eaccelerator_version = encode_version(EACCELERATOR_VERSION);
5035  binary_php_version = encode_version(PHP_VERSION);
5036  binary_zend_version = encode_version(ZEND_VERSION);
5037  eaccelerator_is_extension = 1;
5038  if (type == MODULE_PERSISTENT &&
5039      strcmp(sapi_module.name, "cgi") != 0 &&
5040      strcmp(sapi_module.name, "cli") != 0) {
5041#if defined(DEBUG) || defined(TEST_PERFORMANCE) || defined(PROFILE_OPCODES)
5042    F_fp = fopen(DEBUG_LOGFILE, "a");
5043    if (!F_fp) {
5044      F_fp = fopen(DEBUG_LOGFILE_CGI, "a");
5045      if (!F_fp) {
5046        fprintf(stderr, "Cann't open log file '%s'.", DEBUG_LOGFILE);
5047      }
5048      chmod(DEBUG_LOGFILE_CGI, 0777);
5049    }
5050    fputs("\n=======================================\n", F_fp);
5051    fprintf(F_fp, "[%d] EACCELERATOR STARTED\n", getpid());
5052    fputs("=======================================\n", F_fp);
5053    fflush(F_fp);
5054#endif
5055
5056    if (init_mm(TSRMLS_C) == FAILURE) {
5057      zend_error(E_CORE_WARNING,"[%s] Can not create shared memory area\n", EACCELERATOR_EXTENSION_NAME);
5058    }
5059
5060    mm_saved_zend_compile_file = zend_compile_file;
5061#ifdef PROFILE_OPCODES
5062    zend_compile_file = profile_compile_file;
5063    mm_saved_zend_execute = zend_execute;
5064    zend_execute = profile_execute;
5065#else
5066    zend_compile_file = eaccelerator_compile_file;
5067#ifdef WITH_EACCELERATOR_EXECUTOR
5068    mm_saved_zend_execute = zend_execute;
5069    zend_execute = eaccelerator_execute;
5070#endif
5071#endif
5072#ifndef HAS_ATTRIBUTE
5073    atexit(eaccelerator_clean_shutdown);
5074#endif
5075  }
5076#if defined(WITH_EACCELERATOR_SESSIONS) && defined(HAVE_PHP_SESSIONS_SUPPORT)
5077    if (eaccelerator_sessions_cache_place != eaccelerator_none &&
5078        eaccelerator_sessions_registered == 0) {
5079      php_session_register_module(&ps_mod_eaccelerator);
5080      eaccelerator_sessions_registered = 1;
5081    }
5082#endif
5083#ifdef WITH_EACCELERATOR_CONTENT_CACHING
5084    eaccelerator_content_cache_startup();
5085#endif
5086  if (!eaccelerator_is_zend_extension) {
5087    register_eaccelerator_as_zend_extension();
5088  }
5089  return SUCCESS;
5090}
5091
5092PHP_MSHUTDOWN_FUNCTION(eaccelerator) {
5093  if (eaccelerator_mm_instance == NULL || !eaccelerator_is_extension) {
5094    return SUCCESS;
5095  }
5096  zend_compile_file = mm_saved_zend_compile_file;
5097#if defined(PROFILE_OPCODES) || defined(WITH_EACCELERATOR_EXECUTOR)
5098  zend_execute = mm_saved_zend_execute;
5099#endif
5100#ifdef WITH_EACCELERATOR_CONTENT_CACHING
5101  eaccelerator_content_cache_shutdown();
5102#endif
5103  shutdown_mm(TSRMLS_C);
5104#if defined(DEBUG) || defined(TEST_PERFORMANCE) || defined(PROFILE_OPCODES)
5105  fputs("========================================\n", F_fp);
5106  fprintf(F_fp, "[%d] EACCELERATOR STOPPED\n", getpid());
5107  fputs("========================================\n\n", F_fp);
5108  fclose(F_fp);
5109  F_fp = NULL;
5110#endif
5111  UNREGISTER_INI_ENTRIES();
5112#ifndef ZTS
5113  eaccelerator_globals_dtor(&eaccelerator_globals TSRMLS_CC);
5114#endif
5115  eaccelerator_is_zend_extension = 0;
5116  eaccelerator_is_extension = 0;
5117  return SUCCESS;
5118}
5119
5120PHP_RINIT_FUNCTION(eaccelerator)
5121{
5122        if (eaccelerator_mm_instance == NULL)
5123        {
5124                return SUCCESS;
5125        }
5126        /*
5127         * HOESH: Initialization on first call,
5128         * came from eaccelerator_zend_startup().
5129         */
5130        if (eaccelerator_global_function_table.nTableSize == 0)
5131        {
5132                zend_function tmp_func;
5133                zend_class_entry tmp_class;
5134
5135                // Don't need this, as the context given by function argument.
5136                // TSRMLS_FETCH();
5137
5138                zend_hash_init_ex(&eaccelerator_global_function_table, 100, NULL, NULL, 1, 0);
5139                zend_hash_copy(&eaccelerator_global_function_table, CG(function_table), NULL, &tmp_func, sizeof(zend_function));
5140               
5141                zend_hash_init_ex(&eaccelerator_global_class_table, 10, NULL, NULL, 1, 0);
5142                zend_hash_copy(&eaccelerator_global_class_table, CG(class_table), NULL, &tmp_class, sizeof(zend_class_entry));
5143        }
5144#if defined(DEBUG)
5145        fprintf(F_fp, "[%d] Enter RINIT\n",getpid()); fflush(F_fp);
5146#endif
5147#ifdef PROFILE_OPCODES
5148        fputs("\n========================================\n", F_fp);
5149        fflush(F_fp);
5150#endif
5151        MMCG(in_request) = 1;
5152        MMCG(used_entries) = NULL;
5153        MMCG(compiler) = 0;
5154        MMCG(encoder) = 0;
5155        MMCG(refcount_helper) = 1;
5156        MMCG(compress_content) = 1;
5157        MMCG(content_headers) = NULL;
5158        /* Storing Host Name */
5159        MMCG(hostname)[0] = '\000';
5160        {
5161                zval  **server_vars, **hostname;
5162
5163                if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &server_vars) == SUCCESS &&
5164                        Z_TYPE_PP(server_vars) == IS_ARRAY &&
5165                        zend_hash_find(Z_ARRVAL_PP(server_vars), "SERVER_NAME", sizeof("SERVER_NAME"), (void **) &hostname)==SUCCESS &&
5166                        Z_TYPE_PP(hostname) == IS_STRING &&
5167                        Z_STRLEN_PP(hostname) > 0)
5168                {
5169                        if (sizeof(MMCG(hostname)) > Z_STRLEN_PP(hostname))
5170                        {
5171                                memcpy(MMCG(hostname),Z_STRVAL_PP(hostname),Z_STRLEN_PP(hostname)+1);
5172                        }
5173                        else
5174                        {
5175                                memcpy(MMCG(hostname),Z_STRVAL_PP(hostname),sizeof(MMCG(hostname))-1);
5176                                MMCG(hostname)[sizeof(MMCG(hostname))-1] = '\000';
5177                        }
5178                }
5179        }
5180#if defined(DEBUG)
5181        fprintf(F_fp, "[%d] Leave RINIT\n",getpid()); fflush(F_fp);
5182#endif
5183#if defined(DEBUG) || defined(TEST_PERFORMANCE)  || defined(PROFILE_OPCODES)
5184        MMCG(xpad) = 0;
5185#endif
5186#ifdef PROFILE_OPCODES
5187        MMCG(profile_level) = 0;
5188#endif
5189#ifdef WITH_EACCELERATOR_CRASH_DETECTION
5190#ifdef SIGSEGV
5191        MMCG(original_sigsegv_handler) = signal(SIGSEGV, eaccelerator_crash_handler);
5192#endif
5193#ifdef SIGFPE
5194        MMCG(original_sigfpe_handler) = signal(SIGFPE, eaccelerator_crash_handler);
5195#endif
5196#ifdef SIGBUS
5197        MMCG(original_sigbus_handler) = signal(SIGBUS, eaccelerator_crash_handler);
5198#endif
5199#ifdef SIGILL
5200        MMCG(original_sigill_handler) = signal(SIGILL, eaccelerator_crash_handler);
5201#endif
5202#ifdef SIGABRT
5203        MMCG(original_sigabrt_handler) = signal(SIGABRT, eaccelerator_crash_handler);
5204#endif
5205#endif
5206        return SUCCESS;
5207}
5208
5209PHP_RSHUTDOWN_FUNCTION(eaccelerator)
5210{
5211        if (eaccelerator_mm_instance == NULL)
5212        {
5213                return SUCCESS;
5214        }
5215#ifdef WITH_EACCELERATOR_CRASH_DETECTION
5216#ifdef SIGSEGV
5217        if (MMCG(original_sigsegv_handler) != eaccelerator_crash_handler)
5218        {
5219                signal(SIGSEGV, MMCG(original_sigsegv_handler));
5220        }
5221        else
5222        {
5223                signal(SIGSEGV, SIG_DFL);
5224        }
5225#endif
5226#ifdef SIGFPE
5227        if (MMCG(original_sigfpe_handler) != eaccelerator_crash_handler)
5228        {
5229                signal(SIGFPE, MMCG(original_sigfpe_handler));
5230        }
5231        else
5232        {
5233                signal(SIGFPE, SIG_DFL);
5234        }
5235#endif
5236#ifdef SIGBUS
5237        if (MMCG(original_sigbus_handler) != eaccelerator_crash_handler)
5238        {
5239                signal(SIGBUS, MMCG(original_sigbus_handler));
5240        }
5241        else
5242        {
5243                signal(SIGBUS, SIG_DFL);
5244        }
5245#endif
5246#ifdef SIGILL
5247        if (MMCG(original_sigill_handler) != eaccelerator_crash_handler)
5248        {
5249                signal(SIGILL, MMCG(original_sigill_handler));
5250        }
5251        else
5252        {
5253                signal(SIGILL, SIG_DFL);
5254        }
5255#endif
5256#ifdef SIGABRT
5257        if (MMCG(original_sigabrt_handler) != eaccelerator_crash_handler)
5258        {
5259                signal(SIGABRT, MMCG(original_sigabrt_handler));
5260        }
5261        else
5262        {
5263                signal(SIGABRT, SIG_DFL);
5264        }
5265#endif
5266#endif
5267#if defined(DEBUG)
5268        fprintf(F_fp, "[%d] Enter RSHUTDOWN\n",getpid()); fflush(F_fp);
5269#endif
5270        eaccelerator_clean_request(TSRMLS_C);
5271#if defined(DEBUG)
5272        fprintf(F_fp, "[%d] Leave RSHUTDOWN\n",getpid()); fflush(F_fp);
5273#endif
5274        return SUCCESS;
5275}
5276
5277#ifdef ZEND_ENGINE_2
5278ZEND_BEGIN_ARG_INFO(eaccelerator_second_arg_force_ref, 0)
5279  ZEND_ARG_PASS_INFO(0)
5280  ZEND_ARG_PASS_INFO(1)
5281ZEND_END_ARG_INFO();
5282#else
5283static unsigned char eaccelerator_second_arg_force_ref[] = {2, BYREF_NONE, BYREF_FORCE};
5284#endif
5285
5286function_entry eaccelerator_functions[] = {
5287  PHP_FE(eaccelerator, NULL)
5288  PHP_FE(eaccelerator_put, NULL)
5289  PHP_FE(eaccelerator_get, NULL)
5290  PHP_FE(eaccelerator_rm, NULL)
5291  PHP_FE(eaccelerator_gc, NULL)
5292  PHP_FE(eaccelerator_lock, NULL)
5293  PHP_FE(eaccelerator_unlock, NULL)
5294#ifdef WITH_EACCELERATOR_ENCODER
5295  PHP_FE(eaccelerator_encode, eaccelerator_second_arg_force_ref)
5296#endif
5297#ifdef WITH_EACCELERATOR_LOADER
5298  PHP_FE(eaccelerator_load, NULL)
5299  PHP_FE(_eaccelerator_loader_file, NULL)
5300  PHP_FE(_eaccelerator_loader_line, NULL)
5301#endif
5302#ifdef WITH_EACCELERATOR_SESSIONS
5303#ifndef HAVE_PHP_SESSIONS_SUPPORT
5304  PHP_FE(_eaccelerator_session_open, NULL)
5305  PHP_FE(_eaccelerator_session_close, NULL)
5306  PHP_FE(_eaccelerator_session_read, NULL)
5307  PHP_FE(_eaccelerator_session_write, NULL)
5308  PHP_FE(_eaccelerator_session_destroy, NULL)
5309  PHP_FE(_eaccelerator_session_gc, NULL)
5310#endif
5311  PHP_FE(eaccelerator_set_session_handlers, NULL)
5312#endif
5313#ifdef WITH_EACCELERATOR_CONTENT_CACHING
5314  PHP_FE(_eaccelerator_output_handler, NULL)
5315  PHP_FE(eaccelerator_cache_page, NULL)
5316  PHP_FE(eaccelerator_rm_page, NULL)
5317  PHP_FE(eaccelerator_cache_output, NULL)
5318  PHP_FE(eaccelerator_cache_result, NULL)
5319#endif
5320#ifdef WITH_EACCELERATOR_CRASH
5321  PHP_FE(eaccelerator_crash, NULL)
5322#endif
5323  {NULL, NULL, NULL}
5324};
5325
5326zend_module_entry eaccelerator_module_entry = {
5327#if ZEND_MODULE_API_NO >= 20010901
5328  STANDARD_MODULE_HEADER,
5329#endif
5330  EACCELERATOR_EXTENSION_NAME,
5331  eaccelerator_functions,
5332  PHP_MINIT(eaccelerator),
5333  PHP_MSHUTDOWN(eaccelerator),
5334  PHP_RINIT(eaccelerator),
5335  PHP_RSHUTDOWN(eaccelerator),
5336  PHP_MINFO(eaccelerator),
5337#if ZEND_MODULE_API_NO >= 20010901
5338  EACCELERATOR_VERSION,          /* extension version number (string) */
5339#endif
5340  STANDARD_MODULE_PROPERTIES
5341};
5342
5343#if defined(COMPILE_DL_EACCELERATOR)
5344ZEND_GET_MODULE(eaccelerator)
5345#endif
5346
5347static startup_func_t last_startup;
5348static zend_llist_element *eaccelerator_el;
5349
5350#define EACCELERATOR_VERSION_GUID   "PHPE8EDA1B6-806A-4851-B1C8-A6B4712F44FB"
5351#define EACCELERATOR_LOGO_GUID      "PHPE6F78DE9-13E4-4dee-8518-5FA2DACEA803"
5352
5353#define EACCELERATOR_VERSION_STRING ("eAccelerator " EACCELERATOR_VERSION " (PHP " PHP_VERSION ")")
5354
5355static const unsigned char eaccelerator_logo[] = {
5356      71,  73,  70,  56,  57,  97,  88,   0,  31,   0,
5357     213,   0,   0, 150, 153, 196, 237, 168,  86, 187,
5358     206, 230,   4,   4,   4, 108, 110, 144,  99, 144,
5359     199, 136, 138, 184,  87,  88, 109, 165, 165, 167,
5360     163, 166, 202, 240, 151,  44, 149,  91,  21, 225,
5361     225, 229,   4,  76, 164, 252, 215, 171, 255, 255,
5362     255, 212, 212, 224, 241, 200, 149, 141, 144, 192,
5363     216, 216, 226, 251, 230, 205, 192, 193, 218, 207,
5364     221, 238, 181, 188, 216, 130, 132, 168, 150, 152,
5365     185, 152, 152, 154, 180, 181, 198, 215, 184, 147,
5366      40, 102, 177, 224, 232, 242, 244, 244, 244, 235,
5367     236, 239, 118, 121, 157, 193, 193, 194, 146, 148,
5368     174, 181, 143,  96, 154, 183, 219, 156, 159, 200,
5369     126, 128, 170, 174, 175, 193,  65,  39,   7, 232,
5370     214, 192, 254, 241, 226, 246, 246, 248, 108,  65,
5371      13, 142, 144, 185, 252, 224, 189, 138, 171, 213,
5372      69, 122, 188, 239, 244, 249,  48,  49,  60, 176,
5373     178, 209, 200, 201, 222, 252, 252, 253, 251, 251,
5374     251, 162, 163, 187, 208, 208, 213, 169, 171, 205,
5375     241, 234, 225, 255, 252, 249, 254, 248, 241, 140,
5376     142, 169, 249, 186, 111,  33, 249,   4,   0,   0,
5377       0,   0,   0,  44,   0,   0,   0,   0,  88,   0,
5378      31,   0,   0,   6, 255,  64, 137, 112,  72,  44,
5379      26, 143, 200, 164, 114, 201,  92,  62, 158, 208,
5380     168, 116,  74, 173,  90, 175, 216, 108,  85, 168,
5381     237, 122, 191,  15,  25, 163, 118, 209, 153,   0,
5382      68, 128,  73, 119, 169,  49, 100,  86,  46, 120,
5383      78, 127, 216,  60,  21,  93,  83,   8, 208,  85,
5384      60,  54,  83, 114, 117, 132,  89,  32,  23,  38,
5385      73,  38, 103,  72,  38,  23,  32,  82, 123, 146,