root/eaccelerator/trunk/eaccelerator.c

Revision 348, 79.7 kB (checked in by bart, 1 month ago)

First stab at php 5.3 support. Only fixes the script cache. phpMyAdmin seems to work with these changes.

  • 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 /* pointer to the properties_info hashtable destructor */
105 extern dtor_func_t properties_info_dtor;
106
107 /* saved original functions */
108 static zend_op_array *(*ea_saved_zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
109
110 #ifdef DEBUG
111 static void (*ea_saved_zend_execute)(zend_op_array *op_array TSRMLS_DC);
112 #endif
113
114 /* external declarations */
115 PHPAPI void php_stripslashes(char *str, int *len TSRMLS_DC);
116
117 ZEND_DLEXPORT zend_op_array* eaccelerator_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC);
118
119 /******************************************************************************/
120 /* hash mm functions                                                          */
121 /******************************************************************************/
122
123 /* Find a script entry with the given hash key */
124 static ea_cache_entry* hash_find_mm(const char  *key,
125                                     struct stat *buf,
126                                     int         *nreloads,
127                                     time_t      ttl) {
128   unsigned int hv, slot;
129   ea_cache_entry *p, *q;
130
131 #ifdef EACCELERATOR_USE_INODE
132   hv = buf->st_dev + buf->st_ino;
133 #else
134   hv = zend_get_hash_value((char *)key, strlen(key));
135 #endif
136   slot = hv & EA_HASH_MAX;
137
138   EACCELERATOR_LOCK_RW();
139   q = NULL;
140   p = eaccelerator_mm_instance->hash[slot];
141   while (p != NULL) {
142 #ifdef EACCELERATOR_USE_INODE
143     if (p->st_dev == buf->st_dev && p->st_ino == buf->st_ino) {
144       struct stat buf2;
145       if ((eaccelerator_check_mtime &&
146           (buf->st_mtime != p->mtime || buf->st_size != p->filesize)) ||
147           (strcmp(p->realfilename, key) != 0 &&
148            (stat(p->realfilename,&buf2) != 0 ||
149            buf2.st_dev != buf->st_dev ||
150            buf2.st_ino != buf->st_ino))) {
151 #else
152     if ((p->hv == hv) && (strcmp(p->realfilename, key) == 0)) {
153       if (eaccelerator_check_mtime &&
154           (buf->st_mtime != p->mtime || buf->st_size != p->filesize)) {
155 #endif
156         /* key is invalid. Remove it. */
157         *nreloads = p->nreloads+1;
158         if (q == NULL) {
159           eaccelerator_mm_instance->hash[slot] = p->next;
160         } else {
161           q->next = p->next;
162         }
163         eaccelerator_mm_instance->hash_cnt--;
164         if (p->use_cnt > 0) {
165           /* key is used by other process/thread. Shedule it for removal */
166           p->removed = 1;
167           p->next = eaccelerator_mm_instance->removed;
168           eaccelerator_mm_instance->removed = p;
169           eaccelerator_mm_instance->rem_cnt++;
170           EACCELERATOR_UNLOCK_RW();
171           return NULL;
172         } else {
173           /* key is unused. Remove it. */
174           eaccelerator_free_nolock(p);
175           EACCELERATOR_UNLOCK_RW();
176           return NULL;
177         }
178       } else {
179         /* key is valid */
180         p->nhits++;
181         p->use_cnt++;
182         p->ttl = ttl;
183         EACCELERATOR_UNLOCK_RW();
184         return p;
185       }
186     }
187     q = p;
188     p = p->next;
189   }
190   EACCELERATOR_UNLOCK_RW();
191   return NULL;
192 }
193
194 /* Add a new entry to the hashtable */
195 static void hash_add_mm(ea_cache_entry *x) {
196   ea_cache_entry *p,*q;
197   unsigned int slot;
198 #ifdef EACCELERATOR_USE_INODE
199   slot = (x->st_dev + x->st_ino) & EA_HASH_MAX;
200 #else
201   x->hv = zend_get_hash_value(x->realfilename, strlen(x->realfilename));
202   slot = x->hv & EA_HASH_MAX;
203 #endif
204
205   EACCELERATOR_LOCK_RW();
206   x->next = eaccelerator_mm_instance->hash[slot];
207   eaccelerator_mm_instance->hash[slot] = x;
208   eaccelerator_mm_instance->hash_cnt++;
209   q = x;
210   p = x->next;
211   while (p != NULL) {
212 #ifdef EACCELERATOR_USE_INODE
213     if ((p->st_dev == x->st_dev) && (p->st_ino == x->st_ino)) {
214 #else
215     if ((p->hv == x->hv) &&
216         (strcmp(p->realfilename, x->realfilename) == 0)) {
217 #endif
218       q->next = p->next;
219       eaccelerator_mm_instance->hash_cnt--;
220       eaccelerator_mm_instance->hash[slot]->nreloads += p->nreloads;
221       if (p->use_cnt > 0) {
222         /* key is used by other process/thread. Shedule it to remove */
223         p->removed = 1;
224         p->next = eaccelerator_mm_instance->removed;
225         eaccelerator_mm_instance->removed = p;
226         eaccelerator_mm_instance->rem_cnt++;
227         EACCELERATOR_UNLOCK_RW();
228         return;
229       } else {
230         /* key is unused. Remove it. */
231         eaccelerator_free_nolock(p);
232         EACCELERATOR_UNLOCK_RW();
233         return;
234       }
235     }
236     q = p;
237     p = p->next;
238   }
239   EACCELERATOR_UNLOCK_RW();
240 }
241
242 /* Initialise the shared memory */
243 static int init_mm(TSRMLS_D) {
244   pid_t  owner = getpid();
245   MM     *mm;
246   size_t total;
247   char   mm_path[MAXPATHLEN];
248
249 #ifdef ZEND_WIN32
250     snprintf(mm_path, MAXPATHLEN, "%s.%s", EACCELERATOR_MM_FILE, sapi_module.name);
251 #else
252     snprintf(mm_path, MAXPATHLEN, "%s.%s%d", EACCELERATOR_MM_FILE, sapi_module.name, owner);
253 #endif
254 /*  snprintf(mm_path, MAXPATHLEN, "%s.%s%d", EACCELERATOR_MM_FILE, sapi_module.name, geteuid());*/
255   if ((eaccelerator_mm_instance = (eaccelerator_mm*)mm_attach(ea_shm_size*1024*1024, mm_path)) != NULL) {
256 #ifdef ZTS
257     ea_mutex = tsrm_mutex_alloc();
258 #endif
259     return SUCCESS;
260   }
261   mm = mm_create(ea_shm_size*1024*1024, mm_path);
262   if (!mm) {
263     return FAILURE;
264   }
265 #ifdef ZEND_WIN32
266   DBG(ea_debug_printf, (EA_DEBUG, "init_mm [%d]\n", owner));
267 #else
268   DBG(ea_debug_printf, (EA_DEBUG, "init_mm [%d,%d]\n", owner, getppid()));
269 #endif
270 #ifdef ZTS
271   ea_mutex = tsrm_mutex_alloc();
272 #endif
273   total = mm_available(mm);
274   eaccelerator_mm_instance = mm_malloc_lock(mm, sizeof(*eaccelerator_mm_instance));
275   if (!eaccelerator_mm_instance) {
276     return FAILURE;
277   }
278   mm_set_attach(mm, eaccelerator_mm_instance);
279   memset(eaccelerator_mm_instance, 0, sizeof(*eaccelerator_mm_instance));
280   eaccelerator_mm_instance->owner = owner;
281   eaccelerator_mm_instance->mm    = mm;
282   eaccelerator_mm_instance->total = total;
283   eaccelerator_mm_instance->hash_cnt = 0;
284   eaccelerator_mm_instance->rem_cnt  = 0;
285   eaccelerator_mm_instance->enabled = 1;
286   eaccelerator_mm_instance->optimizer_enabled = 1;
287   eaccelerator_mm_instance->removed = NULL;
288   eaccelerator_mm_instance->locks = NULL;
289   eaccelerator_mm_instance->user_hash_cnt = 0;
290   eaccelerator_mm_instance->last_prune = time(NULL);    /* this time() call is harmless since this is init phase */
291   EACCELERATOR_PROTECT();
292   return SUCCESS;
293 }
294
295 /* Clean up the shared memory */
296 static void shutdown_mm(TSRMLS_D) {
297   if (eaccelerator_mm_instance) {
298 #ifdef ZEND_WIN32
299     if (eaccelerator_mm_instance->owner == getpid()) {
300 #else
301     if (getpgrp() == getpid()) {
302 #endif
303       MM *mm = eaccelerator_mm_instance->mm;
304 #ifdef ZEND_WIN32
305       DBG(ea_debug_printf, (EA_DEBUG, "shutdown_mm [%d]\n", getpid()));
306 #else
307       DBG(ea_debug_printf, (EA_DEBUG, "shutdown_mm [%d,%d]\n", getpid(), getppid()));
308 #endif
309 #ifdef ZTS
310       tsrm_mutex_free(ea_mutex);
311 #endif
312       if (mm) {
313         mm_destroy(mm);
314       }
315       eaccelerator_mm_instance = NULL;
316     }
317   }
318 }
319
320 void encode_version(const char *str, int *version, int *extra)
321 {
322     unsigned int a = 0;
323     unsigned int b = 0;
324     unsigned int c = 0;
325     unsigned int d = 0;
326     size_t len;
327     char s[255];
328     char buf[255];
329
330     len = strlen(str);
331     memcpy(buf, str, (len > 255) ? 255 : len);
332     buf[254] = '\0';
333
334     memset(s, 0, 255);
335     sscanf(str, "%u.%u.%u%s", &a, &b, &c, s);
336
337     if (s[0] == '.') {
338         sscanf(s, ".%u-%s", &d, buf);
339     } else if (s[0] == '-') {
340         memcpy(buf, &s[1], 254);
341     } else {
342         memcpy(buf, s, 255);
343     }
344
345     *version = ((a & 0xff) << 24) | ((b & 0xff) << 16) | ((c & 0xff) << 8) | (d & 0xff);
346
347     if (buf[0] == 0) {
348         a = 0;
349         b = 0;
350     } else if (strncasecmp(buf, "rev", 3) == 0) {
351         a = 1;
352         sscanf(buf, "rev%u", &b);
353     } else if (strncasecmp(buf, "rc", 2) == 0) {
354         a = 2;
355         sscanf(buf, "rc%u", &b);
356     } else if (strncasecmp(buf, "beta", 4) == 0) {
357         a = 3;
358         sscanf(buf, "beta%u", &b);
359     } else {
360         a = 0xf;
361         // just encode the first 4 bytes
362         b = ((buf[0] & 0x7f) << 21) | ((buf[1] & 0x7f) << 14) | ((buf[2] & 0x7f) << 7) | (buf[3] & 0x7f);
363     }
364
365     *extra = ((a & 0xf) << 28) | (0x0fffffff & b);
366 }
367
368 #ifdef DEBUG
369 static void decode_version(int version, int extra, char *str, size_t len)
370 {
371     int number;
372
373     if ((version & 0xff) == 0) {
374         number = snprintf(str, len, "%u.%u.%u", (version >> 24), ((version >> 16) & 0xff), ((version >> 8) & 0xff));
375     } else {
376         number = snprintf(str, len, "%u.%u.%u.%u", (version >> 24), ((version >> 16) & 0xff), ((version >> 8) & 0xff), (version & 0xff));
377     }
378
379     if (extra != 0) {
380         unsigned int type = ((extra >> 28) & 0xf);
381         extra = (extra & 0x0fffffff);
382         switch (type) {
383             case 1:
384                 snprintf(&str[number], len, "-rev%u", extra);
385                 break;
386             case 2:
387                 snprintf(&str[number], len, "-rc%u", extra);
388                 break;
389             case 3:
390                 snprintf(&str[number], len, "-beta%u", extra);
391                 break;
392             case 15:
393                 if ((int)len >= number + 5) {
394                     str[number] = '-';
395                     str[number + 1] = (extra >> 21) & 0x7f;
396                     str[number + 2] = (extra >> 14) & 0x7f;
397                     str[number + 3] = (extra >> 7) & 0x7f;
398                     str[number + 4] = extra & 0x7f;
399                     str[number + 5] = '\0';
400                 }
401                 break;
402             default:
403                 break;
404         }
405     }
406 }
407 #endif
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       p->ts       = hdr.ts;     /* get cached item creation timestamp from cache file */
747       hash_add_mm(p);
748     } else {
749       p->use_cnt  = 0;
750       p->removed  = 1;
751     }
752     mm_check_mem(p);
753     return p;
754   }
755   return NULL;
756 }
757
758 /* Add a cache entry to the cache directory */
759 static int hash_add_file(ea_cache_entry *p TSRMLS_DC) {
760   int f;
761   int ret = 0;
762   char s[MAXPATHLEN];
763   ea_file_header hdr;
764
765 #ifdef EACCELERATOR_USE_INODE
766   if (!eaccelerator_inode_key(s, p->st_dev, p->st_ino TSRMLS_CC)) {
767     return 0;
768   }
769 #else
770   if (!eaccelerator_md5(s, "/eaccelerator-", p->realfilename TSRMLS_CC)) {
771     return 0;
772   }
773 #endif
774
775   unlink(s);
776   f = open(s, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, S_IRUSR | S_IWUSR);
777   if (f > 0) {
778     EACCELERATOR_FLOCK(f, LOCK_EX);
779     init_header(&hdr);
780     hdr.size  = p->size;
781     hdr.mtime = p->mtime;
782     hdr.ts    = p->ts;
783     p->next = p;
784     hdr.crc32 = eaccelerator_crc32((const char*)p,p->size);
785     ret = (write(f, &hdr, sizeof(hdr)) == sizeof(hdr));
786     if (ret) ret = (write(f, p, p->size) == p->size);
787     EACCELERATOR_FLOCK(f, LOCK_UN);
788     close(f);
789   } else {
790     ea_debug_log("EACCELERATOR: Open for write failed for \"%s\": %s\n", s, strerror(errno));
791   }
792   return ret;
793 }
794
795 /* called after succesful compilation, from eaccelerator_compile file */
796 /* Adds the data from the compilation of the script to the cache */
797 static int eaccelerator_store(char* key, struct stat *buf, int nreloads,
798                          zend_op_array* op_array,
799                          Bucket* f, Bucket *c TSRMLS_DC) {
800   ea_cache_entry *p;
801   int len = strlen(key);
802   int use_shm = 1;
803   int ret = 0;
804   int size = 0;
805   void *data = NULL;
806
807   zend_try {
808     size = calc_size(key, op_array, f, c TSRMLS_CC);
809   } zend_catch {
810     size =  0;
811   } zend_end_try();
812   if (size == 0) {
813     return 0;
814   }
815
816   DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
817   DBG(ea_debug_printf, (EA_DEBUG, "[%d] eaccelerator_store:  returned %d, mm=%x\n", getpid(), size, eaccelerator_mm_instance->mm));
818  
819   EACCELERATOR_UNPROTECT();
820   EAG(mem) = eaccelerator_malloc(size);
821   data = EAG(mem);
822   if (EAG(mem) == NULL) {
823     EAG(mem) = eaccelerator_malloc2(size TSRMLS_CC);
824   }
825   if (!EAG(mem) && !eaccelerator_scripts_shm_only) {
826     EACCELERATOR_PROTECT();
827     EAG(mem) = emalloc(size);
828     use_shm = 0;
829   }
830   if (EAG(mem)) {
831     memset(EAG(mem), 0, size);
832                 p = (ea_cache_entry *)EAG(mem);
833     eaccelerator_store_int(p, key, len, op_array, f, c TSRMLS_CC);
834     p->mtime    = buf->st_mtime;
835     p->ts       = EAG(req_start);
836     p->filesize = buf->st_size;
837     p->size     = size;
838     p->nreloads = nreloads;
839 #ifdef EACCELERATOR_USE_INODE
840     p->st_dev   = buf->st_dev;
841     p->st_ino   = buf->st_ino;
842 #endif
843     if (use_shm) {
844       if (ea_shm_ttl > 0) {
845         p->ttl = EAG(req_start) + ea_shm_ttl;
846       } else {
847         p->ttl = 0;
848       }
849       if (!eaccelerator_scripts_shm_only) {
850         hash_add_file(p TSRMLS_CC);
851       }
852       hash_add_mm(p);
853       EACCELERATOR_PROTECT();
854       ret = 1;
855       mm_check_mem(data);
856     } else {
857       ret =  hash_add_file(p TSRMLS_CC);
858       efree(p);
859     }
860   }
861   return ret;
862 }
863
864 /* Try to restore a file from the cache. If the file isn't found in memory, the
865    the disk cache is checked */
866 static zend_op_array* eaccelerator_restore(char *realname, struct stat *buf,
867                                       int *nreloads, time_t compile_time TSRMLS_DC) {
868   ea_cache_entry *p;
869   zend_op_array *op_array = NULL;
870
871   *nreloads = 1;
872   EACCELERATOR_UNPROTECT();
873   p = hash_find_mm(realname, buf, nreloads, ((ea_shm_ttl > 0)?(compile_time + ea_shm_ttl):0));
874   if (p == NULL && !eaccelerator_scripts_shm_only) {
875     p = hash_find_file(realname, buf TSRMLS_CC);
876   }
877   EACCELERATOR_PROTECT();
878   if (p != NULL && p->op_array != NULL) {
879     EAG(class_entry) = NULL;
880     op_array = restore_op_array(NULL, p->op_array TSRMLS_CC);
881     if (op_array != NULL) {
882       ea_fc_entry *e;
883       ea_used_entry *used = emalloc(sizeof(ea_used_entry));
884       used->entry  = p;
885       used->next   = (ea_used_entry*)EAG(used_entries);
886       EAG(used_entries) = (void*)used;
887       EAG(mem) = op_array->filename;
888                         /* only restore the classes and functions when we restore this script
889                          * for the first time.
890                          */
891       if (!zend_hash_exists(&EAG(restored), p->realfilename, strlen(p->realfilename))) {
892                                 for (e = p->c_head; e!=NULL; e = e->next) {
893           restore_class(e TSRMLS_CC);
894         }
895         for (e = p->f_head; e!=NULL; e = e->next) {
896           restore_function(e TSRMLS_CC);
897         }
898                                 zend_hash_add(&EAG(restored), p->realfilename, strlen(p->realfilename), NULL, 0, NULL); 
899                         }
900                         EAG(mem) = p->realfilename;
901     }
902   }
903   return op_array;
904 }
905
906
907 static int eaccelerator_stat(zend_file_handle *file_handle,
908                         char* realname, struct stat* buf TSRMLS_DC) {
909 #ifdef EACCELERATOR_USE_INODE
910 #ifndef ZEND_WIN32
911   if (file_handle->type == ZEND_HANDLE_FP && file_handle->handle.fp != NULL) {
912     if (fstat(fileno(file_handle->handle.fp), buf) == 0 && S_ISREG(buf->st_mode)) {
913       if (file_handle->opened_path != NULL) {
914         strcpy(realname, file_handle->opened_path);
915       }
916       return 0;
917     }
918   } else
919 #endif
920   if (file_handle->opened_path != NULL) {
921     if (stat(file_handle->opened_path, buf) == 0 && S_ISREG(buf->st_mode)) {
922        strcpy(realname,file_handle->opened_path);
923        return 0;
924     }
925   } else if (PG(include_path) == NULL ||
926                                  file_handle->filename[0] == '.' ||
927              IS_SLASH(file_handle->filename[0]) ||
928              IS_ABSOLUTE_PATH(file_handle->filename,strlen(file_handle->filename))) {
929     if (stat(file_handle->filename, buf) == 0 && S_ISREG(buf->st_mode)) {
930        return 0;
931     }
932   } else {
933     char* ptr = PG(include_path);
934     char* end;
935     int   len;
936     char  tryname[MAXPATHLEN];
937     int   filename_len = strlen(file_handle->filename);
938
939     while (ptr && *ptr) {
940       end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
941       if (end != NULL) {
942         len = end - ptr;
943         end++;
944       } else {
945         len = strlen(ptr);
946         end = ptr + len;
947       }
948       if (len + filename_len + 2 < MAXPATHLEN) {
949         memcpy(tryname, ptr, len);
950         tryname[len] = '/';
951         memcpy(tryname + len + 1, file_handle->filename, filename_len);
952         tryname[len + filename_len + 1] = '\0';
953         if (stat(tryname, buf) == 0 && S_ISREG(buf->st_mode)) {
954           return 0;
955         }
956       }
957       ptr = end;
958     }
959
960         if (zend_is_executing(TSRMLS_C)) {
961         int tryname_length;
962                 strncpy(tryname, zend_get_executed_filename(TSRMLS_C), MAXPATHLEN);
963                 tryname[MAXPATHLEN - 1] = 0;
964                 tryname_length = strlen(tryname);
965
966                 while (tryname_length >= 0 && !IS_SLASH(tryname[tryname_length])) {
967                         tryname_length--;
968                 }
969                 if (tryname_length > 0 && tryname[0] != '[' // [no active file]
970                         && tryname_length + filename_len + 1 < MAXPATHLEN)
971                 {
972                         strncpy(tryname + tryname_length + 1, file_handle->filename, filename_len + 1);
973                         if (stat(tryname, buf) == 0 && S_ISREG(buf->st_mode)) {
974                                 return 0;
975                         }
976                 }
977         }
978   }
979   return -1;
980 #else
981   if (file_handle->opened_path != NULL) {
982     strcpy(realname,file_handle->opened_path);
983 #ifndef ZEND_WIN32
984     if (file_handle->type == ZEND_HANDLE_FP && file_handle->handle.fp != NULL) {
985       if (!eaccelerator_check_mtime) {
986         return 0;
987       } else if (fstat(fileno(file_handle->handle.fp), buf) == 0 && S_ISREG(buf->st_mode)) {
988         return 0;
989       } else {
990         return -1;
991       }
992     } else {
993       if (!eaccelerator_check_mtime) {
994         return 0;
995       } else if (stat(realname, buf) == 0 && S_ISREG(buf->st_mode)) {
996         return 0;
997       } else {
998         return -1;
999       }
1000     }
1001 #else
1002     if (!eaccelerator_check_mtime) {
1003       return 0;
1004     } else if (stat(realname, buf) == 0 && S_ISREG(buf->st_mode)) {
1005       return 0;
1006     } else {
1007       return -1;
1008     }
1009 #endif
1010   } else if (file_handle->filename == NULL) {
1011     return -1;
1012   } else if (PG(include_path) == NULL ||
1013              file_handle->filename[0] == '.' ||
1014              IS_SLASH(file_handle->filename[0]) ||
1015              IS_ABSOLUTE_PATH(file_handle->filename,strlen(file_handle->filename))) {
1016     if (VCWD_REALPATH(file_handle->filename, realname)) {
1017       if (!eaccelerator_check_mtime) {
1018         return 0;
1019       } else if (stat(realname, buf) == 0 && S_ISREG(buf->st_mode)) {
1020         return 0;
1021       } else {
1022         return -1;
1023       }
1024     }
1025   } else {
1026     char* ptr = PG(include_path);
1027     char* end;
1028     int   len;
1029     char  tryname[MAXPATHLEN];
1030     int   filename_len = strlen(file_handle->filename);
1031
1032     while (ptr && *ptr) {
1033       end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
1034       if (end != NULL) {
1035         len = end - ptr;
1036         end++;
1037       } else {
1038         len = strlen(ptr);
1039         end = ptr + len;
1040       }
1041       if (len+filename_len+2 < MAXPATHLEN) {
1042         memcpy(tryname, ptr, len);
1043         tryname[len] = '/';
1044         memcpy(tryname + len + 1, file_handle->filename, filename_len);
1045         tryname[len + filename_len + 1] = '\0';
1046         if (VCWD_REALPATH(tryname, realname)) {
1047 #ifdef ZEND_WIN32
1048           if (stat(realname, buf) == 0 && S_ISREG(buf->st_mode)) {
1049             return 0;
1050           }
1051 #else
1052           if (!eaccelerator_check_mtime) {
1053             return 0;
1054           } else if (stat(realname, buf) == 0 && S_ISREG(buf->st_mode)) {
1055             return 0;
1056           } else {
1057             return -1;
1058           }
1059 #endif
1060         }
1061       }
1062       ptr = end;
1063     }
1064   }
1065   return -1;
1066 #endif
1067 }
1068
1069 static int ea_match(struct ea_pattern_t *list, const char *path)
1070 {
1071         struct ea_pattern_t *p;
1072         char result, positive;
1073
1074         // apply all patterns
1075         //  - when not patterns are given, *accept*
1076         //  - when a pattern with a ! matches, *reject*
1077         //  - when no negative pattern matches and a positive pattern match, *accept*
1078         //  - when no negative pattern matches and there are no possitive patterns, *accept*
1079         //  - *reject*
1080
1081         if (list == NULL) {
1082                 // there are no patterns, accept
1083                 return 1;
1084         }
1085
1086         result = 0; // there are patterns, so if no positive pattern matches, reject
1087         positive = 0;
1088         p = list;
1089         while (p != NULL) {
1090                 if (p->pattern[0] == '!') {
1091                   if ((fnmatch((const char *)(p->pattern + 1), path, 0) == 0)) {
1092                                 // a negative pattern matches, accept
1093                                 return 0;
1094                         }
1095                 } else {
1096                         result |= (fnmatch((const char *)p->pattern, path, 0) == 0);
1097                         positive = 1;
1098                 }
1099                 p = p->next;
1100         }
1101
1102   return result | !positive;
1103 }
1104
1105 /* copy of zend_class_add_ref, the linker isn't able to link to it any more
1106  * in php 5.3
1107  * TODO: see if we can steal the pointer
1108  */
1109 void ea_class_add_ref(zend_class_entry **ce)
1110 {
1111             (*ce)->refcount++;
1112 }
1113
1114 /*
1115  * Intercept compilation of PHP file.  If we already have the file in
1116  * our cache, restore it.  Otherwise call the original Zend compilation
1117  * function and store the compiled zend_op_array in out cache.
1118  * This function is called again for each PHP file included in the
1119  * main PHP file.
1120  */
1121 ZEND_DLEXPORT zend_op_array* eaccelerator_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) {
1122   zend_op_array *t;
1123   struct stat buf;
1124   char  realname[MAXPATHLEN];
1125   int   nreloads;
1126   int stat_result = 0;
1127 #ifdef DEBUG
1128   struct timeval tv_start;
1129 #endif
1130   int ok_to_cache = 0;
1131
1132 #ifdef EACCELERATOR_USE_INODE
1133   realname[0] = '\000';
1134 #endif
1135
1136   DBG(ea_debug_start_time, (&tv_start));
1137   DBG(ea_debug_printf, (EA_DEBUG, "[%d] Enter COMPILE\n",getpid()));
1138   DBG(ea_debug_printf, (EA_DEBUG, "[%d] compile_file: \"%s\"\n",getpid(), file_handle->filename));
1139 #ifdef DEBUG
1140   EAG(xpad)+=2;
1141 #endif
1142
1143   stat_result = eaccelerator_stat(file_handle, realname, &buf TSRMLS_CC);
1144
1145   ok_to_cache = ea_match(EAG(pattern_list), file_handle->filename);
1146
1147   // eAccelerator isn't working, so just compile the file
1148   if (!EAG(enabled) || (eaccelerator_mm_instance == NULL) ||
1149       !eaccelerator_mm_instance->enabled || file_handle == NULL ||
1150       file_handle->filename == NULL || stat_result != 0 || !ok_to_cache) {
1151     DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] compile_file: compiling\n", getpid()));
1152     t = ea_saved_zend_compile_file(file_handle, type TSRMLS_CC);
1153     DBG(ea_debug_printf, (EA_TEST_PERFORMANCE, "\t[%d] compile_file: end (%ld)\n", getpid(), ea_debug_elapsed_time(&tv_start)));
1154     DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] compile_file: end\n", getpid()));
1155 #ifdef DEBUG
1156     EAG(xpad)-=2;
1157 #endif
1158     DBG(ea_debug_printf, (EA_DEBUG, "[%d] Leave COMPILE\n", getpid()));
1159     return t;
1160   }
1161
1162   /* only restore file when open_basedir allows it */
1163   if (php_check_open_basedir(file_handle->filename TSRMLS_CC)) {
1164     zend_error(E_ERROR, "Can't load %s, open_basedir restriction.", file_handle->filename);
1165   }
1166
1167   if (buf.st_mtime >= EAG(req_start) && eaccelerator_debug > 0) {
1168         ea_debug_log("EACCELERATOR: Warning: \"%s\" is cached but it's mtime is in the future.\n", file_handle->filename);
1169   }
1170
1171   t = eaccelerator_restore(realname, &buf, &nreloads, EAG(req_start) TSRMLS_CC);
1172
1173 // segv74: really cheap work around to auto_global problem.
1174 //         it makes just in time to every time.