root/eaccelerator/trunk/eaccelerator.c

Revision 426, 76.4 kB (checked in by bart, 2 days ago)

Make the error message about creating the cache directory more clear.

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