root/eaccelerator/branches/new-cache/eaccelerator.c

Revision 335, 81.2 kB (checked in by bart, 1 year ago)

Branch trunk for new caching code

  • 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 - 2007 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 "fnmatch.h"
53 #  include "win32/time.h"
54 #  include <time.h>
55 #  include <sys/utime.h>
56 #else
57 #  include <fnmatch.h>
58 #  include <sys/file.h>
59 #  include <sys/time.h>
60 #  include <utime.h>
61 #endif
62 #include <fcntl.h>
63
64 #ifndef O_BINARY
65 #  define O_BINARY 0
66 #endif
67
68 #include "php.h"
69 #include "php_ini.h"
70 #include "php_logos.h"
71 #include "main/fopen_wrappers.h"
72 #include "ext/standard/info.h"
73 #include "ext/standard/php_incomplete_class.h"
74 #include "ext/standard/md5.h"
75
76 #include "SAPI.h"
77
78 #define MAX_DUP_STR_LEN 256
79
80 /* Globals (different for each process/thread) */
81 ZEND_DECLARE_MODULE_GLOBALS(eaccelerator)
82
83 /* Globals (common for each process/thread) */
84 static long ea_shm_size = 0;
85 long ea_shm_max = 0;
86 static long ea_shm_ttl = 0;
87 static long ea_shm_prune_period = 0;
88 extern long eaccelerator_debug;
89 static zend_bool eaccelerator_check_mtime = 1;
90 zend_bool eaccelerator_scripts_shm_only = 0;
91
92 eaccelerator_mm* eaccelerator_mm_instance = NULL;
93 static int eaccelerator_is_zend_extension = 0;
94 static int eaccelerator_is_extension      = 0;
95 zend_extension* ZendOptimizer = NULL;
96
97 static HashTable eaccelerator_global_function_table;
98 static HashTable eaccelerator_global_class_table;
99
100 int binary_eaccelerator_version[2];
101 int binary_php_version[2];
102 int binary_zend_version[2];
103
104 #ifdef ZEND_ENGINE_2
105 /* pointer to the properties_info hashtable destructor */
106 extern dtor_func_t properties_info_dtor;
107 #endif
108
109 /* saved original functions */
110 static zend_op_array *(*mm_saved_zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
111
112 #ifdef DEBUG
113 static void (*mm_saved_zend_execute)(zend_op_array *op_array TSRMLS_DC);
114 #endif
115
116 /* external declarations */
117 PHPAPI void php_stripslashes(char *str, int *len TSRMLS_DC);
118
119 ZEND_DLEXPORT zend_op_array* eaccelerator_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC);
120
121 /******************************************************************************/
122 /* hash mm functions                                                          */
123 /******************************************************************************/
124
125 /* Find a script entry with the given hash key */
126 static ea_cache_entry* hash_find_mm(const char  *key,
127                                     struct stat *buf,
128                                     int         *nreloads,
129                                     time_t      ttl) {
130   unsigned int hv, slot;
131   ea_cache_entry *p, *q;
132
133 #ifdef EACCELERATOR_USE_INODE
134   hv = buf->st_dev + buf->st_ino;
135 #else
136   hv = zend_get_hash_value((char *)key, strlen(key));
137 #endif
138   slot = hv & EA_HASH_MAX;
139
140   EACCELERATOR_LOCK_RW();
141   q = NULL;
142   p = eaccelerator_mm_instance->hash[slot];
143   while (p != NULL) {
144 #ifdef EACCELERATOR_USE_INODE
145     if (p->st_dev == buf->st_dev && p->st_ino == buf->st_ino) {
146       struct stat buf2;
147       if ((eaccelerator_check_mtime &&
148           (buf->st_mtime != p->mtime || buf->st_size != p->filesize)) ||
149           (strcmp(p->realfilename, key) != 0 &&
150            (stat(p->realfilename,&buf2) != 0 ||
151            buf2.st_dev != buf->st_dev ||
152            buf2.st_ino != buf->st_ino))) {
153 #else
154     if ((p->hv == hv) && (strcmp(p->realfilename, key) == 0)) {
155       if (eaccelerator_check_mtime &&
156           (buf->st_mtime != p->mtime || buf->st_size != p->filesize)) {
157 #endif
158         /* key is invalid. Remove it. */
159         *nreloads = p->nreloads+1;
160         if (q == NULL) {
161           eaccelerator_mm_instance->hash[slot] = p->next;
162         } else {
163           q->next = p->next;
164         }
165         eaccelerator_mm_instance->hash_cnt--;
166         if (p->use_cnt > 0) {
167           /* key is used by other process/thred. Shedule it to remove */
168           p->removed = 1;
169           p->next = eaccelerator_mm_instance->removed;
170           eaccelerator_mm_instance->removed = p;
171           eaccelerator_mm_instance->rem_cnt++;
172           EACCELERATOR_UNLOCK_RW();
173           return NULL;
174         } else {
175           /* key is unused. Remove it. */
176           eaccelerator_free_nolock(p);
177           EACCELERATOR_UNLOCK_RW();
178           return NULL;
179         }
180       } else {
181         /* key is valid */
182         p->nhits++;
183         p->use_cnt++;
184         p->ttl = ttl;
185         EACCELERATOR_UNLOCK_RW();
186         return p;
187       }
188     }
189     q = p;
190     p = p->next;
191   }
192   EACCELERATOR_UNLOCK_RW();
193   return NULL;
194 }
195
196 /* Add a new entry to the hashtable */
197 static void hash_add_mm(ea_cache_entry *x) {
198   ea_cache_entry *p,*q;
199   unsigned int slot;
200 #ifdef EACCELERATOR_USE_INODE
201   slot = (x->st_dev + x->st_ino) & EA_HASH_MAX;
202 #else
203   x->hv = zend_get_hash_value(x->realfilename, strlen(x->realfilename));
204   slot = x->hv & EA_HASH_MAX;
205 #endif
206
207   EACCELERATOR_LOCK_RW();
208   x->next = eaccelerator_mm_instance->hash[slot];
209   eaccelerator_mm_instance->hash[slot] = x;
210   eaccelerator_mm_instance->hash_cnt++;
211   q = x;
212   p = x->next;
213   while (p != NULL) {
214 #ifdef EACCELERATOR_USE_INODE
215     if ((p->st_dev == x->st_dev) && (p->st_ino == x->st_ino)) {
216 #else
217     if ((p->hv == x->hv) &&
218         (strcmp(p->realfilename, x->realfilename) == 0)) {
219 #endif
220       q->next = p->next;
221       eaccelerator_mm_instance->hash_cnt--;
222       eaccelerator_mm_instance->hash[slot]->nreloads += p->nreloads;
223       if (p->use_cnt > 0) {
224         /* key is used by other process/thred. Shedule it to remove */
225         p->removed = 1;
226         p->next = eaccelerator_mm_instance->removed;
227         eaccelerator_mm_instance->removed = p;
228         eaccelerator_mm_instance->rem_cnt++;
229         EACCELERATOR_UNLOCK_RW();
230         return;
231       } else {
232         /* key is unused. Remove it. */
233         eaccelerator_free_nolock(p);
234         EACCELERATOR_UNLOCK_RW();
235         return;
236       }
237     }
238     q = p;
239     p = p->next;
240   }
241   EACCELERATOR_UNLOCK_RW();
242 }
243
244 /* Initialise the shared memory */
245 static int init_mm(TSRMLS_D) {
246   pid_t  owner = getpid();
247   MM     *mm;
248   size_t total;
249   char   mm_path[MAXPATHLEN];
250
251 #ifdef ZEND_WIN32
252     snprintf(mm_path, MAXPATHLEN, "%s.%s", EACCELERATOR_MM_FILE, sapi_module.name);
253 #else
254     snprintf(mm_path, MAXPATHLEN, "%s.%s%d", EACCELERATOR_MM_FILE, sapi_module.name, owner);
255 #endif
256 /*  snprintf(mm_path, MAXPATHLEN, "%s.%s%d", EACCELERATOR_MM_FILE, sapi_module.name, geteuid());*/
257   if ((eaccelerator_mm_instance = (eaccelerator_mm*)mm_attach(ea_shm_size*1024*1024, mm_path)) != NULL) {
258 #ifdef ZTS
259     ea_mutex = tsrm_mutex_alloc();
260 #endif
261     return SUCCESS;
262   }
263   mm = mm_create(ea_shm_size*1024*1024, mm_path);
264   if (!mm) {
265     return FAILURE;
266   }
267 #ifdef ZEND_WIN32
268   DBG(ea_debug_printf, (EA_DEBUG, "init_mm [%d]\n", owner));
269 #else
270   DBG(ea_debug_printf, (EA_DEBUG, "init_mm [%d,%d]\n", owner, getppid()));
271 #endif
272 #ifdef ZTS
273   ea_mutex = tsrm_mutex_alloc();
274 #endif
275   total = mm_available(mm);
276   eaccelerator_mm_instance = mm_malloc_lock(mm, sizeof(*eaccelerator_mm_instance));
277   if (!eaccelerator_mm_instance) {
278     return FAILURE;
279   }
280   mm_set_attach(mm, eaccelerator_mm_instance);
281   memset(eaccelerator_mm_instance, 0, sizeof(*eaccelerator_mm_instance));
282   eaccelerator_mm_instance->owner = owner;
283   eaccelerator_mm_instance->mm    = mm;
284   eaccelerator_mm_instance->total = total;
285   eaccelerator_mm_instance->hash_cnt = 0;
286   eaccelerator_mm_instance->rem_cnt  = 0;
287   eaccelerator_mm_instance->enabled = 1;
288   eaccelerator_mm_instance->optimizer_enabled = 1;
289   eaccelerator_mm_instance->removed = NULL;
290   eaccelerator_mm_instance->locks = NULL;
291   eaccelerator_mm_instance->user_hash_cnt = 0;
292   eaccelerator_mm_instance->last_prune = time(NULL);    /* this time() call is harmless since this is init phase */
293   EACCELERATOR_PROTECT();
294   return SUCCESS;
295 }
296
297 /* Clean up the shared memory */
298 static void shutdown_mm(TSRMLS_D) {
299   if (eaccelerator_mm_instance) {
300 #ifdef ZEND_WIN32
301     if (eaccelerator_mm_instance->owner == getpid()) {
302 #else
303     if (getpgrp() == getpid()) {
304 #endif
305       MM *mm = eaccelerator_mm_instance->mm;
306 #ifdef ZEND_WIN32
307       DBG(ea_debug_printf, (EA_DEBUG, "shutdown_mm [%d]\n", getpid()));
308 #else
309       DBG(ea_debug_printf, (EA_DEBUG, "shutdown_mm [%d,%d]\n", getpid(), getppid()));
310 #endif
311 #ifdef ZTS
312       tsrm_mutex_free(ea_mutex);
313 #endif
314       if (mm) {
315         mm_destroy(mm);
316       }
317       eaccelerator_mm_instance = NULL;
318     }
319   }
320 }
321
322 void encode_version(const char *str, int *version, int *extra)
323 {
324     unsigned int a = 0;
325     unsigned int b = 0;
326     unsigned int c = 0;
327     unsigned int d = 0;
328     size_t len;
329     char s[255];
330     char buf[255];
331
332     len = strlen(str);
333     memcpy(buf, str, (len > 255) ? 255 : len);
334     buf[255] = '\0';
335
336     memset(s, 0, 255);
337     sscanf(str, "%u.%u.%u%s", &a, &b, &c, s);
338
339     if (s[0] == '.') {
340         sscanf(s, ".%u-%s", &d, buf);
341     } else if (s[0] == '-') {
342         memcpy(buf, &s[1], 254);
343     } else {
344         memcpy(buf, s, 255);
345     }
346
347     *version = ((a & 0xff) << 24) | ((b & 0xff) << 16) | ((c & 0xff) << 8) | (d & 0xff);
348
349     if (buf[0] == 0) {
350         a = 0;
351         b = 0;
352     } else if (strncasecmp(buf, "rev", 3) == 0) {
353         a = 1;
354         sscanf(buf, "rev%u", &b);
355     } else if (strncasecmp(buf, "rc", 2) == 0) {
356         a = 2;
357         sscanf(buf, "rc%u", &b);
358     } else if (strncasecmp(buf, "beta", 4) == 0) {
359         a = 3;
360         sscanf(buf, "beta%u", &b);
361     } else {
362         a = 0xf;
363         // just encode the first 4 bytes
364         b = ((buf[0] & 0x7f) << 21) | ((buf[1] & 0x7f) << 14) | ((buf[2] & 0x7f) << 7) | (buf[3] & 0x7f);
365     }
366
367     *extra = ((a & 0xf) << 28) | (0x0fffffff & b);
368 }
369
370 static void decode_version(int version, int extra, char *str, size_t len)
371 {
372     int number;
373
374     if ((version & 0xff) == 0) {
375         number = snprintf(str, len, "%u.%u.%u", (version >> 24), ((version >> 16) & 0xff), ((version >> 8) & 0xff));
376     } else {
377         number = snprintf(str, len, "%u.%u.%u.%u", (version >> 24), ((version >> 16) & 0xff), ((version >> 8) & 0xff), (version & 0xff));
378     }
379
380     if (extra != 0) {
381         unsigned int type = ((extra >> 28) & 0xf);
382         extra = (extra & 0x0fffffff);
383         switch (type) {
384             case 1:
385                 snprintf(&str[number], len, "-rev%u", extra);
386                 break;
387             case 2:
388                 snprintf(&str[number], len, "-rc%u", extra);
389                 break;
390             case 3:
391                 snprintf(&str[number], len, "-beta%u", extra);
392                 break;
393             case 15:
394                 if ((int)len >= number + 5) {
395                     str[number] = '-';
396                     str[number + 1] = (extra >> 21) & 0x7f;
397                     str[number + 2] = (extra >> 14) & 0x7f;
398                     str[number + 3] = (extra >> 7) & 0x7f;
399                     str[number + 4] = extra & 0x7f;
400                     str[number + 5] = '\0';
401                 }
402                 break;
403             default:
404                 break;
405         }
406     }
407 }
408
409 static char num2hex[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
410
411 #ifdef EACCELERATOR_USE_INODE
412 static int eaccelerator_inode_key(char* s, dev_t dev, ino_t ino TSRMLS_DC) {
413   int n, i;
414   snprintf(s, MAXPATHLEN-1, "%s/", EAG(cache_dir));
415   n = strlen(s);
416   for (i = 1; i <= EACCELERATOR_HASH_LEVEL && n < MAXPATHLEN - 1; i++) {
417     s[n++] = num2hex[(ino >> (i << 2)) & 0xf]; // (ino / (i * 4))
418     s[n++] = '/';
419   }
420   s[n] = 0;
421   strlcat(s, "eaccelerator-", MAXPATHLEN-1);
422   n += sizeof("eaccelerator-") - 1;
423   while (dev > 0) {
424     if (n >= MAXPATHLEN) return 0;
425     s[n++] = (dev % 10) +'0';
426     dev /= 10;
427   }
428   if (n >= MAXPATHLEN) return 0;
429   s[n++] = '.';
430   while (ino > 0) {
431     if (n >= MAXPATHLEN) return 0;
432     s[n++] = (ino % 10) +'0';
433     ino /= 10;
434   }
435   if (n >= MAXPATHLEN) return 0;
436   s[n++] = '\000';
437   return 1;
438 }
439 #endif
440
441 /* Function to create a hash key when filenames are used */
442 int eaccelerator_md5(char* s, const char* prefix, const char* key TSRMLS_DC) {
443   char md5str[33];
444   PHP_MD5_CTX context;
445   unsigned char digest[16];
446   int i;
447   int n;
448
449   md5str[0] = '\0';
450   PHP_MD5Init(&context);
451   PHP_MD5Update(&context, (unsigned char*)key, strlen(key));
452   PHP_MD5Final(digest, &context);
453   make_digest(md5str, digest);
454   snprintf(s, MAXPATHLEN-1, "%s/", EAG(cache_dir));
455   n = strlen(s);
456   for (i = 0; i < EACCELERATOR_HASH_LEVEL && n < MAXPATHLEN - 1; i++) {
457     s[n++] = md5str[i];
458     s[n++] = '/';
459   }
460   s[n] = 0;
461   snprintf(s, MAXPATHLEN-1, "%s%s%s", s, prefix, md5str);
462   return 1;
463 }
464
465 /* Remove expired keys, content and scripts from the memory cache */
466 void eaccelerator_prune(time_t t) {
467   unsigned int i;
468
469   EACCELERATOR_LOCK_RW();
470   eaccelerator_mm_instance->last_prune = t;
471   for (i = 0; i < EA_HASH_SIZE; i++) {
472     ea_cache_entry **p = &eaccelerator_mm_instance->hash[i];
473     while (*p != NULL) {
474       struct stat buf;
475       if (((*p)->ttl != 0 && (*p)->ttl < t && (*p)->use_cnt <= 0) ||
476           stat((*p)->realfilename,&buf) != 0 ||
477 #ifdef EACCELERATOR_USE_INODE
478           (*p)->st_dev != buf.st_dev ||
479           (*p)->st_ino != buf.st_ino ||
480 #endif
481           (*p)->mtime != buf.st_mtime ||
482           (*p)->filesize != buf.st_size) {
483         ea_cache_entry *r = *p;
484         *p = (*p)->next;
485         eaccelerator_mm_instance->hash_cnt--;
486         eaccelerator_free_nolock(r);
487       } else {
488         p = &(*p)->next;
489       }
490     }
491   }
492   EACCELERATOR_UNLOCK_RW();
493 }
494
495 /* Allocate a new cache chunk */
496 void* eaccelerator_malloc2(size_t size TSRMLS_DC) {
497   void *p = NULL;
498
499 #if defined(WITH_EACCELERATOR_CONTENT_CACHING) || defined(WITH_EACCELERATOR_SESSIONS) || defined(WITH_EACCELERATOR_SHM)
500   if (eaccelerator_gc(TSRMLS_C) > 0) {
501     p = eaccelerator_malloc(size);
502     if (p != NULL) {
503       return p;
504     }
505   }
506 #endif
507   if (ea_shm_prune_period > 0) {
508     if (EAG(req_start) - eaccelerator_mm_instance->last_prune > ea_shm_prune_period) {
509       eaccelerator_prune(EAG(req_start));
510       p = eaccelerator_malloc(size);
511     }
512   }
513   return p;
514 }
515
516 #define EACCELERATOR_CRC32(crc, ch)   (crc = (crc >> 8) ^ crc32tab[(crc ^ (ch)) & 0xff])
517
518 static const unsigned int crc32tab[256] = {
519   0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
520   0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
521   0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
522   0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
523   0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
524   0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
525   0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
526   0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
527   0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
528   0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
529   0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
530   0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
531   0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
532   0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
533   0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
534   0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
535   0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
536   0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
537   0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
538   0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
539   0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
540   0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
541   0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
542   0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
543   0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
544   0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
545   0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
546   0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
547   0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
548   0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
549   0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
550   0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
551   0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
552   0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
553   0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
554   0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
555   0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
556   0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
557   0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
558   0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
559   0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
560   0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
561   0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
562   0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
563   0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
564   0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
565   0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
566   0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
567   0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
568   0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
569   0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
570   0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
571   0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
572   0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
573   0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
574   0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
575   0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
576   0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
577   0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
578   0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
579   0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
580   0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
581   0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
582   0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
583 };
584
585 unsigned int eaccelerator_crc32(const char *p, size_t n) {
586   unsigned int crc = ~0;
587   for (; n--; ++p) {
588     EACCELERATOR_CRC32(crc, *p);
589   }
590   return ~crc;
591 }
592
593 /******************************************************************************/
594 /* Cache file functions.                                                                                                                */
595 /******************************************************************************/
596
597 /* A function to check if the header of a cache file valid is.
598  */
599 inline int check_header(ea_file_header *hdr)
600 {
601 #ifdef DEBUG
602   char current[255];
603   char cache[255];
604 #endif
605        
606   if (strncmp(hdr->magic, EA_MAGIC, 8) != 0) {
607 #ifdef DEBUG
608     ea_debug_printf(EA_DEBUG, "Magic header mismatch.");
609 #endif
610         return 0;       
611   }
612   if (hdr->eaccelerator_version[0] != binary_eaccelerator_version[0]
613       || hdr->eaccelerator_version[1] != binary_eaccelerator_version[1]) {
614 #ifdef DEBUG
615     decode_version(hdr->eaccelerator_version[0], hdr->eaccelerator_version[1], cache, 255);
616     decode_version(binary_eaccelerator_version[0], binary_eaccelerator_version[1], current, 255);
617     ea_debug_printf(EA_DEBUG, "eAccelerator version mismatch, cache file %s and current version %s\n", cache, current);
618 #endif
619     return 0;
620   }
621   if (hdr->zend_version[0] != binary_zend_version[0]
622       || hdr->zend_version[1] != binary_zend_version[1]) {
623 #ifdef DEBUG
624     decode_version(hdr->zend_version[0], hdr->zend_version[1], cache, 255);
625     decode_version(binary_zend_version[0], binary_zend_version[1], current, 255);
626     ea_debug_printf(EA_DEBUG, "Zend version mismatch, cache file %s and current version %s\n", cache, current);
627 #endif
628     return 0;
629   }
630   if (hdr->php_version[0] != binary_php_version[0]
631       || hdr->php_version[1] != binary_php_version[1]) {
632 #ifdef DEBUG
633     decode_version(hdr->php_version[0], hdr->php_version[1], cache, 255);
634     decode_version(binary_php_version[0], binary_php_version[1], current, 255);
635     ea_debug_printf(EA_DEBUG, "PHP version mismatch, cache file %s and current version %s\n", cache, current);
636 #endif
637     return 0;
638   }
639   return 1;
640 }
641
642 /* A function to create the header for a cache file.
643  */
644 inline void init_header(ea_file_header *hdr)
645 {
646   strncpy(hdr->magic, EA_MAGIC, 8);
647   hdr->eaccelerator_version[0] = binary_eaccelerator_version[0];
648   hdr->eaccelerator_version[1] = binary_eaccelerator_version[1];
649   hdr->zend_version[0] = binary_zend_version[0];
650   hdr->zend_version[1] = binary_zend_version[1];
651   hdr->php_version[0] = binary_php_version[0]; 
652   hdr->php_version[1] = binary_php_version[1];
653 }
654 /* Retrieve a cache entry from the cache directory */
655 static ea_cache_entry* hash_find_file(const char  *key, struct stat *buf TSRMLS_DC) {
656   int f;
657   char s[MAXPATHLEN];
658   ea_file_header hdr;
659   ea_cache_entry *p;
660   int use_shm = 1;
661
662 #ifdef EACCELERATOR_USE_INODE
663   struct stat buf2;
664
665   if (!eaccelerator_inode_key(s, buf->st_dev, buf->st_ino TSRMLS_CC)) {
666     return NULL;
667   }
668 #else
669   if (!eaccelerator_md5(s, "/eaccelerator-", key TSRMLS_CC)) {
670     return NULL;
671   }
672 #endif
673
674   if ((f = open(s, O_RDONLY | O_BINARY)) > 0) {
675     EACCELERATOR_FLOCK(f, LOCK_SH);
676     if (read(f, &hdr, sizeof(hdr)) != sizeof(hdr)) {
677       EACCELERATOR_FLOCK(f, LOCK_UN);
678       close(f);
679       return NULL;
680     }
681     if (!check_header(&hdr)) {
682       EACCELERATOR_FLOCK(f, LOCK_UN);
683       close(f);
684       unlink(s);
685       return NULL;
686     }
687     p = eaccelerator_malloc(hdr.size);
688     if (p == NULL) {
689       p = eaccelerator_malloc2(hdr.size TSRMLS_CC);
690     }
691     if (p == NULL) {
692       p = emalloc(hdr.size);
693       use_shm = 0;
694     }
695     if (p == NULL) {
696       EACCELERATOR_FLOCK(f, LOCK_UN);
697       close(f);
698       return NULL;
699     }
700     if (read(f, p, hdr.size) != hdr.size ||
701         p->size != hdr.size ||
702         hdr.crc32 != eaccelerator_crc32((const char*)p,p->size)) {
703       EACCELERATOR_FLOCK(f, LOCK_UN);
704       close(f);
705       unlink(s);
706       if (use_shm) eaccelerator_free(p); else efree(p);
707                         DBG(ea_debug_printf, (EA_DEBUG, "cache file is corrupted\n"));
708       return NULL;
709     }
710     EACCELERATOR_FLOCK(f, LOCK_UN);
711     close(f);
712 #ifdef EACCELERATOR_USE_INODE
713     if (p->st_dev != buf->st_dev || p->st_ino != buf->st_ino) {
714 #else
715     if (strcmp(key,p->realfilename) != 0) {
716 #endif
717       if (use_shm) eaccelerator_free(p); else efree(p);
718       return NULL;
719     }
720     if ((eaccelerator_check_mtime &&
721         (buf->st_mtime != p->mtime || buf->st_size != p->filesize))
722 #ifdef EACCELERATOR_USE_INODE
723         ||
724         (strcmp(p->realfilename, key) != 0 &&
725          (stat(p->realfilename,&buf2) != 0 ||
726          buf2.st_dev != buf->st_dev ||
727          buf2.st_ino != buf->st_ino))
728 #endif
729        ) {
730       /* key is invalid. Remove it. */
731       if (use_shm) eaccelerator_free(p); else efree(p);
732       unlink(s);
733       return NULL;
734     }
735     eaccelerator_fixup(p TSRMLS_CC);
736     if (use_shm) {
737       p->nhits    = 1;
738       p->nreloads = 1;
739       p->use_cnt  = 1;
740       p->removed  = 0;
741       if (ea_shm_ttl > 0) {
742         p->ttl = EAG(req_start) + ea_shm_ttl;
743       } else {
744         p->ttl = 0;
745       }
746       hash_add_mm(p);
747     } else {
748       p->use_cnt  = 0;
749       p->removed  = 1;
750     }
751     mm_check_mem(p);
752     return p;
753   }
754   return NULL;
755 }
756
757 /* Add a cache entry to the cache directory */
758 static int hash_add_file(ea_cache_entry *p TSRMLS_DC) {
759   int f;
760   int ret = 0;
761   char s[MAXPATHLEN];
762   ea_file_header hdr;
763
764 #ifdef EACCELERATOR_USE_INODE
765   if (!eaccelerator_inode_key(s, p->st_dev, p->st_ino TSRMLS_CC)) {
766     return 0;
767   }
768 #else
769   if (!eaccelerator_md5(s, "/eaccelerator-", p->realfilename TSRMLS_CC)) {
770     return 0;
771   }
772 #endif
773
774   unlink(s);
775   f = open(s, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, S_IRUSR | S_IWUSR);
776   if (f > 0) {
777     EACCELERATOR_FLOCK(f, LOCK_EX);
778     init_header(&hdr);
779     hdr.size  = p->size;
780     hdr.mtime = p->mtime;
781     p->next = p;
782     hdr.crc32 = eaccelerator_crc32((const char*)p,p->size);
783     ret = (write(f, &hdr, sizeof(hdr)) == sizeof(hdr));
784     if (ret) ret = (write(f, p, p->size) == p->size);
785     EACCELERATOR_FLOCK(f, LOCK_UN);
786     close(f);
787   } else {
788     ea_debug_log("EACCELERATOR: Open for write failed for \"%s\": %s\n", s, strerror(errno));
789   }
790   return ret;
791 }
792
793 /* called after succesful compilation, from eaccelerator_compile file */
794 /* Adds the data from the compilation of the script to the cache */
795 static int eaccelerator_store(char* key, struct stat *buf, int nreloads,
796                          zend_op_array* op_array,
797                          Bucket* f, Bucket *c TSRMLS_DC) {
798   ea_cache_entry *p;
799   int len = strlen(key);
800   int use_shm = 1;
801   int ret = 0;
802   int size = 0;
803   void *data = NULL;
804
805   zend_try {
806     size = calc_size(key, op_array, f, c TSRMLS_CC);
807   } zend_catch {
808     size =  0;
809   } zend_end_try();
810   if (size == 0) {
811     return 0;
812   }
813
814   DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
815   DBG(ea_debug_printf, (EA_DEBUG, "[%d] eaccelerator_store:  returned %d, mm=%x\n", getpid(), size, eaccelerator_mm_instance->mm));
816  
817   EACCELERATOR_UNPROTECT();
818   EAG(mem) = eaccelerator_malloc(size);
819   data = EAG(mem);
820   if (EAG(mem) == NULL) {
821     EAG(mem) = eaccelerator_malloc2(size TSRMLS_CC);
822   }
823   if (!EAG(mem) && !eaccelerator_scripts_shm_only) {
824     EACCELERATOR_PROTECT();
825     EAG(mem) = emalloc(size);
826     use_shm = 0;
827   }
828   if (EAG(mem)) {
829     memset(EAG(mem), 0, size);
830                 p = (ea_cache_entry *)EAG(mem);
831     eaccelerator_store_int(p, key, len, op_array, f, c TSRMLS_CC);
832     p->mtime    = buf->st_mtime;
833     p->filesize = buf->st_size;
834     p->size     = size;
835     p->nreloads = nreloads;
836 #ifdef EACCELERATOR_USE_INODE
837     p->st_dev   = buf->st_dev;
838     p->st_ino   = buf->st_ino;
839 #endif
840     if (use_shm) {
841       if (ea_shm_ttl > 0) {
842         p->ttl = EAG(req_start) + ea_shm_ttl;
843       } else {
844         p->ttl = 0;
845       }
846       if (!eaccelerator_scripts_shm_only) {
847         hash_add_file(p TSRMLS_CC);
848       }
849       hash_add_mm(p);
850       EACCELERATOR_PROTECT();
851       ret = 1;
852       mm_check_mem(data);
853     } else {
854       ret =  hash_add_file(p TSRMLS_CC);
855       efree(p);
856     }
857   }
858   return ret;
859 }
860
861 /* Try to restore a file from the cache. If the file isn't found in memory, the
862    the disk cache is checked */
863 static zend_op_array* eaccelerator_restore(char *realname, struct stat *buf,
864                                       int *nreloads, time_t compile_time TSRMLS_DC) {
865   ea_cache_entry *p;
866   zend_op_array *op_array = NULL;
867
868   *nreloads = 1;
869   EACCELERATOR_UNPROTECT();
870   p = hash_find_mm(realname, buf, nreloads, ((ea_shm_ttl > 0)?(compile_time + ea_shm_ttl):0));
871   if (p == NULL && !eaccelerator_scripts_shm_only) {
872     p = hash_find_file(realname, buf TSRMLS_CC);
873   }
874   EACCELERATOR_PROTECT();
875   if (p != NULL && p->op_array != NULL) {
876     EAG(class_entry) = NULL;
877     op_array = restore_op_array(NULL, p->op_array TSRMLS_CC);
878     if (op_array != NULL) {
879       ea_fc_entry *e;
880       ea_used_entry *used = emalloc(sizeof(ea_used_entry));
881       used->entry  = p;
882       used->next   = (ea_used_entry*)EAG(used_entries);
883       EAG(used_entries) = (void*)used;
884       EAG(mem) = op_array->filename;
885                         /* only restore the classes and functions when we restore this script
886                          * for the first time.
887                          */
888       if (!zend_hash_exists(&EAG(restored), p->realfilename, strlen(p->realfilename))) {
889                                 for (e = p->c_head; e!=NULL; e = e->next) {
890           restore_class(e TSRMLS_CC);
891         }
892         for (e = p->f_head; e!=NULL; e = e->next) {
893           restore_function(e TSRMLS_CC);
894         }
895                                 zend_hash_add(&EAG(restored), p->realfilename, strlen(p->realfilename), NULL, 0, NULL); 
896                         }
897                         EAG(mem) = p->realfilename;
898     }
899   }
900   return op_array;
901 }
902
903
904 static int eaccelerator_stat(zend_file_handle *file_handle,
905                         char* realname, struct stat* buf TSRMLS_DC) {
906 #ifdef EACCELERATOR_USE_INODE
907 #ifndef ZEND_WIN32
908   if (file_handle->type == ZEND_HANDLE_FP && file_handle->handle.fp != NULL) {
909     if (fstat(fileno(file_handle->handle.fp), buf) == 0 && S_ISREG(buf->st_mode)) {
910       if (file_handle->opened_path != NULL) {
911         strcpy(realname, file_handle->opened_path);
912       }
913       return 0;
914     }
915   } else
916 #endif
917   if (file_handle->opened_path != NULL) {
918     if (stat(file_handle->opened_path, buf) == 0 && S_ISREG(buf->st_mode)) {
919        strcpy(realname,file_handle->opened_path);
920        return 0;
921     }
922   } else if (PG(include_path) == NULL ||
923                                  file_handle->filename[0] == '.' ||
924              IS_SLASH(file_handle->filename[0]) ||
925              IS_ABSOLUTE_PATH(file_handle->filename,strlen(file_handle->filename))) {
926     if (stat(file_handle->filename, buf) == 0 && S_ISREG(buf->st_mode)) {
927        return 0;
928     }
929   } else {
930     char* ptr = PG(include_path);
931     char* end;
932     int   len;
933     char  tryname[MAXPATHLEN];
934     int   filename_len = strlen(file_handle->filename);
935
936     while (ptr && *ptr) {
937       end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
938       if (end != NULL) {
939         len = end - ptr;
940         end++;
941       } else {
942         len = strlen(ptr);
943         end = ptr + len;
944       }
945       if (len + filename_len + 2 < MAXPATHLEN) {
946         memcpy(tryname, ptr, len);
947         tryname[len] = '/';
948         memcpy(tryname + len + 1, file_handle->filename, filename_len);
949         tryname[len + filename_len + 1] = '\0';
950         if (stat(tryname, buf) == 0 && S_ISREG(buf->st_mode)) {
951           return 0;
952         }
953       }
954       ptr = end;
955     }
956
957         if (zend_is_executing(TSRMLS_C)) {
958         int tryname_length;
959                 strncpy(tryname, zend_get_executed_filename(TSRMLS_C), MAXPATHLEN);
960                 tryname[MAXPATHLEN - 1] = 0;
961                 tryname_length = strlen(tryname);
962
963                 while (tryname_length >= 0 && !IS_SLASH(tryname[tryname_length])) {
964                         tryname_length--;
965                 }
966                 if (tryname_length > 0 && tryname[0] != '[' // [no active file]
967                         && tryname_length + filename_len + 1 < MAXPATHLEN)
968                 {
969                         strncpy(tryname + tryname_length + 1, file_handle->filename, filename_len + 1);
970                         if (stat(tryname, buf) == 0 && S_ISREG(buf->st_mode)) {
971                                 return 0;
972                         }
973                 }
974         }
975   }
976   return -1;
977 #else
978   if (file_handle->opened_path != NULL) {
979     strcpy(realname,file_handle->opened_path);
980 #ifndef ZEND_WIN32
981     if (file_handle->type == ZEND_HANDLE_FP && file_handle->handle.fp != NULL) {
982       if (!eaccelerator_check_mtime) {
983         return 0;
984       } else if (fstat(fileno(file_handle->handle.fp), buf) == 0 && S_ISREG(buf->st_mode)) {
985         return 0;
986       } else {
987         return -1;
988       }
989     } else {
990       if (!eaccelerator_check_mtime) {
991         return 0;
992       } else if (stat(realname, buf) == 0 && S_ISREG(buf->st_mode)) {
993         return 0;
994       } else {
995         return -1;
996       }
997     }
998 #else
999     if (!eaccelerator_check_mtime) {
1000       return 0;
1001     } else if (stat(realname, buf) == 0 && S_ISREG(buf->st_mode)) {
1002       return 0;
1003     } else {
1004       return -1;
1005     }
1006 #endif
1007   } else if (file_handle->filename == NULL) {
1008     return -1;
1009   } else if (PG(include_path) == NULL ||
1010              file_handle->filename[0] == '.' ||
1011              IS_SLASH(file_handle->filename[0]) ||
1012              IS_ABSOLUTE_PATH(file_handle->filename,strlen(file_handle->filename))) {
1013     if (VCWD_REALPATH(file_handle->filename, realname)) {
1014       if (!eaccelerator_check_mtime) {
1015         return 0;
1016       } else if (stat(realname, buf) == 0 && S_ISREG(buf->st_mode)) {
1017         return 0;
1018       } else {
1019         return -1;
1020       }
1021     }
1022   } else {
1023     char* ptr = PG(include_path);
1024     char* end;
1025     int   len;
1026     char  tryname[MAXPATHLEN];
1027     int   filename_len = strlen(file_handle->filename);
1028
1029     while (ptr && *ptr) {
1030       end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
1031       if (end != NULL) {
1032         len = end - ptr;
1033         end++;
1034       } else {
1035         len = strlen(ptr);
1036         end = ptr + len;
1037       }
1038       if (len+filename_len+2 < MAXPATHLEN) {
1039         memcpy(tryname, ptr, len);
1040         tryname[len] = '/';
1041         memcpy(tryname + len + 1, file_handle->filename, filename_len);
1042         tryname[len + filename_len + 1] = '\0';
1043         if (VCWD_REALPATH(tryname, realname)) {
1044 #ifdef ZEND_WIN32
1045           if (stat(realname, buf) == 0 && S_ISREG(buf->st_mode)) {
1046             return 0;
1047           }
1048 #else
1049           if (!eaccelerator_check_mtime) {
1050             return 0;
1051           } else if (stat(realname, buf) == 0 && S_ISREG(buf->st_mode)) {
1052             return 0;
1053           } else {
1054             return -1;
1055           }
1056 #endif
1057         }
1058       }
1059       ptr = end;
1060     }
1061   }
1062   return -1;
1063 #endif
1064 }
1065
1066 static int ea_match(struct ea_pattern_t *list, const char *path)
1067 {
1068         struct ea_pattern_t *p;
1069         char result, positive;
1070
1071         // apply all patterns
1072         //  - when not patterns are given, *accept*
1073         //  - when a pattern with a ! matches, *reject*
1074         //  - when no negative pattern matches and a positive pattern match, *accept*
1075         //  - when no negative pattern matches and there are no possitive patterns, *accept*
1076         //  - *reject*
1077
1078         if (list == NULL) {
1079                 // there are no patterns, accept
1080                 return 1;
1081         }
1082
1083         result = 0; // there are patterns, so if no positive pattern matches, reject
1084         positive = 0;
1085         p = list;
1086         while (p != NULL) {
1087                 if (p->pattern[0] == '!') {
1088                   if ((fnmatch((const char *)(p->pattern + 1), path, 0) == 0)) {
1089                                 // a negative pattern matches, accept
1090                                 return 0;
1091                         }
1092                 } else {
1093                         result |= (fnmatch((const char *)p->pattern, path, 0) == 0);
1094                         positive = 1;
1095                 }
1096                 p = p->next;
1097         }
1098
1099   return result | !positive;
1100 }
1101
1102 /*
1103  * Intercept compilation of PHP file.  If we already have the file in
1104  * our cache, restore it.  Otherwise call the original Zend compilation
1105  * function and store the compiled zend_op_array in out cache.
1106  * This function is called again for each PHP file included in the
1107  * main PHP file.
1108  */
1109 ZEND_DLEXPORT zend_op_array* eaccelerator_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) {
1110   zend_op_array *t;
1111   struct stat buf;
1112   char  realname[MAXPATHLEN];
1113   int   nreloads;
1114   time_t compile_time;
1115   int stat_result = 0;
1116 #ifdef DEBUG
1117   struct timeval tv_start;
1118 #endif
1119   int ok_to_cache = 0;
1120
1121 #ifdef EACCELERATOR_USE_INODE
1122   realname[0] = '\000';
1123 #endif
1124
1125   DBG(ea_debug_start_time, (&tv_start));
1126   DBG(ea_debug_printf, (EA_DEBUG, "[%d] Enter COMPILE\n",getpid()));
1127   DBG(ea_debug_printf, (EA_DEBUG, "[%d] compile_file: \"%s\"\n",getpid(), file_handle->filename));
1128 #ifdef DEBUG
1129   EAG(xpad)+=2;
1130 #endif
1131
1132   stat_result = eaccelerator_stat(file_handle, realname, &buf TSRMLS_CC);
1133
1134   ok_to_cache = ea_match(EAG(pattern_list), file_handle->filename);
1135
1136   // eAccelerator isn't working, so just compile the file
1137   if (!EAG(enabled) || (eaccelerator_mm_instance == NULL) ||
1138       !eaccelerator_mm_instance->enabled || file_handle == NULL ||
1139       file_handle->filename == NULL || stat_result != 0 || !ok_to_cache) {
1140     DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] compile_file: compiling\n", getpid()));
1141     t = mm_saved_zend_compile_file(file_handle, type TSRMLS_CC);
1142     DBG(ea_debug_printf, (EA_TEST_PERFORMANCE, "\t[%d] compile_file: end (%ld)\n", getpid(), ea_debug_elapsed_time(&tv_start)));
1143     DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] compile_file: end\n", getpid()));
1144 #ifdef DEBUG
1145     EAG(xpad)-=2;
1146 #endif
1147     DBG(ea_debug_printf, (EA_DEBUG, "[%d] Leave COMPILE\n", getpid()));
1148     return t;
1149   }
1150
1151   /* only restore file when open_basedir allows it */
1152   if (php_check_open_basedir(file_handle->filename TSRMLS_CC)) {
1153     zend_error(E_ERROR, "Can't load %s, open_basedir restriction.", file_handle->filename);
1154   }
1155
1156   compile_time = EAG(req_start);
1157   if (buf.st_mtime >= compile_time && eaccelerator_debug > 0) {
1158         ea_debug_log("EACCELERATOR: Warning: \"%s\" is cached but it's mtime is in the future.\n", file_handle->filename);
1159   }
1160
1161   t = eaccelerator_restore(realname, &buf, &nreloads, compile_time TSRMLS_CC);
1162
1163 // segv74: really cheap work around to auto_global problem.
1164 //         it makes just in time to every time.
1165 #ifdef ZEND_ENGINE_2
1166   zend_is_auto_global("_GET", sizeof("_GET")-1 TSRMLS_CC);
1167   zend_is_auto_global("_POST", sizeof("_POST")-1 TSRMLS_CC);
1168   zend_is_auto_global("_COOKIE", sizeof("_COOKIE")-1 TSRMLS_CC);
1169   zend_is_auto_global("_SERVER", sizeof("_SERVER")-1 TSRMLS_CC);
1170   zend_is_auto_global("_ENV", sizeof("_ENV")-1 TSRMLS_CC);
1171   zen