source: eaccelerator/tags/0.9.5-rc1/eaccelerator.c @ 237

Revision 237, 86.9 KB checked in by bart, 4 years ago (diff)
  • Make clean routine support dir hashing. Again, this should be tested on win32!
  • Use a define for the magic string in the eAccelerator file headers
  • Bump up version to 0.9.5-rc1
  • Put -O2 back on for -rc1
  • 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 - 2006 eAccelerator                               |
6   | http://eaccelerator.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   $Id$
26*/
27
28#include "eaccelerator.h"
29#include "eaccelerator_version.h"
30
31#ifdef HAVE_EACCELERATOR
32
33#include "opcodes.h"
34
35#include "zend.h"
36#include "zend_API.h"
37#include "zend_extensions.h"
38
39#include "debug.h"
40#include "shm.h"
41#include "session.h"
42#include "content.h"
43#include "cache.h"
44#include "ea_store.h"
45#include "ea_restore.h"
46#include "ea_info.h"
47#include "ea_dasm.h"
48
49#include <sys/types.h>
50#include <sys/stat.h>
51#ifdef ZEND_WIN32
52#  include "win32/time.h"
53#  include <time.h>
54#  include <sys/utime.h>
55#else
56#  include <sys/file.h>
57#  include <sys/time.h>
58#  include <utime.h>
59#endif
60#include <fcntl.h>
61
62#ifndef O_BINARY
63#  define O_BINARY 0
64#endif
65
66#include "php.h"
67#include "php_ini.h"
68#include "php_logos.h"
69#include "main/fopen_wrappers.h"
70#include "ext/standard/info.h"
71#include "ext/standard/php_incomplete_class.h"
72#include "ext/standard/md5.h"
73
74#include "SAPI.h"
75
76#define MAX_DUP_STR_LEN 256
77
78/* Globals (different for each process/thread) */
79ZEND_DECLARE_MODULE_GLOBALS(eaccelerator)
80
81/* Globals (common for each process/thread) */
82static long eaccelerator_shm_size = 0;
83long eaccelerator_shm_max = 0;
84static long eaccelerator_shm_ttl = 0;
85static long eaccelerator_shm_prune_period = 0;
86extern long eaccelerator_debug;
87static zend_bool eaccelerator_check_mtime = 1;
88zend_bool eaccelerator_scripts_shm_only = 0;
89
90eaccelerator_mm* eaccelerator_mm_instance = NULL;
91static int eaccelerator_is_zend_extension = 0;
92static int eaccelerator_is_extension      = 0;
93zend_extension* ZendOptimizer = NULL;
94
95static HashTable eaccelerator_global_function_table;
96static HashTable eaccelerator_global_class_table;
97
98int binary_eaccelerator_version;
99int binary_php_version;
100int binary_zend_version;
101
102#ifdef ZEND_ENGINE_2
103/* pointer to the properties_info hashtable destructor */
104extern dtor_func_t properties_info_dtor;
105#endif
106
107/* saved original functions */
108static zend_op_array *(*mm_saved_zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
109
110#ifdef DEBUG
111static void (*mm_saved_zend_execute)(zend_op_array *op_array TSRMLS_DC);
112#endif
113
114/* external declarations */
115PHPAPI void php_stripslashes(char *str, int *len TSRMLS_DC);
116
117ZEND_DLEXPORT zend_op_array* eaccelerator_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC);
118
119/******************************************************************************/
120/* hash mm functions                                                          */
121/******************************************************************************/
122
123inline unsigned int hash_mm(const char *data, int len) {
124  unsigned int h;
125  const char *e = data + len;
126  for (h = 2166136261U; data < e; ) {
127    h *= 16777619;
128    h ^= *data++;
129  }
130  return h;
131}
132
133/* Find a script entry with the given hash key */
134static mm_cache_entry* hash_find_mm(const char  *key,
135                                    struct stat *buf,
136                                    int         *nreloads,
137                                    time_t      ttl) {
138  unsigned int hv, slot;
139  mm_cache_entry *p, *q;
140
141#ifdef EACCELERATOR_USE_INODE
142  hv = buf->st_dev + buf->st_ino;
143#else
144  hv = hash_mm(key, strlen(key));
145#endif
146  slot = hv & EA_HASH_MAX;
147
148  EACCELERATOR_LOCK_RW();
149  q = NULL;
150  p = eaccelerator_mm_instance->hash[slot];
151  while (p != NULL) {
152#ifdef EACCELERATOR_USE_INODE
153    if (p->st_dev == buf->st_dev && p->st_ino == buf->st_ino) {
154      struct stat buf2;
155      if ((eaccelerator_check_mtime &&
156          (buf->st_mtime != p->mtime || buf->st_size != p->filesize)) ||
157          (strcmp(p->realfilename, key) != 0 &&
158           (stat(p->realfilename,&buf2) != 0 ||
159           buf2.st_dev != buf->st_dev ||
160           buf2.st_ino != buf->st_ino))) {
161#else
162    if ((p->hv == hv) && (strcmp(p->realfilename, key) == 0)) {
163      if (eaccelerator_check_mtime &&
164          (buf->st_mtime != p->mtime || buf->st_size != p->filesize)) {
165#endif
166        /* key is invalid. Remove it. */
167        *nreloads = p->nreloads+1;
168        if (q == NULL) {
169          eaccelerator_mm_instance->hash[slot] = p->next;
170        } else {
171          q->next = p->next;
172        }
173        eaccelerator_mm_instance->hash_cnt--;
174        if (p->use_cnt > 0) {
175          /* key is used by other process/thred. Shedule it to remove */
176          p->removed = 1;
177          p->next = eaccelerator_mm_instance->removed;
178          eaccelerator_mm_instance->removed = p;
179          eaccelerator_mm_instance->rem_cnt++;
180          EACCELERATOR_UNLOCK_RW();
181          return NULL;
182        } else {
183          /* key is unused. Remove it. */
184          eaccelerator_free_nolock(p);
185          EACCELERATOR_UNLOCK_RW();
186          return NULL;
187        }
188      } else {
189        /* key is valid */
190        p->nhits++;
191        p->use_cnt++;
192        p->ttl = ttl;
193        EACCELERATOR_UNLOCK_RW();
194        return p;
195      }
196    }
197    q = p;
198    p = p->next;
199  }
200  EACCELERATOR_UNLOCK_RW();
201  return NULL;
202}
203
204/* Add a new entry to the hashtable */
205static void hash_add_mm(mm_cache_entry *x) {
206  mm_cache_entry *p,*q;
207  unsigned int slot;
208#ifdef EACCELERATOR_USE_INODE
209  slot = (x->st_dev + x->st_ino) & EA_HASH_MAX;
210#else
211  x->hv = hash_mm(x->realfilename, strlen(x->realfilename));
212  slot = x->hv & EA_HASH_MAX;
213#endif
214
215  EACCELERATOR_LOCK_RW();
216  x->next = eaccelerator_mm_instance->hash[slot];
217  eaccelerator_mm_instance->hash[slot] = x;
218  eaccelerator_mm_instance->hash_cnt++;
219  q = x;
220  p = x->next;
221  while (p != NULL) {
222#ifdef EACCELERATOR_USE_INODE
223    if ((p->st_dev == x->st_dev) && (p->st_ino == x->st_ino)) {
224#else
225    if ((p->hv == x->hv) &&
226        (strcmp(p->realfilename, x->realfilename) == 0)) {
227#endif
228      q->next = p->next;
229      eaccelerator_mm_instance->hash_cnt--;
230      eaccelerator_mm_instance->hash[slot]->nreloads += p->nreloads;
231      if (p->use_cnt > 0) {
232        /* key is used by other process/thred. Shedule it to remove */
233        p->removed = 1;
234        p->next = eaccelerator_mm_instance->removed;
235        eaccelerator_mm_instance->removed = p;
236        eaccelerator_mm_instance->rem_cnt++;
237        EACCELERATOR_UNLOCK_RW();
238        return;
239      } else {
240        /* key is unused. Remove it. */
241        eaccelerator_free_nolock(p);
242        EACCELERATOR_UNLOCK_RW();
243        return;
244      }
245    }
246    q = p;
247    p = p->next;
248  }
249  EACCELERATOR_UNLOCK_RW();
250}
251
252/* Initialise the shared memory */
253static int init_mm(TSRMLS_D) {
254  pid_t  owner = getpid();
255  MM     *mm;
256  size_t total;
257  char   mm_path[MAXPATHLEN];
258
259/*  if (getppid() != 1) return SUCCESS; */ /*???*/
260#ifdef ZEND_WIN32
261    snprintf(mm_path, MAXPATHLEN, "%s.%s", EACCELERATOR_MM_FILE, sapi_module.name);
262#else
263    snprintf(mm_path, MAXPATHLEN, "%s.%s%d", EACCELERATOR_MM_FILE, sapi_module.name, getpid());
264#endif
265/*  snprintf(mm_path, MAXPATHLEN, "%s.%s%d", EACCELERATOR_MM_FILE, sapi_module.name, geteuid());*/
266  if ((eaccelerator_mm_instance = (eaccelerator_mm*)mm_attach(eaccelerator_shm_size*1024*1024, mm_path)) != NULL) {
267#ifdef ZTS
268    ea_mutex = tsrm_mutex_alloc();
269#endif
270    return SUCCESS;
271  }
272  mm = mm_create(eaccelerator_shm_size*1024*1024, mm_path);
273  if (!mm) {
274    return FAILURE;
275  }
276#ifdef ZEND_WIN32
277  DBG(ea_debug_printf, (EA_DEBUG, "init_mm [%d]\n", getpid()));
278#else
279  DBG(ea_debug_printf, (EA_DEBUG, "init_mm [%d,%d]\n", getpid(), getppid()));
280#endif
281#ifdef ZTS
282  ea_mutex = tsrm_mutex_alloc();
283#endif
284  total = mm_available(mm);
285  eaccelerator_mm_instance = mm_malloc_lock(mm, sizeof(*eaccelerator_mm_instance));
286  if (!eaccelerator_mm_instance) {
287    return FAILURE;
288  }
289  mm_set_attach(mm, eaccelerator_mm_instance);
290  memset(eaccelerator_mm_instance, 0, sizeof(*eaccelerator_mm_instance));
291  eaccelerator_mm_instance->owner = owner;
292  eaccelerator_mm_instance->mm    = mm;
293  eaccelerator_mm_instance->total = total;
294  eaccelerator_mm_instance->hash_cnt = 0;
295  eaccelerator_mm_instance->rem_cnt  = 0;
296  eaccelerator_mm_instance->enabled = 1;
297  eaccelerator_mm_instance->optimizer_enabled = 1;
298  eaccelerator_mm_instance->removed = NULL;
299  eaccelerator_mm_instance->locks = NULL;
300  eaccelerator_mm_instance->user_hash_cnt = 0;
301  eaccelerator_mm_instance->last_prune = time(0);
302  EACCELERATOR_PROTECT();
303  return SUCCESS;
304}
305
306/* Clean up the shared memory */
307static void shutdown_mm(TSRMLS_D) {
308  if (eaccelerator_mm_instance) {
309#ifdef ZEND_WIN32
310    if (eaccelerator_mm_instance->owner == getpid()) {
311#else
312    if (getpgrp() == getpid()) {
313#endif
314      MM *mm = eaccelerator_mm_instance->mm;
315#ifdef ZEND_WIN32
316      DBG(ea_debug_printf, (EA_DEBUG, "shutdown_mm [%d]\n", getpid()));
317#else
318      DBG(ea_debug_printf, (EA_DEBUG, "shutdown_mm [%d,%d]\n", getpid(), getppid()));
319#endif
320#ifdef ZTS
321      tsrm_mutex_free(ea_mutex);
322#endif
323      if (mm) {
324        mm_destroy(mm);
325      }
326      eaccelerator_mm_instance = NULL;
327    }
328  }
329}
330
331
332static int encode_version(const char *s) {
333  unsigned int v1 = 0;
334  unsigned int v2 = 0;
335  unsigned int v3 = 0;
336  unsigned int c;
337  char m = '.';
338  sscanf(s, "%u.%u%c%u",&v1,&v2,&m,&v3);
339  switch (m) {
340    case  'a': c = 0; break;
341    case  'b': c = 1; break;
342    case  '.': c = 2; break;
343    case  's': c = 15; break;
344    default: c = 2;
345  }
346  return ((v1 & 0xf) << 20) |
347         ((v2 & 0xff) << 12) |
348         ((c & 0xf) << 8) |
349         (v3 & 0xff);
350}
351
352/* This function isn't used. So disable it for now
353static void decode_version(char *version, int v) {
354  int t = (v & 0x000f00) >> 8;
355  char c;
356  switch (t) {
357    case  0: c = 'a'; break;
358    case  1: c = 'b'; break;
359    case  2: c = '.'; break;
360    case 15: c = 's'; break;
361    default: c = '.';
362  }
363  snprintf(version, 16, "%d.%d%c%d", (v & 0xf00000) >> 20,
364                                     (v & 0x0ff000) >> 12,
365                                     c,
366                                     (v & 0x0000ff));
367}
368*/
369
370static char num2hex[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
371
372#ifdef EACCELERATOR_USE_INODE
373static int eaccelerator_inode_key(char* s, dev_t dev, ino_t ino TSRMLS_DC) {
374  int n, i;
375  snprintf(s, MAXPATHLEN-1, "%s/", EAG(cache_dir));
376  n = strlen(s);
377  for (i = 1; i <= EACCELERATOR_HASH_LEVEL && n < MAXPATHLEN - 1; i++) {
378    s[n++] = num2hex[(ino >> (i*4)) & 0xf];
379    s[n++] = '/';
380  }
381  s[n] = 0;
382  strlcat(s, "eaccelerator-", MAXPATHLEN-1);
383  n += sizeof("eaccelerator-") - 1;
384  while (dev > 0) {
385    if (n >= MAXPATHLEN) return 0;
386    s[n++] = (dev % 10) +'0';
387    dev /= 10;
388  }
389  if (n >= MAXPATHLEN) return 0;
390  s[n++] = '.';
391  while (ino > 0) {
392    if (n >= MAXPATHLEN) return 0;
393    s[n++] = (ino % 10) +'0';
394    ino /= 10;
395  }
396  if (n >= MAXPATHLEN) return 0;
397  s[n++] = '\000';
398  return 1;
399}
400#endif
401
402/* Function to create a hash key when filenames are used */
403int eaccelerator_md5(char* s, const char* prefix, const char* key TSRMLS_DC) {
404#if defined(PHP_MAJOR_VERSION) && defined(PHP_MINOR_VERSION) && \
405    ((PHP_MAJOR_VERSION > 4) || (PHP_MAJOR_VERSION == 4 && PHP_MINOR_VERSION > 1))
406  char md5str[33];
407  PHP_MD5_CTX context;
408  unsigned char digest[16];
409  int i;
410  int n;
411
412  md5str[0] = '\0';
413  PHP_MD5Init(&context);
414  PHP_MD5Update(&context, (unsigned char*)key, strlen(key));
415  PHP_MD5Final(digest, &context);
416  make_digest(md5str, digest);
417  snprintf(s, MAXPATHLEN-1, "%s/", EAG(cache_dir));
418  n = strlen(s);
419  for (i = 0; i < EACCELERATOR_HASH_LEVEL && n < MAXPATHLEN - 1; i++) {
420    s[n++] = md5str[i];
421    s[n++] = '/';
422  }
423  s[n] = 0;
424  snprintf(s, MAXPATHLEN-1, "%s%s%s", s, prefix, md5str);
425  return 1;
426#else
427  zval retval;
428  zval md5;
429  zval param;
430  zval *params[1];
431
432  ZVAL_STRING(&md5, "md5", 0);
433  INIT_ZVAL(param);
434  params[0] = &param;
435  ZVAL_STRING(params[0], (char*)key, 0);
436  if (call_user_function(CG(function_table), (zval**)NULL, &md5, &retval, 1, params TSRMLS_CC) == SUCCESS &&
437      Z_TYPE(retval) == IS_STRING && Z_STRLEN(retval) == 32) {
438    strncpy(s, EAG(cache_dir), MAXPATHLEN-1);
439    strlcat(s, prefix, MAXPATHLEN);
440    strlcat(s, Z_STRVAL(retval), MAXPATHLEN);
441    zval_dtor(&retval);
442    return 1;
443  }
444  s[0] ='\0';
445#endif
446  return 0;
447}
448
449/* Remove expired keys, content and scripts from the cache */
450void eaccelerator_prune(time_t t) {
451  unsigned int i;
452
453  EACCELERATOR_LOCK_RW();
454  eaccelerator_mm_instance->last_prune = t;
455  for (i = 0; i < EA_HASH_SIZE; i++) {
456    mm_cache_entry **p = &eaccelerator_mm_instance->hash[i];
457    while (*p != NULL) {
458      struct stat buf;
459      if (((*p)->ttl != 0 && (*p)->ttl < t && (*p)->use_cnt <= 0) ||
460          stat((*p)->realfilename,&buf) != 0 ||
461#ifdef EACCELERATOR_USE_INODE
462          (*p)->st_dev != buf.st_dev ||
463          (*p)->st_ino != buf.st_ino ||
464#endif
465          (*p)->mtime != buf.st_mtime ||
466          (*p)->filesize != buf.st_size) {
467        mm_cache_entry *r = *p;
468        *p = (*p)->next;
469        eaccelerator_mm_instance->hash_cnt--;
470        eaccelerator_free_nolock(r);
471      } else {
472        p = &(*p)->next;
473      }
474    }
475  }
476  EACCELERATOR_UNLOCK_RW();
477}
478
479/* Allocate a new cache chunk */
480void* eaccelerator_malloc2(size_t size TSRMLS_DC) {
481  void *p = NULL;
482  time_t t;
483
484  if (eaccelerator_gc(TSRMLS_C) > 0) {
485    p = eaccelerator_malloc(size);
486    if (p != NULL) {
487      return p;
488    }
489  }
490  if (eaccelerator_shm_prune_period > 0) {
491    t = time(0);
492    if (t - eaccelerator_mm_instance->last_prune > eaccelerator_shm_prune_period) {
493      eaccelerator_prune(t);
494      p = eaccelerator_malloc(size);
495    }
496  }
497  return p;
498}
499
500#define EACCELERATOR_CRC32(crc, ch)   (crc = (crc >> 8) ^ crc32tab[(crc ^ (ch)) & 0xff])
501
502static const unsigned int crc32tab[256] = {
503  0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
504  0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
505  0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
506  0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
507  0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
508  0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
509  0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
510  0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
511  0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
512  0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
513  0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
514  0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
515  0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
516  0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
517  0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
518  0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
519  0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
520  0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
521  0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
522  0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
523  0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
524  0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
525  0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
526  0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
527  0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
528  0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
529  0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
530  0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
531  0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
532  0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
533  0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
534  0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
535  0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
536  0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
537  0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
538  0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
539  0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
540  0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
541  0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
542  0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
543  0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
544  0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
545  0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
546  0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
547  0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
548  0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
549  0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
550  0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
551  0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
552  0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
553  0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
554  0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
555  0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
556  0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
557  0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
558  0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
559  0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
560  0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
561  0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
562  0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
563  0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
564  0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
565  0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
566  0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
567};
568
569unsigned int eaccelerator_crc32(const char *p, size_t n) {
570  unsigned int crc = ~0;
571  for (; n--; ++p) {
572    EACCELERATOR_CRC32(crc, *p);
573  }
574  return ~crc;
575}
576
577void eaccelerator_fixup (mm_cache_entry * p TSRMLS_DC)
578{
579  mm_fc_entry *q;
580
581  EAG (mem) = (char *) ((long) p - (long) p->next);
582  EAG (compress) = 1;
583  p->next = NULL;
584  FIXUP (p->op_array);
585  FIXUP (p->f_head);
586  FIXUP (p->c_head);
587  fixup_op_array (p->op_array TSRMLS_CC);
588  q = p->f_head;
589  while (q != NULL) {
590    FIXUP (q->fc);
591    fixup_op_array ((eaccelerator_op_array *) q->fc TSRMLS_CC);
592    FIXUP (q->next);
593    q = q->next;
594  }
595  q = p->c_head;
596  while (q != NULL) {
597    FIXUP (q->fc);
598    fixup_class_entry ((eaccelerator_class_entry *) q->fc TSRMLS_CC);
599    FIXUP (q->next);
600    q = q->next;
601  }
602}
603
604/******************************************************************************/
605/* Cache file functions.                                                                                                                */
606/******************************************************************************/
607
608/* Retrieve a cache entry from the cache directory */
609static mm_cache_entry* hash_find_file(const char  *key,
610                                      struct stat *buf TSRMLS_DC) {
611  int f;
612  char s[MAXPATHLEN];
613  mm_file_header hdr;
614  mm_cache_entry *p;
615  int use_shm = 1;
616
617#ifdef EACCELERATOR_USE_INODE
618  struct stat buf2;
619
620  if (!eaccelerator_inode_key(s, buf->st_dev, buf->st_ino TSRMLS_CC)) {
621    return NULL;
622  }
623#else
624  if (!eaccelerator_md5(s, "/eaccelerator-", key TSRMLS_CC)) {
625    return NULL;
626  }
627#endif
628
629  if ((f = open(s, O_RDONLY | O_BINARY)) > 0) {
630    EACCELERATOR_FLOCK(f, LOCK_SH);
631    if (read(f, &hdr, sizeof(hdr)) != sizeof(hdr)) {
632      EACCELERATOR_FLOCK(f, LOCK_UN);
633      close(f);
634      return NULL;
635    }
636    if (strncmp(hdr.magic, EA_MAGIC, 8) != 0 ||
637        hdr.eaccelerator_version != binary_eaccelerator_version ||
638        hdr.zend_version != binary_zend_version ||
639        hdr.php_version != binary_php_version) {
640      EACCELERATOR_FLOCK(f, LOCK_UN);
641      close(f);
642      unlink(s);
643      return NULL;
644    }
645    p = eaccelerator_malloc(hdr.size);
646    if (p == NULL) {
647      p = eaccelerator_malloc2(hdr.size TSRMLS_CC);
648    }
649    if (p == NULL) {
650      p = emalloc(hdr.size);
651      use_shm = 0;
652    }
653    if (p == NULL) {
654      EACCELERATOR_FLOCK(f, LOCK_UN);
655      close(f);
656      return NULL;
657    }
658    if (read(f, p, hdr.size) != hdr.size ||
659        p->size != hdr.size ||
660        hdr.crc32 != eaccelerator_crc32((const char*)p,p->size)) {
661      EACCELERATOR_FLOCK(f, LOCK_UN);
662      close(f);
663      unlink(s);
664      if (use_shm) eaccelerator_free(p); else efree(p);
665      return NULL;
666    }
667    EACCELERATOR_FLOCK(f, LOCK_UN);
668    close(f);
669#ifdef EACCELERATOR_USE_INODE
670    if (p->st_dev != buf->st_dev || p->st_ino != buf->st_ino) {
671#else
672    if (strcmp(key,p->realfilename) != 0) {
673#endif
674      if (use_shm) eaccelerator_free(p); else efree(p);
675      return NULL;
676    }
677    if ((eaccelerator_check_mtime &&
678        (buf->st_mtime != p->mtime || buf->st_size != p->filesize))
679#ifdef EACCELERATOR_USE_INODE
680        ||
681        (strcmp(p->realfilename, key) != 0 &&
682         (stat(p->realfilename,&buf2) != 0 ||
683         buf2.st_dev != buf->st_dev ||
684         buf2.st_ino != buf->st_ino))
685#endif
686       ) {
687      /* key is invalid. Remove it. */
688      if (use_shm) eaccelerator_free(p); else efree(p);
689      unlink(s);
690      return NULL;
691    }
692    eaccelerator_fixup(p TSRMLS_CC);
693    if (use_shm) {
694      p->nhits    = 1;
695      p->nreloads = 1;
696      p->use_cnt  = 1;
697      p->removed  = 0;
698      if (eaccelerator_shm_ttl > 0) {
699        p->ttl = time(0) + eaccelerator_shm_ttl;
700      } else {
701        p->ttl = 0;
702      }
703      hash_add_mm(p);
704    } else {
705      p->use_cnt  = 0;
706      p->removed  = 1;
707    }
708    return p;
709  }
710  return NULL;
711}
712
713/* Add a cache entry to the cache directory */
714static int hash_add_file(mm_cache_entry *p TSRMLS_DC) {
715  int f;
716  int ret = 0;
717  char s[MAXPATHLEN];
718  mm_file_header hdr;
719
720#ifdef EACCELERATOR_USE_INODE
721  if (!eaccelerator_inode_key(s, p->st_dev, p->st_ino TSRMLS_CC)) {
722    return 0;
723  }
724#else
725  if (!eaccelerator_md5(s, "/eaccelerator-", p->realfilename TSRMLS_CC)) {
726    return 0;
727  }
728#endif
729
730  unlink(s);
731  f = open(s, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, S_IRUSR | S_IWUSR);
732  if (f > 0) {
733    EACCELERATOR_FLOCK(f, LOCK_EX);
734    strncpy(hdr.magic, EA_MAGIC, 8);
735    hdr.eaccelerator_version = binary_eaccelerator_version;
736    hdr.zend_version    = binary_zend_version;
737    hdr.php_version     = binary_php_version;
738    hdr.size  = p->size;
739    hdr.mtime = p->mtime;
740    p->next = p;
741    hdr.crc32 = eaccelerator_crc32((const char*)p,p->size);
742    ret = (write(f, &hdr, sizeof(hdr)) == sizeof(hdr));
743    if (ret) ret = (write(f, p, p->size) == p->size);
744    EACCELERATOR_FLOCK(f, LOCK_UN);
745    close(f);
746  } else {
747    ea_debug_log("EACCELERATOR: Open for write failed for \"%s\": %s\n", s, strerror(errno));
748  }
749  return ret;
750}
751
752/* Create a cache entry from the given op_array, functions and classes of a
753   script */
754static mm_cache_entry *eaccelerator_store_int (char *key, int len,
755        zend_op_array * op_array, Bucket * f, Bucket * c TSRMLS_DC)
756{
757  mm_cache_entry *p;
758  mm_fc_entry *fc;
759  mm_fc_entry *q;
760  char *x;
761
762  DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
763  DBG(ea_debug_printf, (EA_DEBUG, "[%d] eaccelerator_store_int: key='%s'\n",
764          getpid (), key));
765
766  EAG (compress) = 1;
767  zend_hash_init (&EAG (strings), 0, NULL, NULL, 0);
768  p = (mm_cache_entry *) EAG (mem);
769  EAG (mem) += offsetof (mm_cache_entry, realfilename) + len + 1;
770
771  p->nhits = 0;
772  p->use_cnt = 0;
773  p->removed = 0;
774  p->f_head = NULL;
775  p->c_head = NULL;
776  memcpy (p->realfilename, key, len + 1);
777  x = p->realfilename;
778  zend_hash_add (&EAG (strings), key, len + 1, &x, sizeof (char *), NULL);
779
780  q = NULL;
781  while (c != NULL) {
782    DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
783    DBG(ea_debug_printf, (EA_DEBUG,
784            "[%d] eaccelerator_store_int:     class hashkey=", getpid ()));
785    DBG(ea_debug_binary_print, (EA_DEBUG, c->arKey, c->nKeyLength));
786
787    EACCELERATOR_ALIGN (EAG (mem));
788    fc = (mm_fc_entry *) EAG (mem);
789    EAG (mem) += offsetof (mm_fc_entry, htabkey) + c->nKeyLength;
790    memcpy (fc->htabkey, c->arKey, c->nKeyLength);
791    fc->htablen = c->nKeyLength;
792    fc->next = NULL;
793#ifdef ZEND_ENGINE_2
794    fc->fc = *(zend_class_entry **) c->pData;
795#else
796    fc->fc = c->pData;
797#endif
798    c = c->pListNext;
799    x = fc->htabkey;
800    zend_hash_add (&EAG (strings), fc->htabkey, fc->htablen, &x,
801            sizeof (char *), NULL);
802    if (q == NULL) {
803      p->c_head = fc;
804    } else {
805      q->next = fc;
806    }
807    q = fc;
808  }
809
810  q = NULL;
811  while (f != NULL) {
812      DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
813      DBG(ea_debug_printf, (EA_DEBUG,
814              "[%d] eaccelerator_store_int:     function hashkey='%s'\n", getpid (), f->arKey));
815
816      EACCELERATOR_ALIGN (EAG (mem));
817      fc = (mm_fc_entry *) EAG (mem);
818      EAG (mem) += offsetof (mm_fc_entry, htabkey) + f->nKeyLength;
819      memcpy (fc->htabkey, f->arKey, f->nKeyLength);
820      fc->htablen = f->nKeyLength;
821      fc->next = NULL;
822      fc->fc = f->pData;
823      f = f->pListNext;
824      x = fc->htabkey;
825      zend_hash_add (&EAG (strings), fc->htabkey, fc->htablen, &x,
826              sizeof (char *), NULL);
827      if (q == NULL) {
828          p->f_head = fc;
829      } else {
830          q->next = fc;
831      }
832      q = fc;
833  }
834
835  q = p->c_head;
836  while (q != NULL) {
837      q->fc = store_class_entry ((zend_class_entry *) q->fc TSRMLS_CC);
838      q = q->next;
839  }
840
841  q = p->f_head;
842  while (q != NULL) {
843      q->fc = store_op_array ((zend_op_array *) q->fc TSRMLS_CC);
844      q = q->next;
845  }
846  p->op_array = store_op_array (op_array TSRMLS_CC);
847
848  zend_hash_destroy (&EAG (strings));
849  return p;
850}
851
852/* called after succesful compilation, from eaccelerator_compile file */
853/* Adds the data from the compilation of the script to the cache */
854static int eaccelerator_store(char* key, struct stat *buf, int nreloads,
855                         zend_op_array* op_array,
856                         Bucket* f, Bucket *c TSRMLS_DC) {
857  mm_cache_entry *p;
858  int len = strlen(key);
859  int use_shm = 1;
860  int ret = 0;
861  int size = 0;
862
863  zend_try {
864    size = calc_size(key, op_array, f, c TSRMLS_CC);
865  } zend_catch {
866    size =  0;
867  } zend_end_try();
868  if (size == 0) {
869    return 0;
870  }
871  DBG(ea_debug_printf, (EA_DEBUG, "[%d] eaccelerator_store: calc_size returned %d, mm=%x", getpid(), size, eaccelerator_mm_instance->mm));
872  EACCELERATOR_UNPROTECT();
873  EAG(mem) = eaccelerator_malloc(size);
874  if (EAG(mem) == NULL) {
875    EAG(mem) = eaccelerator_malloc2(size TSRMLS_CC);
876  }
877  if (!EAG(mem) && !eaccelerator_scripts_shm_only) {
878    EACCELERATOR_PROTECT();
879    EAG(mem) = emalloc(size);
880    use_shm = 0;
881  }
882  if (EAG(mem)) {
883    memset(EAG(mem), 0, size);
884    p = eaccelerator_store_int(key, len, op_array, f, c TSRMLS_CC);
885    p->mtime    = buf->st_mtime;
886    p->filesize = buf->st_size;
887    p->size     = size;
888    p->nreloads = nreloads;
889#ifdef EACCELERATOR_USE_INODE
890    p->st_dev   = buf->st_dev;
891    p->st_ino   = buf->st_ino;
892#endif
893    if (use_shm) {
894      if (eaccelerator_shm_ttl > 0) {
895        p->ttl = time(0) + eaccelerator_shm_ttl;
896      } else {
897        p->ttl = 0;
898      }
899      if (!eaccelerator_scripts_shm_only) {
900        hash_add_file(p TSRMLS_CC);
901      }
902      hash_add_mm(p);
903      EACCELERATOR_PROTECT();
904      ret = 1;
905    } else {
906      ret =  hash_add_file(p TSRMLS_CC);
907      efree(p);
908    }
909  }
910  return ret;
911}
912
913/* Try to restore a file from the cache. If the file isn't found in memory, the
914   the disk cache is checked */
915static zend_op_array* eaccelerator_restore(char *realname, struct stat *buf,
916                                      int *nreloads, time_t compile_time TSRMLS_DC) {
917  mm_cache_entry *p;
918  zend_op_array *op_array = NULL;
919
920  *nreloads = 1;
921  EACCELERATOR_UNPROTECT();
922  p = hash_find_mm(realname, buf, nreloads, ((eaccelerator_shm_ttl > 0)?(compile_time + eaccelerator_shm_ttl):0));
923  if (p == NULL && !eaccelerator_scripts_shm_only) {
924    p = hash_find_file(realname, buf TSRMLS_CC);
925  }
926  EACCELERATOR_PROTECT();
927  if (p != NULL && p->op_array != NULL) {
928    EAG(class_entry) = NULL;
929    op_array = restore_op_array(NULL, p->op_array TSRMLS_CC);
930    if (op_array != NULL) {
931      mm_fc_entry *e;
932      mm_used_entry *used = emalloc(sizeof(mm_used_entry));
933      used->entry  = p;
934      used->next   = (mm_used_entry*)EAG(used_entries);
935      EAG(used_entries) = (void*)used;
936      EAG(mem) = op_array->filename;
937            /* only restore the classes and functions when we restore this script
938             * for the first time.
939             */
940      if (!zend_hash_exists(&EAG(restored), p->realfilename, strlen(p->realfilename))) {
941              for (e = p->c_head; e!=NULL; e = e->next) {
942          restore_class(e TSRMLS_CC);
943        }
944        for (e = p->f_head; e!=NULL; e = e->next) {
945          restore_function(e TSRMLS_CC);
946        }
947                    zend_hash_add(&EAG(restored), p->realfilename, strlen(p->realfilename), NULL, 0, NULL); 
948            }
949            EAG(mem) = p->realfilename;
950    }
951  }
952  return op_array;
953}
954
955/*
956 * Only files matching user specified conditions should be cached.
957 *
958 * TODO - check the algorithm (fl)
959 */
960static int match(const char* name, const char* pat) {
961  char p,k;
962  int ok, neg;
963 
964  while (1) {
965    p = *pat++;
966    if (p == '\0') {
967      return (*name == '\0');
968    } else if (p == '*') {
969      if (*pat == '\0') {
970        return 1;
971      }
972      do {
973        if (match(name, pat)) {
974          return 1;
975        }
976      } while (*name++ != '\0');
977      return 0;
978    } else if (p == '?') {
979      if (*name++ == '\0') {
980        return 0;
981      }
982    } else if (p == '[') {
983      ok = 0;
984      if ((k = *name++) == '\0') {
985        return 0;
986      }
987      if ((neg = (*pat == '!')) != '\0') {
988        ++pat;
989      }
990      while ((p = *pat++) != ']') {
991        if (*pat == '-') {
992          if (p <= k && k <= pat[1]) {
993            ok = 1;
994          }
995          pat += 2;
996        } else {
997          if (p == '\\') {
998            p = *pat++;
999            if (p == '\0') {
1000              p ='\\';
1001              pat--;
1002            }
1003          }
1004          if (p == k) {
1005            ok = 1;
1006          }
1007        }
1008      }
1009      if (ok == neg) {
1010        return 0;
1011      }
1012    } else {
1013      if (p == '\\') {
1014        p = *pat++;
1015        if (p == '\0') {
1016          p ='\\';
1017          pat--;
1018        }
1019      }
1020      if (*name++ != p) {
1021        return 0;
1022      }
1023    }
1024  }
1025  return (*name == '\0');
1026}
1027
1028/* Check if the file is ok to cache */
1029static int eaccelerator_ok_to_cache(char *realname TSRMLS_DC) {
1030  mm_cond_entry *p;
1031  int ok;
1032  if (EAG(cond_list) == NULL) {
1033    return 1;
1034  }
1035
1036  /* if "realname" matches to any pattern started with "!" then ignore it */
1037  for (p = EAG(cond_list); p != NULL; p = p->next) {
1038    if (p->not && match(realname, p->str)) {
1039      return 0;
1040    }
1041  }
1042
1043  /* else if it matches to any pattern not started with "!" then accept it */
1044  ok = 1;
1045  for (p = EAG(cond_list); p != NULL; p = p->next) {
1046    if (!p->not) {
1047      ok = 0;
1048      if (match(realname, p->str)) {
1049        return 1;
1050      }
1051    }
1052  }
1053  return ok;
1054}
1055
1056#ifndef EACCELERATOR_USE_INODE
1057static char* eaccelerator_realpath(const char* name, char* realname TSRMLS_DC) {
1058/* ???TODO it is possibe to cache name->realname mapping to avoid lstat() calls */
1059#if ZEND_MODULE_API_NO >= 20001222
1060  return VCWD_REALPATH(name, realname);
1061#else
1062  return V_REALPATH(name, realname);
1063#endif
1064}
1065#endif
1066
1067static int eaccelerator_stat(zend_file_handle *file_handle,
1068                        char* realname, struct stat* buf TSRMLS_DC) {
1069#ifdef EACCELERATOR_USE_INODE
1070#ifndef ZEND_WIN32
1071  if (file_handle->type == ZEND_HANDLE_FP && file_handle->handle.fp != NULL) {
1072    if (fstat(fileno(file_handle->handle.fp), buf) == 0 &&
1073       S_ISREG(buf->st_mode)) {
1074      if (file_handle->opened_path != NULL) {
1075        strcpy(realname,file_handle->opened_path);
1076      }
1077      return 0;
1078    }
1079  } else
1080#endif
1081  if (file_handle->opened_path != NULL) {
1082    if (stat(file_handle->opened_path, buf) == 0 &&
1083        S_ISREG(buf->st_mode)) {
1084       strcpy(realname,file_handle->opened_path);
1085       return 0;
1086    }
1087  } else if (PG(include_path) == NULL ||
1088             file_handle->filename[0] == '.' ||
1089             IS_SLASH(file_handle->filename[0]) ||
1090             IS_ABSOLUTE_PATH(file_handle->filename,strlen(file_handle->filename))) {
1091    if (stat(file_handle->filename, buf) == 0 &&
1092        S_ISREG(buf->st_mode)) {
1093       return 0;
1094    }
1095  } else {
1096    char* ptr = PG(include_path);
1097    char* end;
1098    int   len;
1099    char  tryname[MAXPATHLEN];
1100    int   filename_len = strlen(file_handle->filename);
1101
1102    while (ptr && *ptr) {
1103      end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
1104      if (end != NULL) {
1105        len = end-ptr;
1106        end++;
1107      } else {
1108        len = strlen(ptr);
1109        end = ptr+len;
1110      }
1111      if (len+filename_len+2 < MAXPATHLEN) {
1112        memcpy(tryname, ptr, len);
1113        tryname[len] = '/';
1114        memcpy(tryname+len+1, file_handle->filename, filename_len);
1115        tryname[len+filename_len+1] = '\0';
1116        if (stat(tryname, buf) == 0 &&
1117            S_ISREG(buf->st_mode)) {
1118          return 0;
1119        }
1120      }
1121      ptr = end;
1122    }
1123
1124        if (zend_is_executing(TSRMLS_C)) {
1125        int tryname_length;
1126                strncpy(tryname, zend_get_executed_filename(TSRMLS_C), MAXPATHLEN);
1127                tryname[MAXPATHLEN - 1] = 0;
1128                tryname_length = strlen(tryname);
1129
1130                while (tryname_length >= 0 && !IS_SLASH(tryname[tryname_length]))
1131                        tryname_length--;
1132                if (tryname_length > 0 && tryname[0] != '[' // [no active file]
1133                        && tryname_length + filename_len + 1 < MAXPATHLEN)
1134                {
1135                        strncpy(tryname + tryname_length + 1, file_handle->filename, filename_len + 1);
1136                        if (stat(tryname, buf) == 0 && S_ISREG(buf->st_mode))
1137                                return 0;
1138                }
1139        }
1140  }
1141  return -1;
1142#else
1143  if (file_handle->opened_path != NULL) {
1144    strcpy(realname,file_handle->opened_path);
1145#ifndef ZEND_WIN32
1146    if (file_handle->type == ZEND_HANDLE_FP && file_handle->handle.fp != NULL) {
1147      if (!eaccelerator_check_mtime) {
1148        return 0;
1149      } else if (fstat(fileno(file_handle->handle.fp), buf) == 0 &&
1150                 S_ISREG(buf->st_mode)) {
1151        return 0;
1152      } else {
1153        return -1;
1154      }
1155    } else {
1156      if (!eaccelerator_check_mtime) {
1157        return 0;
1158      } else if (stat(realname, buf) == 0 &&
1159                 S_ISREG(buf->st_mode)) {
1160        return 0;
1161      } else {
1162        return -1;
1163      }
1164    }
1165#else
1166    if (!eaccelerator_check_mtime) {
1167      return 0;
1168    } else if (stat(realname, buf) == 0 &&
1169               S_ISREG(buf->st_mode)) {
1170      return 0;
1171    } else {
1172      return -1;
1173    }
1174#endif
1175  } else if (file_handle->filename == NULL) {
1176    return -1;
1177  } else if (PG(include_path) == NULL ||
1178             file_handle->filename[0] == '.' ||
1179             IS_SLASH(file_handle->filename[0]) ||
1180             IS_ABSOLUTE_PATH(file_handle->filename,strlen(file_handle->filename))) {
1181    if (eaccelerator_realpath(file_handle->filename, realname TSRMLS_CC)) {
1182      if (!eaccelerator_check_mtime) {
1183        return 0;
1184      } else if (stat(realname, buf) == 0 &&
1185                 S_ISREG(buf->st_mode)) {
1186        return 0;
1187      } else {
1188        return -1;
1189      }
1190    }
1191  } else {
1192    char* ptr = PG(include_path);
1193    char* end;
1194    int   len;
1195    char  tryname[MAXPATHLEN];
1196    int   filename_len = strlen(file_handle->filename);
1197
1198    while (ptr && *ptr) {
1199      end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
1200      if (end != NULL) {
1201        len = end-ptr;
1202        end++;
1203      } else {
1204        len = strlen(ptr);
1205        end = ptr+len;
1206      }
1207      if (len+filename_len+2 < MAXPATHLEN) {
1208        memcpy(tryname, ptr, len);
1209        tryname[len] = '/';
1210        memcpy(tryname+len+1, file_handle->filename, filename_len);
1211        tryname[len+filename_len+1] = '\0';
1212        if (eaccelerator_realpath(tryname, realname TSRMLS_CC)) {
1213#ifdef ZEND_WIN32
1214          if (stat(realname, buf) == 0 &&
1215              S_ISREG(buf->st_mode)) {
1216            return 0;
1217          }
1218#else
1219          if (!eaccelerator_check_mtime) {
1220            return 0;
1221          } else if (stat(realname, buf) == 0 &&
1222                     S_ISREG(buf->st_mode)) {
1223            return 0;
1224          } else {
1225            return -1;
1226          }
1227#endif
1228        }
1229      }
1230      ptr = end;
1231    }
1232  }
1233  return -1;
1234#endif
1235}
1236
1237/*
1238 * Intercept compilation of PHP file.  If we already have the file in
1239 * our cache, restore it.  Otherwise call the original Zend compilation
1240 * function and store the compiled zend_op_array in out cache.
1241 * This function is called again for each PHP file included in the
1242 * main PHP file.
1243 */
1244ZEND_DLEXPORT zend_op_array* eaccelerator_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) {
1245  zend_op_array *t;
1246  struct stat buf;
1247  char  realname[MAXPATHLEN];
1248  int   nreloads;
1249  time_t compile_time;
1250  int stat_result = 0;
1251#ifdef DEBUG
1252  struct timeval tv_start;
1253#endif
1254  int ok_to_cache = 0;
1255
1256#ifdef EACCELERATOR_USE_INODE
1257  realname[0] = '\000';
1258#endif
1259  DBG(ea_debug_start_time, (&tv_start));
1260  DBG(ea_debug_printf, (EA_DEBUG, "[%d] Enter COMPILE\n",getpid()));
1261  DBG(ea_debug_printf, (EA_DEBUG, "[%d] compile_file: \"%s\"\n",getpid(), file_handle->filename));
1262#ifdef DEBUG
1263  EAG(xpad)+=2;
1264#endif
1265
1266  compile_time = time(0);
1267  stat_result = eaccelerator_stat(file_handle, realname, &buf TSRMLS_CC);
1268  if (buf.st_mtime >= compile_time && eaccelerator_debug > 0) {
1269        ea_debug_log("EACCELERATOR: Warning: \"%s\" is cached but it's mtime is in the future.\n", file_handle->filename);
1270  }
1271
1272  ok_to_cache = eaccelerator_ok_to_cache(file_handle->filename TSRMLS_CC);
1273 
1274  // eAccelerator isn't working, so just compile the file
1275  if (!EAG(enabled) || (eaccelerator_mm_instance == NULL) ||
1276      !eaccelerator_mm_instance->enabled || file_handle == NULL ||
1277      file_handle->filename == NULL || stat_result != 0 || !ok_to_cache) {
1278    DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] compile_file: compiling\n", getpid()));
1279    t = mm_saved_zend_compile_file(file_handle, type TSRMLS_CC);
1280    DBG(ea_debug_printf, (EA_TEST_PERFORMANCE, "\t[%d] compile_file: end (%ld)\n", getpid(), ea_debug_elapsed_time(&tv_start)));
1281    DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] compile_file: end\n", getpid()));
1282#ifdef DEBUG
1283    EAG(xpad)-=2;
1284#endif
1285    DBG(ea_debug_printf, (EA_DEBUG, "[%d] Leave COMPILE\n", getpid()));
1286    return t;
1287  }
1288
1289  /* only restore file when open_basedir allows it */
1290  if (php_check_open_basedir(file_handle->filename TSRMLS_CC)) {
1291    zend_error(E_ERROR, "Can't load %s, open_basedir restriction.", file_handle->filename);
1292  }
1293
1294  t = eaccelerator_restore(realname, &buf, &nreloads, compile_time TSRMLS_CC);
1295
1296// segv74: really cheap work around to auto_global problem.
1297//         it makes just in time to every time.
1298#ifdef ZEND_ENGINE_2
1299  zend_is_auto_global("_GET", sizeof("_GET")-1 TSRMLS_CC);
1300  zend_is_auto_global("_POST", sizeof("_POST")-1 TSRMLS_CC);
1301  zend_is_auto_global("_COOKIE", sizeof("_COOKIE")-1 TSRMLS_CC);
1302  zend_is_auto_global("_SERVER", sizeof("_SERVER")-1 TSRMLS_CC);
1303  zend_is_auto_global("_ENV", sizeof("_ENV")-1 TSRMLS_CC);
1304  zend_is_auto_global("_REQUEST", sizeof("_REQUEST")-1 TSRMLS_CC);
1305  zend_is_auto_global("_FILES", sizeof("_FILES")-1 TSRMLS_CC);
1306#endif
1307
1308  if (t != NULL) { // restore from cache
1309#ifdef DEBUG
1310    ea_debug_log("[%d] EACCELERATOR hit: \"%s\"\n", getpid(), t->filename);
1311#else
1312    ea_debug_log("EACCELERATOR hit: \"%s\"\n", t->filename);
1313#endif
1314
1315    zend_llist_add_element(&CG(open_files), file_handle);
1316#ifdef ZEND_ENGINE_2
1317    if (file_handle->opened_path == NULL && file_handle->type != ZEND_HANDLE_STREAM) {
1318      file_handle->handle.stream.handle = (void*)1;
1319      file_handle->opened_path = EAG(mem);
1320#else
1321    if (file_handle->opened_path == NULL && file_handle->type != ZEND_HANDLE_FP) {
1322      int dummy = 1;
1323      file_handle->opened_path = EAG(mem);
1324      zend_hash_add(&EG(included_files), file_handle->opened_path, strlen(file_handle->opened_path)+1, (void *)&dummy, sizeof(int), NULL);
1325      file_handle->handle.fp = NULL;
1326#endif
1327    }
1328    DBG(ea_debug_printf, (EA_TEST_PERFORMANCE, "\t[%d] compile_file: restored (%ld)\n", getpid(), ea_debug_elapsed_time(&tv_start)));
1329    DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] compile_file: restored\n", getpid()));
1330#ifdef DEBUG
1331    EAG(xpad)-=2;
1332#endif
1333    DBG(ea_debug_printf, (EA_DEBUG, "[%d] Leave COMPILE\n", getpid()));
1334    return t;
1335  } else { // not in cache or must be recompiled
1336    Bucket *function_table_tail;
1337    Bucket *class_table_tail;
1338    HashTable* orig_function_table;
1339    HashTable* orig_class_table;
1340    HashTable* orig_eg_class_table = NULL;
1341    HashTable tmp_function_table;
1342    HashTable tmp_class_table;
1343    zend_function tmp_func;
1344    zend_class_entry tmp_class;
1345    int ea_bailout;
1346
1347    DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] compile_file: marking\n", getpid()));
1348    if (CG(class_table) != EG(class_table)) {
1349      DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] oops, CG(class_table)[%08x] != EG(class_table)[%08x]\n",
1350                                                getpid(), CG(class_table), EG(class_table)));
1351      DBG(ea_debug_log_hashkeys, ("CG(class_table)\n", CG(class_table)));
1352      DBG(ea_debug_log_hashkeys, ("EG(class_table)\n", EG(class_table)));
1353    } else {
1354      DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] OKAY. That what I thought, CG(class_table)[%08x] == EG(class_table)[%08x]\n",
1355                                                getpid(), CG(class_table), EG(class_table)));
1356      DBG(ea_debug_log_hashkeys, ("CG(class_table)\n", CG(class_table)));
1357    }
1358
1359    zend_hash_init_ex(&tmp_function_table, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0);
1360    zend_hash_copy(&tmp_function_table, &eaccelerator_global_function_table, NULL, &tmp_func, sizeof(zend_function));
1361    orig_function_table = CG(function_table);
1362    CG(function_table) = &tmp_function_table;
1363
1364    zend_hash_init_ex(&tmp_class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0);
1365    zend_hash_copy(&tmp_class_table, &eaccelerator_global_class_table, NULL, &tmp_class, sizeof(zend_class_entry));
1366
1367    orig_class_table = CG(class_table);;
1368    CG(class_table) = &tmp_class_table;
1369#ifdef ZEND_ENGINE_2
1370    orig_eg_class_table = EG(class_table);;
1371    EG(class_table) = &tmp_class_table;
1372#endif
1373
1374    /* Storing global pre-compiled functions and classes */
1375    function_table_tail = CG(function_table)->pListTail;
1376    class_table_tail = CG(class_table)->pListTail;
1377
1378    DBG(ea_debug_printf, (EA_TEST_PERFORMANCE, "\t[%d] compile_file: compiling (%ld)\n",getpid(),ea_debug_elapsed_time(&tv_start)));
1379    DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] compile_file: compiling tmp_class_table=%d class_table=%d\n",
1380          getpid(), tmp_class_table.nNumOfElements, orig_class_table->nNumOfElements));
1381    if (EAG(optimizer_enabled) && eaccelerator_mm_instance->optimizer_enabled) {
1382      EAG(compiler) = 1;
1383    }
1384
1385    ea_bailout = 0;
1386    zend_try {
1387      t = mm_saved_zend_compile_file(file_handle, type TSRMLS_CC);
1388    } zend_catch {
1389      CG(function_table) = orig_function_table;
1390      CG(class_table) = orig_class_table;
1391#ifdef ZEND_ENGINE_2
1392      EG(class_table) = orig_eg_class_table;
1393#endif
1394      ea_bailout = 1;
1395    } zend_end_try();
1396    if (ea_bailout) {
1397      zend_bailout();
1398    }
1399    DBG(ea_debug_log_hashkeys, ("class_table\n", CG(class_table)));
1400
1401/*???
1402    if (file_handle->opened_path == NULL && t != NULL) {
1403      file_handle->opened_path = t->filename;
1404    }
1405*/
1406    EAG(compiler) = 0;
1407    if (t != NULL && file_handle->opened_path != NULL && (eaccelerator_check_mtime ||
1408         ((stat(file_handle->opened_path, &buf) == 0) && S_ISREG(buf.st_mode)))) {
1409      DBG(ea_debug_printf, (EA_TEST_PERFORMANCE, "\t[%d] compile_file: storing in cache (%ld)\n", getpid(), ea_debug_elapsed_time(&tv_start)));
1410      DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] compile_file: storing in cache\n", getpid()));
1411#ifdef WITH_EACCELERATOR_LOADER
1412      if (t->last >= 3 &&
1413          t->opcodes[0].opcode == ZEND_SEND_VAL &&
1414          t->opcodes[1].opcode == ZEND_DO_FCALL &&
1415          t->opcodes[2].opcode == ZEND_RETURN &&
1416          t->opcodes[1].op1.op_type == IS_CONST &&
1417          t->opcodes[1].op1.u.constant.type == IS_STRING &&
1418          t->opcodes[1].op1.u.constant.value.str.len == sizeof("eaccelerator_load")-1 &&
1419          (memcmp(t->opcodes[1].op1.u.constant.value.str.val, "eaccelerator_load", sizeof("eaccelerator_load")-1) == 0) &&
1420          t->opcodes[0].op1.op_type == IS_CONST &&
1421          t->opcodes[0].op1.u.constant.type == IS_STRING) {
1422        zend_op_array* new_t = NULL;
1423        zend_bool old_in_compilation = CG(in_compilation);
1424        char* old_filename = CG(compiled_filename);
1425        int old_lineno = CG(zend_lineno);
1426
1427        CG(in_compilation) = 1;
1428        zend_set_compiled_filename(t->filename TSRMLS_CC);
1429        CG(zend_lineno) = t->opcodes[1].lineno;
1430
1431        zend_try {
1432          new_t = eaccelerator_load(
1433            t->opcodes[0].op1.u.constant.value.str.val,
1434            t->opcodes[0].op1.u.constant.value.str.len TSRMLS_CC);
1435        } zend_catch {
1436            CG(function_table)  = orig_function_table;
1437            CG(class_table)             = orig_class_table;
1438            ea_bailout                          = 1;
1439        } zend_end_try();
1440        if (ea_bailout) {
1441          zend_bailout ();
1442        }
1443        CG(in_compilation) = old_in_compilation;
1444        CG(compiled_filename) = old_filename;
1445        CG(zend_lineno) = old_lineno;
1446        if (new_t != NULL) {
1447#ifdef ZEND_ENGINE_2
1448          destroy_op_array(t TSRMLS_CC);
1449#else
1450          destroy_op_array(t);
1451#endif
1452          efree(t);
1453          t = new_t;
1454        }
1455      }
1456#endif
1457      function_table_tail = function_table_tail?function_table_tail->pListNext:CG(function_table)->pListHead;
1458      class_table_tail = class_table_tail?class_table_tail->pListNext:CG(class_table)->pListHead;
1459      if (eaccelerator_store(file_handle->opened_path, &buf, nreloads, t, function_table_tail, class_table_tail TSRMLS_CC)) {
1460#ifdef DEBUG
1461        ea_debug_log("[%d] EACCELERATOR %s: \"%s\"\n", getpid(), (nreloads == 1) ? "cached" : "re-cached", file_handle->opened_path);
1462#else
1463        ea_debug_log("EACCELERATOR %s: \"%s\"\n", (nreloads == 1) ? "cached" : "re-cached", file_handle->opened_path);
1464#endif
1465      } else {
1466#ifdef DEBUG
1467        ea_debug_log("[%d] EACCELERATOR can't cache: \"%s\"\n", getpid(), file_handle->opened_path);
1468#else
1469        ea_debug_log("EACCELERATOR can't cache: \"%s\"\n", file_handle->opened_path);
1470#endif
1471      }
1472    } else {
1473      function_table_tail = function_table_tail?function_table_tail->pListNext:CG(function_table)->pListHead;
1474      class_table_tail = class_table_tail?class_table_tail->pListNext:CG(class_table)->pListHead;
1475    }
1476    CG(function_table) = orig_function_table;
1477    CG(class_table) = orig_class_table;
1478#ifdef ZEND_ENGINE_2
1479    EG(class_table) = orig_eg_class_table;
1480    DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] restoring CG(class_table)[%08x] != EG(class_table)[%08x]\n",
1481                getpid(), CG(class_table), EG(class_table)));
1482#endif
1483    while (function_table_tail != NULL) {
1484      zend_op_array *op_array = (zend_op_array*)function_table_tail->pData;
1485      if (op_array->type == ZEND_USER_FUNCTION) {
1486        if (zend_hash_add(CG(function_table), function_table_tail->arKey, function_table_tail->nKeyLength, op_array,
1487                    sizeof(zend_op_array), NULL) == FAILURE && function_table_tail->arKey[0] != '\000') {
1488          CG(in_compilation) = 1;
1489          CG(compiled_filename) = file_handle->opened_path;
1490#ifdef ZEND_ENGINE_2
1491          CG(zend_lineno) = op_array->line_start;
1492#else
1493          CG(zend_lineno) = op_array->opcodes[0].lineno;
1494#endif
1495          zend_error(E_ERROR, "Cannot redeclare %s()", function_table_tail->arKey);
1496        }
1497      }
1498      function_table_tail = function_table_tail->pListNext;
1499    }
1500    while (class_table_tail != NULL) {
1501#ifdef ZEND_ENGINE_2
1502      zend_class_entry **ce = (zend_class_entry**)class_table_tail->pData;
1503      if ((*ce)->type == ZEND_USER_CLASS) {
1504        if (zend_hash_add(CG(class_table), class_table_tail->arKey, class_table_tail->nKeyLength,
1505                    ce, sizeof(zend_class_entry*), NULL) == FAILURE && class_table_tail->arKey[0] != '\000') {
1506          CG(in_compilation) = 1;
1507          CG(compiled_filename) = file_handle->opened_path;
1508          CG(zend_lineno) = (*ce)->line_start;
1509#else
1510      zend_class_entry *ce = (zend_class_entry*)class_table_tail->pData;
1511      if (ce->type == ZEND_USER_CLASS) {
1512        if (ce->parent != NULL) {
1513          if (zend_hash_find(CG(class_table), (void*)ce->parent->name, ce->parent->name_length+1, (void **)&ce->parent) != SUCCESS) {
1514            ce->parent = NULL;
1515          }
1516        }
1517        if (zend_hash_add(CG(class_table), class_table_tail->arKey, class_table_tail->nKeyLength, ce,
1518                    sizeof(zend_class_entry), NULL) == FAILURE && class_table_tail->arKey[0] != '\000') {
1519          CG(in_compilation) = 1;
1520          CG(compiled_filename) = file_handle->opened_path;
1521          CG(zend_lineno) = 0;
1522#endif
1523          zend_error(E_ERROR, "Cannot redeclare class %s", class_table_tail->arKey);
1524        }
1525      }
1526      class_table_tail = class_table_tail->pListNext;
1527    }
1528    tmp_function_table.pDestructor = NULL;
1529    tmp_class_table.pDestructor = NULL;
1530    zend_hash_destroy(&tmp_function_table);
1531    zend_hash_destroy(&tmp_class_table);
1532  }
1533  DBG(ea_debug_printf, (EA_TEST_PERFORMANCE, "\t[%d] compile_file: end (%ld)\n", getpid(), ea_debug_elapsed_time(&tv_start)));
1534  DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] compile_file: end\n", getpid()));
1535#ifdef DEBUG
1536  EAG(xpad)-=2;
1537#endif
1538  DBG(ea_debug_printf, (EA_DEBUG, "[%d] Leave COMPILE\n", getpid()));
1539  return t;
1540}
1541
1542#ifdef DEBUG
1543static void profile_execute(zend_op_array *op_array TSRMLS_DC)
1544{
1545  int i;
1546  struct timeval tv_start;
1547  long usec;
1548
1549  for (i=0;i<EAG(profile_level);i++)
1550    DBG(ea_debug_put, (EA_PROFILE_OPCODES, "  "));
1551  ea_debug_printf(EA_PROFILE_OPCODES, "enter profile_execute: %s:%s\n", op_array->filename, op_array->function_name);
1552  ea_debug_start_time(&tv_start);
1553  EAG(self_time)[EAG(profile_level)] = 0;
1554  EAG(profile_level)++;
1555  ea_debug_printf(EA_PROFILE_OPCODES, "About to enter zend_execute...\n");
1556  mm_saved_zend_execute(op_array TSRMLS_CC);
1557  ea_debug_printf(EA_PROFILE_OPCODES, "Finished zend_execute...\n");
1558  usec = ea_debug_elapsed_time(&tv_start);
1559  EAG(profile_level)--;
1560  if (EAG(profile_level) > 0)
1561    EAG(self_time)[EAG(profile_level)-1] += usec;
1562  for (i=0;i<EAG(profile_level);i++)
1563    DBG(ea_debug_put, (EA_PROFILE_OPCODES, "  "));
1564  ea_debug_printf(EA_PROFILE_OPCODES, "leave profile_execute: %s:%s (%ld,%ld)\n", op_array->filename, op_array->function_name, usec, usec-EAG(self_time)[EAG(profile_level)]);
1565}
1566
1567ZEND_DLEXPORT zend_op_array* profile_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) {
1568  zend_op_array *t;
1569  int i;
1570  struct timeval tv_start;
1571  long usec;
1572
1573  ea_debug_start_time(&tv_start);
1574  EAG(self_time)[EAG(profile_level)] = 0;
1575  t = eaccelerator_compile_file(file_handle, type TSRMLS_CC);
1576  usec = ea_debug_elapsed_time(&tv_start);
1577  if (EAG(profile_level) > 0)
1578    EAG(self_time)[EAG(profile_level)-1] += usec;
1579  for (i=0;i<EAG(profile_level);i++)
1580    DBG(ea_debug_put, (EA_PROFILE_OPCODES, "  "));
1581  ea_debug_printf(EA_DEBUG, "zend_op_array compile: %s (%ld)\n", file_handle->filename, usec);
1582  return t;
1583}
1584
1585#endif  /* DEBUG */
1586
1587/* Format Bytes */
1588void format_size(char* s, unsigned int size, int legend) {
1589  unsigned int i = 0;
1590  unsigned int n = 0;
1591  char ch;
1592  do {
1593    if ((n != 0) && (n % 3 == 0)) {
1594      s[i++] = ',';
1595    }
1596    s[i++] = (char)((int)'0' + (size % 10));
1597    n++;
1598    size = size / 10;
1599  } while (size != 0);
1600  s[i] = '\0';
1601  n = 0; i--;
1602  while (n < i) {
1603    ch = s[n];
1604    s[n] = s[i];
1605    s[i] = ch;
1606    n++, i--;
1607  }
1608  if (legend) {
1609    strcat(s, " Bytes");
1610  }
1611}
1612
1613/* eAccelerator entry for phpinfo() */
1614PHP_MINFO_FUNCTION(eaccelerator) {
1615  char s[32];
1616
1617  php_info_print_table_start();
1618  php_info_print_table_header(2, "eAccelerator support", "enabled");
1619  php_info_print_table_row(2, "Version", EACCELERATOR_VERSION);
1620  php_info_print_table_row(2, "Caching Enabled", (EAG(enabled) && (eaccelerator_mm_instance != NULL) &&
1621              eaccelerator_mm_instance->enabled)?"true":"false");
1622  php_info_print_table_row(2, "Optimizer Enabled", (EAG(optimizer_enabled) &&
1623              (eaccelerator_mm_instance != NULL) && eaccelerator_mm_instance->optimizer_enabled)?"true":"false");
1624  if (eaccelerator_mm_instance != NULL) {
1625    size_t available;
1626    EACCELERATOR_UNPROTECT();
1627    available = mm_available(eaccelerator_mm_instance->mm);
1628    EACCELERATOR_LOCK_RD();
1629    EACCELERATOR_PROTECT();
1630    format_size(s, eaccelerator_mm_instance->total, 1);
1631    php_info_print_table_row(2, "Memory Size", s);
1632    format_size(s, available, 1);
1633    php_info_print_table_row(2, "Memory Available", s);
1634    format_size(s, eaccelerator_mm_instance->total - available, 1);
1635    php_info_print_table_row(2, "Memory Allocated", s);
1636    snprintf(s, 32, "%u", eaccelerator_mm_instance->hash_cnt);
1637    php_info_print_table_row(2, "Cached Scripts", s);
1638    snprintf(s, 32, "%u", eaccelerator_mm_instance->rem_cnt);
1639    php_info_print_table_row(2, "Removed Scripts", s);
1640    snprintf(s, 32, "%u", eaccelerator_mm_instance->user_hash_cnt);
1641    php_info_print_table_row(2, "Cached Keys", s);
1642    EACCELERATOR_UNPROTECT();
1643    EACCELERATOR_UNLOCK_RD();
1644    EACCELERATOR_PROTECT();
1645  }
1646  php_info_print_table_end();
1647
1648  DISPLAY_INI_ENTRIES();
1649}
1650
1651/******************************************************************************/
1652/*
1653 * Begin of dynamic loadable module interfaces.
1654 * There are two interfaces:
1655 *  - standard php module,
1656 *  - zend extension.
1657 */
1658PHP_INI_MH(eaccelerator_filter) {
1659  mm_cond_entry *p, *q;
1660  char *s = new_value;
1661  char *ss;
1662  int  not;
1663  for (p = EAG(cond_list); p != NULL; p = q) {
1664    q = p->next;
1665    if (p->str) {
1666      free(p->str);
1667    }
1668    free(p);
1669  }
1670  EAG(cond_list) = NULL;
1671  while (*s) {
1672    for (; *s == ' ' || *s == '\t'; s++)
1673      ;
1674    if (*s == 0)
1675      break;
1676    if (*s == '!') {
1677      s++;
1678      not = 1;
1679    } else {
1680      not = 0;
1681    }
1682    ss = s;
1683    for (; *s && *s != ' ' && *s != '\t'; s++)
1684      ;
1685    if ((s > ss) && *ss) {
1686      p = (mm_cond_entry *)malloc(sizeof(mm_cond_entry));
1687      if (p == NULL)
1688        break;
1689      p->not = not;
1690      p->len = s-ss;
1691      p->str = malloc(p->len+1);
1692      memcpy(p->str, ss, p->len);
1693      p->str[p->len] = 0;
1694      p->next = EAG(cond_list);
1695      EAG(cond_list) = p;
1696    }
1697  }
1698  return SUCCESS;
1699}
1700
1701static PHP_INI_MH(eaccelerator_OnUpdateLong) {
1702  long *p = (long*)mh_arg1;
1703  *p = zend_atoi(new_value, new_value_length);
1704  return SUCCESS;
1705}
1706
1707static PHP_INI_MH(eaccelerator_OnUpdateBool) {
1708  zend_bool *p = (zend_bool*)mh_arg1;
1709  if (strncasecmp("on", new_value, sizeof("on"))) {
1710    *p = (zend_bool) atoi(new_value);
1711  } else {
1712    *p = (zend_bool) 1;
1713  }
1714  return SUCCESS;
1715}
1716
1717#ifndef ZEND_ENGINE_2
1718#define OnUpdateLong OnUpdateInt
1719#endif
1720
1721PHP_INI_BEGIN()
1722STD_PHP_INI_ENTRY("eaccelerator.enable",         "1", PHP_INI_ALL, OnUpdateBool, enabled, zend_eaccelerator_globals, eaccelerator_globals)
1723STD_PHP_INI_ENTRY("eaccelerator.optimizer",      "1", PHP_INI_ALL, OnUpdateBool, optimizer_enabled, zend_eaccelerator_globals, eaccelerator_globals)
1724STD_PHP_INI_ENTRY("eaccelerator.compress",       "1", PHP_INI_ALL, OnUpdateBool, compression_enabled, zend_eaccelerator_globals, eaccelerator_globals)
1725STD_PHP_INI_ENTRY("eaccelerator.compress_level", "9", PHP_INI_ALL, OnUpdateLong, compress_level, zend_eaccelerator_globals, eaccelerator_globals)                 
1726ZEND_INI_ENTRY1("eaccelerator.shm_size",        "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &eaccelerator_shm_size)
1727ZEND_INI_ENTRY1("eaccelerator.shm_max",         "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &eaccelerator_shm_max)
1728ZEND_INI_ENTRY1("eaccelerator.shm_ttl",         "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &eaccelerator_shm_ttl)
1729ZEND_INI_ENTRY1("eaccelerator.shm_prune_period", "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &eaccelerator_shm_prune_period)
1730ZEND_INI_ENTRY1("eaccelerator.debug",           "1", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &eaccelerator_debug)
1731STD_PHP_INI_ENTRY("eaccelerator.log_file",      "", PHP_INI_SYSTEM, OnUpdateString, eaccelerator_log_file, zend_eaccelerator_globals, eaccelerator_globals)
1732ZEND_INI_ENTRY1("eaccelerator.check_mtime",     "1", PHP_INI_SYSTEM, eaccelerator_OnUpdateBool, &eaccelerator_check_mtime)
1733ZEND_INI_ENTRY1("eaccelerator.shm_only",        "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateBool, &eaccelerator_scripts_shm_only)
1734#ifdef WITH_EACCELERATOR_SHM
1735ZEND_INI_ENTRY("eaccelerator.keys",             "shm_and_disk", PHP_INI_SYSTEM, eaccelerator_OnUpdateKeysCachePlace)
1736#endif
1737#ifdef WITH_EACCELERATOR_SESSIONS
1738ZEND_INI_ENTRY("eaccelerator.sessions",         "shm_and_disk", PHP_INI_SYSTEM, eaccelerator_OnUpdateSessionCachePlace)
1739#endif
1740#ifdef WITH_EACCELERATOR_CONTENT_CACHING
1741ZEND_INI_ENTRY("eaccelerator.content",          "shm_and_disk", PHP_INI_SYSTEM, eaccelerator_OnUpdateContentCachePlace)
1742#endif
1743#ifdef WITH_EACCELERATOR_INFO
1744STD_PHP_INI_ENTRY("eaccelerator.allowed_admin_path",       "", PHP_INI_SYSTEM, OnUpdateString, allowed_admin_path, zend_eaccelerator_globals, eaccelerator_globals)
1745#endif
1746STD_PHP_INI_ENTRY("eaccelerator.cache_dir",      "/tmp/eaccelerator", PHP_INI_SYSTEM, OnUpdateString, cache_dir, zend_eaccelerator_globals, eaccelerator_globals)
1747PHP_INI_ENTRY("eaccelerator.filter",             "",  PHP_INI_ALL, eaccelerator_filter)
1748STD_PHP_INI_ENTRY("eaccelerator.name_space",      "", PHP_INI_SYSTEM, OnUpdateString, name_space, zend_eaccelerator_globals, eaccelerator_globals)
1749PHP_INI_END()
1750
1751static void eaccelerator_clean_request(TSRMLS_D) {
1752  mm_used_entry  *p = (mm_used_entry*)EAG(used_entries);
1753  if (eaccelerator_mm_instance != NULL) {
1754    EACCELERATOR_UNPROTECT();
1755    mm_unlock(eaccelerator_mm_instance->mm);
1756    if (p != NULL || eaccelerator_mm_instance->locks != NULL) {
1757      EACCELERATOR_LOCK_RW();
1758      while (p != NULL) {
1759        p->entry->use_cnt--;
1760        if (p->entry->removed && p->entry->use_cnt <= 0) {
1761          if (eaccelerator_mm_instance->removed == p->entry) {
1762            eaccelerator_mm_instance->removed = p->entry->next;
1763            eaccelerator_mm_instance->rem_cnt--;
1764            eaccelerator_free_nolock(p->entry);
1765            p->entry = NULL;
1766          } else {
1767            mm_cache_entry *q = eaccelerator_mm_instance->removed;
1768            while (q != NULL && q->next != p->entry) {
1769              q = q->next;
1770            }
1771            if (q != NULL) {
1772              q->next = p->entry->next;
1773              eaccelerator_mm_instance->rem_cnt--;
1774              eaccelerator_free_nolock(p->entry);
1775              p->entry = NULL;
1776            }
1777          }
1778        }
1779        p = p->next;
1780      }
1781      if (eaccelerator_mm_instance->locks != NULL) {
1782        pid_t    pid    = getpid();
1783#ifdef ZTS
1784        THREAD_T thread = tsrm_thread_id();
1785#endif
1786        mm_lock_entry** p = &eaccelerator_mm_instance->locks;
1787        while ((*p) != NULL) {
1788#ifdef ZTS
1789          if ((*p)->pid == pid && (*p)->thread == thread) {
1790#else
1791          if ((*p)->pid == pid) {
1792#endif
1793            mm_lock_entry* x = *p;
1794            *p = (*p)->next;
1795            eaccelerator_free_nolock(x);
1796          } else {
1797            p = &(*p)->next;
1798          }
1799        }
1800      }
1801      EACCELERATOR_UNLOCK_RW();
1802    }
1803    EACCELERATOR_PROTECT();
1804    p = (mm_used_entry*)EAG(used_entries);
1805    while (p != NULL) {
1806      mm_used_entry* r = p;
1807      p = p->next;
1808      if (r->entry != NULL && r->entry->use_cnt < 0) {
1809        efree(r->entry);
1810      }
1811      efree(r);
1812    }
1813  }
1814  EAG(used_entries) = NULL;
1815  EAG(in_request) = 0;
1816}
1817
1818#if (__GNUC__ >= 3) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 91))
1819static void __attribute__((destructor)) eaccelerator_clean_shutdown(void)
1820#else
1821void _fini(void)
1822#endif
1823{
1824  if (eaccelerator_mm_instance != NULL) {
1825    TSRMLS_FETCH();
1826    if (EAG(in_request)) {
1827      fflush(stdout);
1828      fflush(stderr);
1829      eaccelerator_clean_request(TSRMLS_C);
1830      if (EG(active_op_array)) {
1831        DBG(ea_debug_error, ("[%d] EACCELERATOR: PHP unclean shutdown on opline %ld of %s() at %s:%u\n\n",
1832          getpid(),
1833          (long)(active_opline-EG(active_op_array)->opcodes),
1834          get_active_function_name(TSRMLS_C),
1835          zend_get_executed_filename(TSRMLS_C),
1836          zend_get_executed_lineno(TSRMLS_C)));
1837      } else {
1838        DBG(ea_debug_error, ("[%d] EACCELERATOR: PHP unclean shutdown\n\n",getpid()));
1839      }
1840    }
1841  }
1842}
1843
1844/* signal handlers */
1845#ifdef WITH_EACCELERATOR_CRASH_DETECTION
1846static void eaccelerator_crash_handler(int dummy) {
1847  TSRMLS_FETCH();
1848  fflush(stdout);
1849  fflush(stderr);
1850#ifdef SIGSEGV
1851  if (EAG(original_sigsegv_handler) != eaccelerator_crash_handler) {
1852    signal(SIGSEGV, EAG(original_sigsegv_handler));
1853  } else {
1854    signal(SIGSEGV, SIG_DFL);
1855  }
1856#endif
1857#ifdef SIGFPE
1858  if (EAG(original_sigfpe_handler) != eaccelerator_crash_handler) {
1859    signal(SIGFPE, EAG(original_sigfpe_handler));
1860  } else {
1861    signal(SIGFPE, SIG_DFL);
1862  }
1863#endif
1864#ifdef SIGBUS
1865  if (EAG(original_sigbus_handler) != eaccelerator_crash_handler) {
1866    signal(SIGBUS, EAG(original_sigbus_handler));
1867  } else {
1868    signal(SIGBUS, SIG_DFL);
1869  }
1870#endif
1871#ifdef SIGILL
1872  if (EAG(original_sigill_handler) != eaccelerator_crash_handler) {
1873    signal(SIGILL, EAG(original_sigill_handler));
1874  } else {
1875    signal(SIGILL, SIG_DFL);
1876  }
1877#endif
1878#ifdef SIGABRT
1879  if (EAG(original_sigabrt_handler) != eaccelerator_crash_handler) {
1880    signal(SIGABRT, EAG(original_sigabrt_handler));
1881  } else {
1882    signal(SIGABRT, SIG_DFL);
1883  }
1884#endif
1885  eaccelerator_clean_request(TSRMLS_C);
1886  if (EG(active_op_array)) {
1887    fprintf(stderr, "[%d] EACCELERATOR: PHP crashed on opline %ld of %s() at %s:%u\n\n",
1888      getpid(),
1889      (long)(active_opline-EG(active_op_array)->opcodes),
1890      get_active_function_name(TSRMLS_C),
1891      zend_get_executed_filename(TSRMLS_C),
1892      zend_get_executed_lineno(TSRMLS_C));
1893  } else {
1894    fprintf(stderr, "[%d] EACCELERATOR: PHP crashed\n\n",getpid());
1895  }
1896#if !defined(WIN32) && !defined(NETWARE)
1897  kill(getpid(), dummy);
1898#else
1899  raise(dummy);
1900#endif
1901}
1902#endif
1903
1904static void eaccelerator_init_globals(zend_eaccelerator_globals *eaccelerator_globals)
1905{
1906  eaccelerator_globals->used_entries      = NULL;
1907  eaccelerator_globals->enabled           = 1;
1908  eaccelerator_globals->cache_dir         = NULL;
1909  eaccelerator_globals->optimizer_enabled = 1;
1910  eaccelerator_globals->compiler          = 0;
1911  eaccelerator_globals->encoder           = 0;
1912  eaccelerator_globals->cond_list         = NULL;
1913  eaccelerator_globals->content_headers   = NULL;
1914#ifdef WITH_EACCELERATOR_SESSIONS
1915  eaccelerator_globals->session           = NULL;
1916#endif
1917  eaccelerator_globals->eaccelerator_log_file = '\000';
1918  eaccelerator_globals->name_space        = '\000';
1919  eaccelerator_globals->hostname[0]       = '\000';
1920  eaccelerator_globals->in_request        = 0;
1921  eaccelerator_globals->allowed_admin_path= NULL;
1922}
1923
1924static void eaccelerator_globals_dtor(zend_eaccelerator_globals *eaccelerator_globals)
1925{
1926  mm_cond_entry *p, *q;
1927
1928  for (p = eaccelerator_globals->cond_list; p != NULL; p = q) {
1929    q = p->next;
1930    if (p->str) {
1931      free(p->str);
1932    }
1933    free(p);
1934  }
1935  eaccelerator_globals->cond_list = NULL;
1936}
1937
1938static void register_eaccelerator_as_zend_extension();
1939
1940static int eaccelerator_check_php_version(TSRMLS_D) {
1941  zval v;
1942  int ret = 0;
1943  if (zend_get_constant("PHP_VERSION", sizeof("PHP_VERSION")-1, &v TSRMLS_CC)) {
1944    if (Z_TYPE(v) == IS_STRING &&
1945        Z_STRLEN(v) == sizeof(PHP_VERSION)-1 &&
1946        strcmp(Z_STRVAL(v),PHP_VERSION) == 0) {
1947      ret = 1;
1948    } else {
1949      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));
1950    }
1951    zval_dtor(&v);
1952  } else {
1953    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);
1954  }
1955  return ret;
1956}
1957
1958static void make_hash_dirs(char *fullpath, int lvl) {
1959  int j;
1960  int n = strlen(fullpath);
1961  mode_t old_umask = umask(0);
1962 
1963  if (lvl < 1)
1964    return;
1965  if (fullpath[n-1] != '/')
1966    fullpath[n++] = '/';
1967 
1968  for (j = 0; j < 16; j++) {
1969    fullpath[n] = num2hex[j];       
1970    fullpath[n+1] = 0;
1971    mkdir(fullpath, 0777);
1972    make_hash_dirs(fullpath, lvl-1);
1973  }
1974  fullpath[n+2] = 0;
1975  umask(old_umask);
1976}
1977
1978
1979PHP_MINIT_FUNCTION(eaccelerator) {
1980  char fullpath[MAXPATHLEN];
1981
1982  if (type == MODULE_PERSISTENT) {
1983#ifndef ZEND_WIN32
1984    if (strcmp(sapi_module.name,"apache") == 0) {
1985      if (getpid() != getpgrp()) {
1986        return SUCCESS;
1987      }
1988    }
1989#endif
1990#ifdef WITH_EACCELERATOR_LOADER
1991    if (zend_hash_exists(&module_registry, EACCELERATOR_LOADER_EXTENSION_NAME,
1992                sizeof(EACCELERATOR_LOADER_EXTENSION_NAME))) {
1993      zend_error(E_CORE_WARNING,"Extension \"%s\" is not need with \"%s\". Remove it from php.ini\n",
1994              EACCELERATOR_LOADER_EXTENSION_NAME, EACCELERATOR_EXTENSION_NAME);
1995      zend_hash_del(&module_registry, EACCELERATOR_LOADER_EXTENSION_NAME,
1996              sizeof(EACCELERATOR_LOADER_EXTENSION_NAME));
1997    }
1998#endif
1999  }
2000  if (!eaccelerator_check_php_version(TSRMLS_C)) {
2001    return FAILURE;
2002  }
2003  ZEND_INIT_MODULE_GLOBALS(eaccelerator, eaccelerator_init_globals, NULL);
2004  REGISTER_INI_ENTRIES();
2005  REGISTER_STRING_CONSTANT("EACCELERATOR_VERSION", EACCELERATOR_VERSION, CONST_CS | CONST_PERSISTENT);
2006  REGISTER_LONG_CONSTANT("EACCELERATOR_SHM_AND_DISK", eaccelerator_shm_and_disk, CONST_CS | CONST_PERSISTENT);
2007  REGISTER_LONG_CONSTANT("EACCELERATOR_SHM", eaccelerator_shm, CONST_CS | CONST_PERSISTENT);
2008  REGISTER_LONG_CONSTANT("EACCELERATOR_SHM_ONLY", eaccelerator_shm_only, CONST_CS | CONST_PERSISTENT);
2009  REGISTER_LONG_CONSTANT("EACCELERATOR_DISK_ONLY", eaccelerator_disk_only, CONST_CS | CONST_PERSISTENT);
2010  REGISTER_LONG_CONSTANT("EACCELERATOR_NONE", eaccelerator_none, CONST_CS | CONST_PERSISTENT);
2011  binary_eaccelerator_version = encode_version(EACCELERATOR_VERSION);
2012  binary_php_version = encode_version(PHP_VERSION);
2013  binary_zend_version = encode_version(ZEND_VERSION);
2014  eaccelerator_is_extension = 1;
2015
2016  ea_debug_init(TSRMLS_C);
2017
2018  snprintf(fullpath, MAXPATHLEN-1, "%s/", EAG(cache_dir));
2019  make_hash_dirs(fullpath, EACCELERATOR_HASH_LEVEL);
2020
2021  if (type == MODULE_PERSISTENT &&
2022      strcmp(sapi_module.name, "cgi") != 0 &&
2023      strcmp(sapi_module.name, "cli") != 0) {
2024    DBG(ea_debug_put, (EA_DEBUG, "\n=======================================\n"));
2025    DBG(ea_debug_printf, (EA_DEBUG, "[%d] EACCELERATOR STARTED\n", getpid()));
2026    DBG(ea_debug_put, (EA_DEBUG, "=======================================\n"));
2027
2028    if (init_mm(TSRMLS_C) == FAILURE) {
2029      zend_error(E_CORE_WARNING,"[%s] Can not create shared memory area", EACCELERATOR_EXTENSION_NAME);
2030      return FAILURE;
2031    }
2032    mm_saved_zend_compile_file = zend_compile_file;
2033
2034#ifdef DEBUG
2035    zend_compile_file = profile_compile_file;
2036    mm_saved_zend_execute = zend_execute;
2037    zend_execute = profile_execute;
2038#else
2039    zend_compile_file = eaccelerator_compile_file;
2040#endif
2041  }
2042#if defined(WITH_EACCELERATOR_SESSIONS) && defined(HAVE_PHP_SESSIONS_SUPPORT)
2043  if (!eaccelerator_session_registered()) {
2044    eaccelerator_register_session();
2045  }
2046#endif
2047#ifdef WITH_EACCELERATOR_CONTENT_CACHING
2048  eaccelerator_content_cache_startup();
2049#endif
2050  if (!eaccelerator_is_zend_extension) {
2051    register_eaccelerator_as_zend_extension();
2052  }
2053#ifdef ZEND_ENGINE_2
2054  /* cache the properties_info destructor */
2055  properties_info_dtor = get_zend_destroy_property_info(TSRMLS_C);
2056#endif
2057  return SUCCESS;
2058}
2059
2060PHP_MSHUTDOWN_FUNCTION(eaccelerator) {
2061  if (eaccelerator_mm_instance == NULL || !eaccelerator_is_extension) {
2062    return SUCCESS;
2063  }
2064  zend_compile_file = mm_saved_zend_compile_file;
2065#ifdef WITH_EACCELERATOR_CONTENT_CACHING
2066  eaccelerator_content_cache_shutdown();
2067#endif
2068  shutdown_mm(TSRMLS_C);
2069  DBG(ea_debug_put, (EA_DEBUG, "========================================\n"));
2070  DBG(ea_debug_printf, (EA_DEBUG, "[%d] EACCELERATOR STOPPED\n", getpid()));
2071  DBG(ea_debug_put, (EA_DEBUG, "========================================\n\n"));
2072  ea_debug_shutdown();
2073  UNREGISTER_INI_ENTRIES();
2074#ifdef ZTS
2075  ts_free_id(eaccelerator_globals_id);
2076#else
2077  eaccelerator_globals_dtor(&eaccelerator_globals TSRMLS_CC);
2078#endif
2079  eaccelerator_is_zend_extension = 0;
2080  eaccelerator_is_extension = 0;
2081  return SUCCESS;
2082}
2083
2084PHP_RINIT_FUNCTION(eaccelerator)
2085{
2086  union {
2087                zval **v;
2088    void *ptr;
2089  } server_vars, hostname;
2090
2091        if (eaccelerator_mm_instance == NULL) {
2092                return SUCCESS;
2093        }
2094
2095        /*
2096         * Initialization on first call, comes from eaccelerator_zend_startup().
2097         */
2098        if (eaccelerator_global_function_table.nTableSize == 0) {
2099                zend_function tmp_func;
2100                zend_class_entry tmp_class;
2101
2102                zend_hash_init_ex(&eaccelerator_global_function_table, 100, NULL, NULL, 1, 0);
2103                zend_hash_copy(&eaccelerator_global_function_table, CG(function_table), NULL,
2104                        &tmp_func, sizeof(zend_function));
2105               
2106                zend_hash_init_ex(&eaccelerator_global_class_table, 10, NULL, NULL, 1, 0);
2107                zend_hash_copy(&eaccelerator_global_class_table, CG(class_table), NULL,
2108                        &tmp_class, sizeof(zend_class_entry));
2109        }
2110
2111        DBG(ea_debug_printf, (EA_DEBUG, "[%d] Enter RINIT\n",getpid()));
2112        DBG(ea_debug_put, (EA_PROFILE_OPCODES, "\n========================================\n"));
2113
2114        EAG(in_request) = 1;
2115        EAG(used_entries) = NULL;
2116        EAG(compiler) = 0;
2117        EAG(encoder) = 0;
2118        EAG(refcount_helper) = 1;
2119        EAG(compress_content) = 1;
2120        EAG(content_headers) = NULL;
2121
2122        /* Storing Host Name */
2123        EAG(hostname)[0] = '\000';
2124  if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), &server_vars.ptr) == SUCCESS &&
2125                        Z_TYPE_PP(server_vars.v) == IS_ARRAY &&
2126                        zend_hash_find(Z_ARRVAL_PP(server_vars.v), "SERVER_NAME", sizeof("SERVER_NAME"), &hostname.ptr)==SUCCESS &&
2127                        Z_TYPE_PP(hostname.v) == IS_STRING && Z_STRLEN_PP(hostname.v) > 0) {
2128                if (sizeof(EAG(hostname)) > Z_STRLEN_PP(hostname.v)) {
2129                        memcpy(EAG(hostname),Z_STRVAL_PP(hostname.v),Z_STRLEN_PP(hostname.v)+1);
2130                } else {
2131                        memcpy(EAG(hostname),Z_STRVAL_PP(hostname.v),sizeof(EAG(hostname))-1);
2132                        EAG(hostname)[sizeof(EAG(hostname))-1] = '\000';
2133                }
2134  }
2135
2136        zend_hash_init(&EAG(restored), 0, NULL, NULL, 0);
2137
2138        DBG(ea_debug_printf, (EA_DEBUG, "[%d] Leave RINIT\n",getpid()));
2139#ifdef DEBUG
2140        EAG(xpad) = 0;
2141        EAG(profile_level) = 0;
2142#endif
2143
2144#ifdef WITH_EACCELERATOR_CRASH_DETECTION
2145#ifdef SIGSEGV
2146        EAG(original_sigsegv_handler) = signal(SIGSEGV, eaccelerator_crash_handler);
2147#endif
2148#ifdef SIGFPE
2149        EAG(original_sigfpe_handler) = signal(SIGFPE, eaccelerator_crash_handler);
2150#endif
2151#ifdef SIGBUS
2152        EAG(original_sigbus_handler) = signal(SIGBUS, eaccelerator_crash_handler);
2153#endif
2154#ifdef SIGILL
2155        EAG(original_sigill_handler) = signal(SIGILL, eaccelerator_crash_handler);
2156#endif
2157#ifdef SIGABRT
2158        EAG(original_sigabrt_handler) = signal(SIGABRT, eaccelerator_crash_handler);
2159#endif
2160#endif
2161        return SUCCESS;
2162}
2163
2164PHP_RSHUTDOWN_FUNCTION(eaccelerator)
2165{
2166        if (eaccelerator_mm_instance == NULL) {
2167                return SUCCESS;
2168        }
2169        zend_hash_destroy(&EAG(restored));
2170#ifdef WITH_EACCELERATOR_CRASH_DETECTION
2171#ifdef SIGSEGV
2172        if (EAG(original_sigsegv_handler) != eaccelerator_crash_handler) {
2173                signal(SIGSEGV, EAG(original_sigsegv_handler));
2174        } else {
2175                signal(SIGSEGV, SIG_DFL);
2176        }
2177#endif
2178#ifdef SIGFPE
2179        if (EAG(original_sigfpe_handler) != eaccelerator_crash_handler) {
2180                signal(SIGFPE, EAG(original_sigfpe_handler));
2181        } else {
2182                signal(SIGFPE, SIG_DFL);
2183        }
2184#endif
2185#ifdef SIGBUS
2186        if (EAG(original_sigbus_handler) != eaccelerator_crash_handler) {
2187                signal(SIGBUS, EAG(original_sigbus_handler));
2188        } else {
2189                signal(SIGBUS, SIG_DFL);
2190        }
2191#endif
2192#ifdef SIGILL
2193        if (EAG(original_sigill_handler) != eaccelerator_crash_handler) {
2194                signal(SIGILL, EAG(original_sigill_handler));
2195        } else {
2196                signal(SIGILL, SIG_DFL);
2197        }
2198#endif
2199#ifdef SIGABRT
2200        if (EAG(original_sigabrt_handler) != eaccelerator_crash_handler) {
2201                signal(SIGABRT, EAG(original_sigabrt_handler));
2202        } else {
2203                signal(SIGABRT, SIG_DFL);
2204        }
2205#endif
2206#endif
2207        DBG(ea_debug_printf, (EA_DEBUG, "[%d] Enter RSHUTDOWN\n",getpid()));
2208        eaccelerator_clean_request(TSRMLS_C);
2209        DBG(ea_debug_printf, (EA_DEBUG, "[%d] Leave RSHUTDOWN\n",getpid()));
2210        return SUCCESS;
2211}
2212
2213#ifdef ZEND_ENGINE_2
2214ZEND_BEGIN_ARG_INFO(eaccelerator_second_arg_force_ref, 0)
2215  ZEND_ARG_PASS_INFO(0)
2216  ZEND_ARG_PASS_INFO(1)
2217ZEND_END_ARG_INFO();
2218#else
2219static unsigned char eaccelerator_second_arg_force_ref[] = {2, BYREF_NONE, BYREF_FORCE};
2220#endif
2221
2222function_entry eaccelerator_functions[] = {
2223#ifdef WITH_EACCELERATOR_SHM
2224  PHP_FE(eaccelerator_put, NULL)
2225  PHP_FE(eaccelerator_get, NULL)
2226  PHP_FE(eaccelerator_rm, NULL)
2227  PHP_FE(eaccelerator_gc, NULL)
2228  PHP_FE(eaccelerator_lock, NULL)
2229  PHP_FE(eaccelerator_unlock, NULL)
2230#endif
2231#ifdef WITH_EACCELERATOR_INFO
2232  PHP_FE(eaccelerator_caching, NULL)
2233  #ifdef WITH_EACCELERATOR_OPTIMIZER
2234  PHP_FE(eaccelerator_optimizer, NULL)
2235  #endif
2236  PHP_FE(eaccelerator_clear, NULL)
2237  PHP_FE(eaccelerator_clean, NULL)
2238  PHP_FE(eaccelerator_info, NULL)
2239  PHP_FE(eaccelerator_purge, NULL)
2240  PHP_FE(eaccelerator_cached_scripts, NULL)
2241  PHP_FE(eaccelerator_removed_scripts, NULL)
2242  PHP_FE(eaccelerator_list_keys, NULL)
2243#endif
2244#ifdef WITH_EACCELERATOR_ENCODER
2245  PHP_FE(eaccelerator_encode, eaccelerator_second_arg_force_ref)
2246#endif
2247#ifdef WITH_EACCELERATOR_LOADER
2248  PHP_FE(eaccelerator_load, NULL)
2249  PHP_FE(_eaccelerator_loader_file, NULL)
2250  PHP_FE(_eaccelerator_loader_line, NULL)
2251#endif
2252#ifdef WITH_EACCELERATOR_SESSIONS
2253#ifndef HAVE_PHP_SESSIONS_SUPPORT
2254  PHP_FE(_eaccelerator_session_open, NULL)
2255  PHP_FE(_eaccelerator_session_close, NULL)
2256  PHP_FE(_eaccelerator_session_read, NULL)
2257  PHP_FE(_eaccelerator_session_write, NULL)
2258  PHP_FE(_eaccelerator_session_destroy, NULL)
2259  PHP_FE(_eaccelerator_session_gc, NULL)
2260#endif
2261  PHP_FE(eaccelerator_set_session_handlers, NULL)
2262#endif
2263#ifdef WITH_EACCELERATOR_CONTENT_CACHING
2264  PHP_FE(_eaccelerator_output_handler, NULL)
2265  PHP_FE(eaccelerator_cache_page, NULL)
2266  PHP_FE(eaccelerator_rm_page, NULL)
2267  PHP_FE(eaccelerator_cache_output, NULL)
2268  PHP_FE(eaccelerator_cache_result, NULL)
2269#endif
2270#ifdef WITH_EACCELERATOR_DISASSEMBLER
2271  PHP_FE(eaccelerator_dasm_file, NULL)
2272#endif
2273#ifdef ZEND_ENGINE_2
2274  {NULL, NULL, NULL, 0U, 0U}
2275#else
2276  {NULL, NULL, NULL}
2277#endif
2278};
2279
2280zend_module_entry eaccelerator_module_entry = {
2281#if ZEND_MODULE_API_NO >= 20010901
2282  STANDARD_MODULE_HEADER,
2283#endif
2284  EACCELERATOR_EXTENSION_NAME,
2285  eaccelerator_functions,
2286  PHP_MINIT(eaccelerator),
2287  PHP_MSHUTDOWN(eaccelerator),
2288  PHP_RINIT(eaccelerator),
2289  PHP_RSHUTDOWN(eaccelerator),
2290  PHP_MINFO(eaccelerator),
2291#if ZEND_MODULE_API_NO >= 20010901
2292  EACCELERATOR_VERSION,          /* extension version number (string) */
2293#endif
2294  STANDARD_MODULE_PROPERTIES
2295};
2296
2297#if defined(COMPILE_DL_EACCELERATOR)
2298ZEND_GET_MODULE(eaccelerator)
2299#endif
2300
2301static startup_func_t last_startup;
2302static zend_llist_element *eaccelerator_el;
2303
2304static const unsigned char eaccelerator_logo[] = {
2305      71,  73,  70,  56,  57,  97,  88,   0,  31,   0,
2306     213,   0,   0, 150, 153, 196, 237, 168,  86, 187,
2307     206, 230,   4,   4,   4, 108, 110, 144,  99, 144,
2308     199, 136, 138, 184,  87,  88, 109, 165, 165, 167,
2309     163, 166, 202, 240, 151,  44, 149,  91,  21, 225,
2310     225, 229,   4,  76, 164, 252, 215, 171, 255, 255,
2311     255, 212, 212, 224, 241, 200, 149, 141, 144, 192,
2312     216, 216, 226, 251, 230, 205, 192, 193, 218, 207,
2313     221, 238, 181, 188, 216, 130, 132, 168, 150, 152,
2314     185, 152, 152, 154, 180, 181, 198, 215, 184, 147,
2315      40, 102, 177, 224, 232, 242, 244, 244, 244, 235,
2316     236, 239, 118, 121, 157, 193, 193, 194, 146, 148,
2317     174, 181, 143,  96, 154, 183, 219, 156, 159, 200,
2318     126, 128, 170, 174, 175, 193,  65,  39,   7, 232,
2319     214, 192, 254, 241, 226, 246, 246, 248, 108,  65,
2320      13, 142, 144, 185, 252, 224, 189, 138, 171, 213,
2321      69, 122, 188, 239, 244, 249,  48,  49,  60, 176,
2322     178, 209, 200, 201, 222, 252, 252, 253, 251, 251,
2323     251, 162, 163, 187, 208, 208, 213, 169, 171, 205,
2324     241, 234, 225, 255, 252, 249, 254, 248, 241, 140,
2325     142, 169, 249, 186, 111,  33, 249,   4,   0,   0,
2326       0,   0,   0,  44,   0,   0,   0,   0,  88,   0,
2327      31,   0,   0,   6, 255,  64, 137, 112,  72,  44,
2328      26, 143, 200, 164, 114, 201,  92,  62, 158, 208,
2329     168, 116,  74, 173,  90, 175, 216, 108,  85, 168,
2330     237, 122, 191,  15,  25, 163, 118, 209, 153,   0,
2331      68, 128,  73, 119, 169,  49, 100,  86,  46, 120,
2332      78, 127, 216,  60,  21,  93,  83,   8, 208,  85,
2333      60,  54,  83, 114, 117, 132,  89,  32,  23,  38,
2334      73,  38, 103,  72,  38,  23,  32,  82, 123, 146,
2335     147,  69, 106,   9,  52,  21,  19,  53, 137, 138,
2336      51,  51, 156, 141,  21, 100,  52,   9, 148, 166,
2337     123,   0, 106, 126,  16,  21, 104,  67, 169, 106,
2338     140,   9,   3, 159, 140,  18, 176, 182,   0,  23,
2339      21, 101,  67,  21,  80,  32,  52, 192,  52,  44,
2340       6,  16,  15,   6,  23,  44,  81,  24,  81,  25,
2341      81, 194,  80,  25,   6,  18,  12,  80,  23,  15,
2342     169,  15, 172, 155, 105,  33,   7,   4, 158,  46,
2343       0,  33,   3,   7,   7,  51,   7, 139, 231, 225,
2344       7,  25, 124,  23,  23,  52, 190,  19,   4, 205,
2345      44,  27,   4,   4,  19,  57,  15,  33,  15,  32,
2346      54,  64, 168, 241,   0,   5,  10,  28, 255,  54,
2347     160, 120, 128, 163, 160,  65,   2,  15, 244, 229,
2348     200, 113, 162,  26,   4,  20, 252,  22, 130, 128,
2349      48,  98, 131,  30,  34,  38, 102, 208,  58,  64,
2350     203,   4,  73, 115,   3,   6, 184, 152,  69,  75,
2351     228,   1,  87,  38,  80, 204,  19, 242, 235,   9,
2352      54,  31,   4,  78, 212, 152, 192, 128,   1,   8,
2353     255,  31,  79,  78, 108,  99, 245, 239,  24,   3,
2354     136,  16,  32, 212, 139,  24,  34,  83,   8,   3,
2355      62,  33, 128,  56,  90,   3,  68, 136,  17, 173,
2356     138, 176,  76,  16, 114,  64,   2, 145,   4,   0,
2357     136, 196, 128, 129,  22, 215, 146,  66,  50, 224,
2358     248,  40,  33, 147,  62,   2,  11,  39, 120, 120,
2359      48, 162,  33,  10,   2,  44,  62,  64, 156, 144,
2360     244,  31, 129,  17,  12,  31, 240, 157, 240,  76,
2361     238, 131,  12,   4, 160, 110,   4,   1, 130, 192,
2362       6,   6,  33, 112, 212,  48, 226, 195, 220,  25,
2363     145,  95, 189, 118,  77,  64,  50, 236, 172,  79,
2364      66,  92, 140,  96,  11,   0,  71,  78,  12,  39,
2365      12, 108, 200,  71,  32,  68, 190,  16,  38,  70,
2366      56,  54, 120,  87,  71, 136,  16,  25,  70,  36,
2367     160, 141,  65,  33,  10,  12,  57,  13,  36, 240,
2368     173,  15,  64,   2,  31,  58, 186, 189,  34,  96,
2369     238,  86,  73,  90, 198,  75, 146,  12,   1, 128,
2370     249, 203, 208,  62,  74,   9,  49,  96,   0,   3,
2371      53,   9,   6,  78, 220,  78, 141, 218, 251, 137,
2372      19, 168, 199, 163, 230,  46, 254, 246, 120, 247,
2373     169, 193, 183, 127, 234,  34,  67,   6,  63,  51,
2374     249, 156,  12,  55, 160, 181,  57, 114, 255, 137,
2375      52,   3, 127,  62,  12, 129,  65, 118,  74, 112,
2376     247,  29, 120, 219,  81, 163, 224, 130, 224,  61,
2377      40, 225, 130,  15, 222, 162,  74,  60, 160, 116,
2378     181,  95,   6,  36, 189, 212, 255, 225, 103,  39,
2379      97, 224,  74, 119, 186, 157,  98, 162,  18, 169,
2380     172,  65,   3,  13,  40, 184, 178, 149,  14,   9,
2381     160,  97,   2,  87,  18, 204, 104,  66,  89,  51,
2382      24,  23, 163,  16,  62, 132, 224, 195,  90,  39,
2383       6, 121, 132,  37,  58, 176, 136, 195,  59,  46,
2384     152, 133,  98, 135, 174,   8, 129, 129, 143,  56,
2385      36, 160,  93,  33,  84,  82,  97,   3,  11,  12,
2386     136, 128,   3,  66, 227,  44,  49,   2, 110,  67,
2387     248, 224, 131,   6,  34,  48, 176, 204,   3, 131,
2388      84, 169, 230,  19,  44, 128, 144, 195,   6,  71,
2389     190, 179,   4,  26,  46, 136, 169,   1,  10,  57,
2390     236, 192,   2,  15,  79, 164, 185, 166, 154,  55,
2391     124, 192, 192, 155,   8, 228,  54, 130,  11, 136,
2392     134,  86, 167, 152,  99,  34, 176,  65,  14,  12,
2393     124,  16,   8,  20, 126,  62, 176,   2,   5,  20,
2394     188, 160, 233, 166, 155,  58, 224, 105,   4,  61,
2395     252,  73,  69, 160,  59,  12,  42,   2,  10,   8,
2396      32, 160, 193, 170, 171, 166, 138, 130,   8, 144,
2397     238, 240,   1, 159, 145,  72,   0,   5,  15,  20,
2398      56,  16,  65,   4,  63,   4, 224, 171,   2,   1,
2399       0, 171, 192, 176, 195,   6,  32, 234,  21, 129,
2400     126,  48,  85,  79, 204,  50,  43, 235,   7,  55,
2401     196,  97, 171, 165, 159, 254, 240, 195, 176,  63,
2402     188, 240,   0, 173,  80, 244, 192, 194, 153,   2,
2403     192, 113, 236, 184, 114, 172,  96, 174, 185, 152,
2404      82, 160, 255, 133,   7,  13,  20, 240, 132,  12,
2405       5, 196,  80, 192,  92,  15, 192,  32, 175,   0,
2406      15,  88,  16, 195, 190,  22, 148, 224, 238,  19,
2407     250, 242,  27, 176, 188, 226, 198, 128, 205, 190,
2408     252, 202,  96, 111,   1, 248,  62, 128, 112,   1,
2409      22,  80, 106, 235,  11,  14,  80, 188, 107, 175,
2410     190, 250, 106,  45, 198,   1, 144, 192, 193,  19,
2411       5,  52, 208,  64,  24,  29, 116,  96, 111,   3,
2412     240,  54,   0,  67, 200,   2,   8, 160,  50,  12,
2413      30, 216,  11, 133, 203,  48, 192,  76,  51,  12,
2414     237,  62, 112,  65, 187,  54, 216, 107, 178,   7,
2415      49, 168,  28,  52, 190, 237, 194,  80, 178, 196,
2416      43, 108,  28, 172,   2,  11, 120, 204, 193, 211,
2417      17, 112, 176, 235, 211,  28, 236, 240,  68,   7,
2418      33, 151, 128, 179, 184,  45,  55,  32,  64, 180,
2419      22, 120, 224, 114, 203,  10, 199,  48, 179, 215,
2420     225, 186,  12, 178, 217,  33, 163,  92, 175, 217,
2421      22, 120, 125, 131,  13, 242,  62, 224, 117, 189,
2422      35, 247,  41, 129,   3, 196,  50, 189,  64,  11,
2423      36, 216,  48, 183,  29,  79,   4,  98, 195, 164,
2424      46, 119,  80, 180, 217, 103,  75, 225, 178, 200,
2425       2, 200, 252, 196, 227, 104, 139,  44, 242,   5,
2426      50,  52, 160,  56,  12, 111,  63, 160, 246,  19,
2427     246, 218,  96, 121, 206, 122, 191, 224, 247, 223,
2428      45, 164, 238, 244, 174, 172,  63, 173, 238,   3,
2429       5, 152,  28,  50, 206,  17,  43,  76, 154,  51,
2430     232,  93,  67,  33, 185, 231, 121, 243,  46,  64,
2431      12,  29,  60,  80, 130, 208, 193, 203, 204,  46,
2432     231,  50,  96, 109, 119, 205,  13, 208, 139, 166,
2433     173,  42, 144, 176,  64,  10, 212,  87, 159, 250,
2434       2, 216, 103, 191, 192,  14, 129, 168, 252, 132,
2435     202,  33,   7,  93, 188, 230, 138, 139, 221,   0,
2436     191,  56, 239, 203, 240, 249,  49,  88, 160, 118,
2437     220,  43, 155, 189, 115, 204, 140, 227, 172, 120,
2438     243, 118, 135, 139, 245, 164, 149,  78,  74, 248,
2439     220, 130, 187, 193, 224,  30,  16,  51, 113, 149,
2440     160,   4,  54, 208,  90,   9, 102,  86,  51,  56,
2441     196, 172, 102,  98, 171,  25,  12,  74, 240,  64,
2442     152, 197, 204,  38,  53, 139,  88, 189,  90, 182,
2443     192, 201, 213, 236,  76,  48, 179, 129,   5,  96,
2444     166, 183, 113, 153,  80,  77,  66,  74, 161,  10,
2445      41,  17,   4,   0,  59,   0 };
2446 
2447static int eaccelerator_last_startup(zend_extension *extension) {
2448  int ret;
2449  extension->startup = last_startup;
2450  ret = extension->startup(extension);
2451  zend_extensions.count++;
2452  eaccelerator_el->next = zend_extensions.head;
2453  eaccelerator_el->prev = NULL;
2454  zend_extensions.head->prev = eaccelerator_el;
2455  zend_extensions.head = eaccelerator_el;
2456  if (ZendOptimizer) {
2457    if ((ZendOptimizer = zend_get_extension("Zend Optimizer")) != NULL) {
2458      ZendOptimizer->op_array_handler = NULL;
2459    }
2460  }
2461  return ret;
2462}
2463
2464/*
2465static int eaccelerator_ioncube_startup(zend_extension *extension) {
2466  int ret;
2467  zend_extension* last_ext = (zend_extension*)zend_extensions.tail->data;
2468  extension->startup = last_startup;
2469  ret = extension->startup(extension);
2470  last_startup = last_ext->startup;
2471  last_ext->startup = eaccelerator_last_startup;
2472  return ret;
2473}
2474*/
2475
2476
2477ZEND_DLEXPORT int eaccelerator_zend_startup(zend_extension *extension) {
2478 eaccelerator_is_zend_extension = 1;
2479  eaccelerator_el   = NULL;
2480  last_startup = NULL;
2481
2482  if (!eaccelerator_is_extension) {
2483    if (zend_startup_module(&eaccelerator_module_entry) != SUCCESS) {
2484      return FAILURE;
2485    }
2486  }
2487
2488  if (zend_llist_count(&zend_extensions) > 1) {
2489    zend_llist_element *p = zend_extensions.head;
2490    while (p != NULL) {
2491      zend_extension* ext = (zend_extension*)(p->data);
2492      if (strcmp(ext->name, EACCELERATOR_EXTENSION_NAME) == 0) {
2493        /* temporary removing eAccelerator extension */
2494        zend_extension* last_ext = (zend_extension*)zend_extensions.tail->data;
2495        if (eaccelerator_el != NULL) {
2496          zend_error(E_CORE_ERROR,"[%s] %s %s can not be loaded twice",
2497                   EACCELERATOR_EXTENSION_NAME,
2498                   EACCELERATOR_EXTENSION_NAME,
2499                   EACCELERATOR_VERSION);
2500          exit(1);
2501        }
2502        if (last_ext != ext) {
2503          eaccelerator_el = p;
2504          last_startup = last_ext->startup;
2505          last_ext->startup = eaccelerator_last_startup;
2506          zend_extensions.count--;
2507          if (p->prev != NULL) {
2508            p->prev->next = p->next;
2509          } else {
2510            zend_extensions.head = p->next;
2511          }
2512          if (p->next != NULL) {
2513            p->next->prev = p->prev;
2514          } else {
2515            zend_extensions.tail = p->prev;
2516          }
2517        }
2518      } else if (strcmp(ext->name, "Zend Extension Manager") == 0 ||
2519                 strcmp(ext->name, "Zend Optimizer") == 0) {
2520        /* Disable ZendOptimizer Optimizations */
2521        ZendOptimizer = ext;
2522        ext->op_array_handler = NULL;
2523      }
2524      p = p->next;
2525    }
2526  }
2527
2528  php_register_info_logo(EACCELERATOR_VERSION_GUID, "text/plain", (unsigned char*)EACCELERATOR_VERSION_STRING, sizeof(EACCELERATOR_VERSION_STRING));
2529  php_register_info_logo(EACCELERATOR_LOGO_GUID,    "image/gif",  (unsigned char*)eaccelerator_logo, sizeof(eaccelerator_logo));
2530
2531  /*
2532   * HOESH: on apache restart there was some
2533   * problem with CG(class_table) in the latest PHP
2534   * versions. Initialization moved to eaccelerator_compile_file()
2535   * depends on the value below.
2536   */
2537  eaccelerator_global_function_table.nTableSize = 0;
2538
2539  return SUCCESS;
2540}
2541
2542#ifndef ZEND_EXT_API
2543#  define ZEND_EXT_API    ZEND_DLEXPORT
2544#endif
2545
2546ZEND_EXTENSION();
2547
2548ZEND_DLEXPORT zend_extension zend_extension_entry = {
2549  EACCELERATOR_EXTENSION_NAME,
2550  EACCELERATOR_VERSION,
2551  "eAccelerator",
2552  "http://eaccelerator.net",
2553  "Copyright (c) 2004-2006 eAccelerator",
2554  eaccelerator_zend_startup,
2555  NULL,
2556  NULL,   /* void (*activate)() */
2557  NULL,   /* void (*deactivate)() */
2558  NULL,   /* void (*message_handle)(int message, void *arg) */
2559#ifdef WITH_EACCELERATOR_OPTIMIZER
2560  eaccelerator_optimize,   /* void (*op_array_handler)(zend_op_array *o_a); */
2561#else
2562  NULL,   /* void (*op_array_handler)(zend_op_array *o_a); */
2563#endif
2564  NULL,   /* void (*statement_handler)(zend_op_array *o_a); */
2565  NULL,   /* void (*fcall_begin_handler)(zend_op_array *o_a); */
2566  NULL,   /* void (*fcall_end_handler)(zend_op_array *o_a); */
2567  NULL,   /* void (*op_array_ctor)(zend_op_array *o_a); */
2568  NULL,   /* void (*op_array_dtor)(zend_op_array *o_a); */
2569#ifdef COMPAT_ZEND_EXTENSION_PROPERTIES
2570  NULL,   /* api_no_check */
2571  COMPAT_ZEND_EXTENSION_PROPERTIES
2572#else
2573  STANDARD_ZEND_EXTENSION_PROPERTIES
2574#endif
2575};
2576
2577static zend_extension eaccelerator_extension_entry = {
2578  EACCELERATOR_EXTENSION_NAME,
2579  EACCELERATOR_VERSION,
2580  "eAccelerator",
2581  "http://eaccelerator.net",
2582  "Copyright (c) 2004-2006 eAccelerator",
2583  eaccelerator_zend_startup,
2584  NULL,
2585  NULL,   /* void (*activate)() */
2586  NULL,   /* void (*deactivate)() */
2587  NULL,   /* void (*message_handle)(int message, void *arg) */
2588#ifdef WITH_EACCELERATOR_OPTIMIZER
2589  eaccelerator_optimize,   /* void (*op_array_handler)(zend_op_array *o_a); */
2590#else
2591  NULL,   /* void (*op_array_handler)(zend_op_array *o_a); */
2592#endif
2593  NULL,   /* void (*statement_handler)(zend_op_array *o_a); */
2594  NULL,   /* void (*fcall_begin_handler)(zend_op_array *o_a); */
2595  NULL,   /* void (*fcall_end_handler)(zend_op_array *o_a); */
2596  NULL,   /* void (*op_array_ctor)(zend_op_array *o_a); */
2597  NULL,   /* void (*op_array_dtor)(zend_op_array *o_a); */
2598#ifdef COMPAT_ZEND_EXTENSION_PROPERTIES
2599  NULL,   /* api_no_check */
2600  COMPAT_ZEND_EXTENSION_PROPERTIES
2601#else
2602  STANDARD_ZEND_EXTENSION_PROPERTIES
2603#endif
2604};
2605
2606static void register_eaccelerator_as_zend_extension() {
2607  zend_extension extension = eaccelerator_extension_entry;
2608  extension.handle = 0;
2609  zend_llist_prepend_element(&zend_extensions, &extension);
2610}
2611
2612/******************************************************************************/
2613
2614#endif  /* #ifdef HAVE_EACCELERATOR */
2615
2616/*
2617 * Local variables:
2618 * tab-width: 2
2619 * c-basic-offset: 2
2620 * End:
2621 * vim600: noet sw=2 ts=2 fdm=marker
2622 * vim<600: noet sw=2 ts=2
2623 */
Note: See TracBrowser for help on using the repository browser.