root/eaccelerator/tags/start/eaccelerator.c

Revision 5, 215.2 kB (checked in by anonymous, 4 years ago)

This commit was manufactured by cvs2svn to create branch 'eAccelerator'.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2    +----------------------------------------------------------------------+
3    | Turck MMCache for PHP Version 4                                      |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 2002-2003 TurckSoft, St. Petersburg                    |
6    | http://www.turcksoft.com                                             |
7    +----------------------------------------------------------------------+
8    | This program is free software; you can redistribute it and/or        |
9    | modify it under the terms of the GNU General Public License          |
10    | as published by the Free Software Foundation; either version 2       |
11    | of the License, or (at your option) any later version.               |
12    |                                                                      |
13    | This program is distributed in the hope that it will be useful,      |
14    | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
15    | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
16    | GNU General Public License for more details.                         |
17    |                                                                      |
18    | You should have received a copy of the GNU General Public License    |
19    | along with this program; if not, write to the Free Software          |
20    | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
21    | MA  02111-1307, USA.                                                 |
22    |                                                                      |
23    | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
24    +----------------------------------------------------------------------+
25    | Author: Dmitry Stogov <mmcache@turckware.ru>                         |
26    +----------------------------------------------------------------------+
27    $Id$
28 */
29
30 #include "eaccelerator.h"
31 #include "eaccelerator_version.h"
32
33 #ifdef HAVE_EACCELERATOR
34
35 #include "opcodes.h"
36
37 #include "zend.h"
38 #include "zend_API.h"
39 #include "zend_extensions.h"
40
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #ifdef ZEND_WIN32
44 #  include "win32/time.h"
45 #  include <time.h>
46 #  include <sys/utime.h>
47 #else
48 #  include <sys/file.h>
49 #  include <sys/time.h>
50 #  include <utime.h>
51 #endif
52 #include <fcntl.h>
53
54 #ifndef O_BINARY
55 #  define O_BINARY 0
56 #endif
57
58 /*???
59 #ifdef HAVE_SCHED_H
60 #  include <sched.h>
61 #endif
62 */
63
64 #ifdef ZEND_WIN32
65 #  include <process.h>
66 #  ifndef S_ISREG
67 #    define S_ISREG(mode) (((mode)&S_IFMT) & S_IFREG)
68 #  endif
69 #  ifndef S_IRUSR
70 #    define S_IRUSR S_IREAD
71 #  endif
72 #  ifndef S_IWUSR
73 #    define S_IWUSR S_IWRITE
74 #  endif
75 #else
76 #  include <dirent.h>
77 #endif
78
79 #include "php.h"
80 #include "php_ini.h"
81 #include "php_logos.h"
82 #include "main/fopen_wrappers.h"
83 #include "ext/standard/info.h"
84 #include "ext/standard/php_incomplete_class.h"
85 #include "ext/standard/md5.h"
86
87 #ifndef INCOMPLETE_CLASS
88 #  define INCOMPLETE_CLASS "__PHP_Incomplete_Class"
89 #endif
90 #ifndef MAGIC_MEMBER
91 #  define MAGIC_MEMBER "__PHP_Incomplete_Class_Name"
92 #endif
93
94 #include "SAPI.h"
95
96 #undef HAVE_PHP_SESSIONS_SUPPORT
97 #ifdef HAVE_EXT_SESSION_PHP_SESSION_H
98 #  include "ext/session/php_session.h"
99 #   ifdef PHP_SESSION_API
100 #     if PHP_SESSION_API >= 20020306
101 #       define HAVE_PHP_SESSIONS_SUPPORT
102 static int eaccelerator_sessions_registered = 0;
103 #       ifdef PS_CREATE_SID_ARGS
104 #         include "ext/standard/php_lcg.h"
105 #       endif
106 #     endif
107 #   endif
108 #endif
109
110 #define MAX_DUP_STR_LEN 256
111
112 #define offsetof(str,fld) ((size_t)&(((str*)NULL)->fld))
113
114 #ifdef EACCELERATOR_WITHOUT_FILE_LOCKING
115 #  ifndef LOCK_SH
116 #    define LOCK_SH 1
117 #    define LOCK_EX 2
118 #    define LOCK_UN 8
119 #  endif
120 #  define EACCELERATOR_FLOCK(FILE,OP)
121 #else
122 #  ifndef ZEND_WIN32
123 #    ifdef HAVE_FLOCK
124 #      define EACCELERATOR_FLOCK(FILE,OP) flock((FILE),(OP))
125 #    else
126 #      ifndef LOCK_SH
127 #        define LOCK_SH 1
128 #        define LOCK_EX 2
129 #        define LOCK_UN 8
130 #      endif
131 #      define EACCELERATOR_FLOCK(FILE,OP)
132 #    endif
133 #  else
134 #    define LOCK_SH 0
135 #    define LOCK_EX 1
136 #    define LOCK_UN 2
137 #    define EACCELERATOR_FLOCK(FILE,OP) {OVERLAPPED offset = {0,0,0,0,NULL};\
138                                    if ((OP) == LOCK_EX) {\
139                                      LockFileEx((HANDLE)_get_osfhandle(FILE), \
140                                        LOCKFILE_EXCLUSIVE_LOCK, 0,\
141                                        1, 0, &offset);\
142                                    } else if ((OP) == LOCK_SH) {\
143                                      LockFileEx((HANDLE)_get_osfhandle(FILE), \
144                                        0, 0,\
145                                        1, 0, &offset);\
146                                    } else if ((OP) == LOCK_UN) {\
147                                      UnlockFileEx((HANDLE)_get_osfhandle(FILE), \
148                                        0,\
149                                        1, 0, &offset);\
150                                    }}
151 #  endif
152 #endif
153
154
155 typedef struct _eaccelerator_op_array {
156   zend_uchar type;
157 #ifdef ZEND_ENGINE_2
158   zend_bool uses_this;
159 #else
160   zend_bool uses_globals;
161 #endif
162   zend_bool return_reference;
163 #ifdef ZEND_ENGINE_2
164   zend_uint num_args;
165   zend_arg_info *arg_info;
166   zend_bool pass_rest_by_reference;
167 #else
168   zend_uchar *arg_types;
169 #endif
170   char *function_name;
171 #ifdef ZEND_ENGINE_2
172   char* scope_name;
173   int   scope_name_len;
174   zend_uint fn_flags;
175 #endif
176   zend_op *opcodes;
177   zend_uint last;
178   zend_uint T;
179   zend_brk_cont_element *brk_cont_array;
180   zend_uint last_brk_cont;
181 #ifdef ZEND_ENGINE_2
182         /* HOESH: try & catch support */
183         zend_try_catch_element* try_catch_array;
184         int last_try_catch;
185 #endif
186   HashTable *static_variables;
187   char *filename;
188 #ifdef ZEND_ENGINE_2
189   zend_uint line_start;
190   zend_uint line_end;
191   char *doc_comment;
192   zend_uint doc_comment_len;
193 #endif
194 } eaccelerator_op_array;
195
196 typedef struct _eaccelerator_class_entry {
197   char type;
198   char *name;
199   uint name_length;
200   char *parent;
201   HashTable function_table;
202   HashTable default_properties;
203 #ifdef ZEND_ENGINE_2
204   zend_uint ce_flags;
205   HashTable *static_members;
206   HashTable properties_info;
207   HashTable constants_table;
208   zend_uint num_interfaces;
209
210   char *filename;
211   zend_uint line_start;
212   zend_uint line_end;
213   char *doc_comment;
214   zend_uint doc_comment_len;
215 #endif
216 } eaccelerator_class_entry;
217
218 /*
219  * To cache functions and classes.
220  */
221 typedef struct _mm_fc_entry {
222   void   *fc;
223   struct _mm_fc_entry *next;
224   int    htablen;
225   char   htabkey[1];         /* must be last element */
226 } mm_fc_entry;
227
228 /*
229  * A mm_cache_entry is a bucket for one PHP script file.
230  * Nested  functions and classes which defined in the file goes
231  * into the list of mm_fc_entry.
232  */
233 typedef struct _mm_cache_entry {
234   struct _mm_cache_entry *next;
235 #ifdef EACCELERATOR_USE_INODE
236   dev_t                  st_dev;         /* file's device                     */
237   ino_t                  st_ino;         /* file's inode                      */
238 #else
239   unsigned int           hv;             /* hash value                        */
240 #endif
241   off_t                  filesize;       /* file size */
242   time_t                 mtime;          /* file last modification time       */
243   time_t                 ttl;            /* expiration time                   */
244   int                    size;           /* entry size (bytes)                */
245   int                    nhits;          /* hits count                        */
246   int                    nreloads;       /* count of reloads                  */
247   int                    use_cnt;        /* how many processes uses the entry */
248   eaccelerator_op_array       *op_array;      /* script's global scope code        */
249   mm_fc_entry            *f_head;        /* list of nested functions          */
250   mm_fc_entry            *c_head;        /* list of nested classes            */
251   zend_bool              removed;        /* the entry is scheduled to remove  */
252   char                   realfilename[1];/* real file name (must be last el.) */
253 } mm_cache_entry;
254
255 /*
256  * bucket for user's cache
257  */
258 typedef struct _mm_user_cache_entry {
259   struct _mm_user_cache_entry *next;
260   unsigned int           hv;            /* hash value                  */
261   long                   ttl;           /* expiration time             */
262   int                    size;
263   zval                   value;         /* value                       */
264   char                   key[1];        /* key value (must be last el) */
265 } mm_user_cache_entry;
266
267 /*
268  * Linked list of mm_cache_entry which are used by process/thread
269  */
270 typedef struct _mm_used_entry {
271   struct _mm_used_entry *next;
272   mm_cache_entry        *entry;
273 } mm_used_entry;
274
275 /*
276  * Linked list of locks
277  */
278 typedef struct _mm_lock_entry {
279   struct _mm_lock_entry *next;
280   pid_t  pid;
281 #ifdef ZTS
282   THREAD_T thread;
283 #endif
284   char                  key[1];
285 } mm_lock_entry;
286
287 typedef struct _mm_file_header {
288   char   magic[8];        /* "EACCELERATOR" */
289   int    eaccelerator_version;
290   int    zend_version;
291   int    php_version;
292   int    size;
293   time_t mtime;
294   unsigned int crc32;
295 } mm_file_header;
296
297 #ifdef ZTS
298 #  define ZTS_LOCK()    tsrm_mutex_lock(mm_mutex)
299 #  define ZTS_UNLOCK()  tsrm_mutex_unlock(mm_mutex)
300 #else
301 #  define ZTS_LOCK()
302 #  define ZTS_UNLOCK()
303 #endif
304
305 #include "mm.h"
306
307 #if defined(EACCELERATOR_PROTECT_SHM)
308 #  define EACCELERATOR_PROTECT()    do {mm_protect(eaccelerator_mm_instance->mm, MM_PROT_READ);} while(0)
309 #  define EACCELERATOR_UNPROTECT()  do {mm_protect(eaccelerator_mm_instance->mm, MM_PROT_READ|MM_PROT_WRITE);} while(0)
310 #else
311 #  define EACCELERATOR_PROTECT()
312 #  define EACCELERATOR_UNPROTECT()
313 #endif
314
315 #define EACCELERATOR_LOCK_RW()    do {ZTS_LOCK(); mm_lock(eaccelerator_mm_instance->mm, MM_LOCK_RW);} while(0)
316 #define EACCELERATOR_LOCK_RD()    do {ZTS_LOCK(); mm_lock(eaccelerator_mm_instance->mm, MM_LOCK_RD);} while(0)
317 #define EACCELERATOR_UNLOCK()     do {mm_unlock(eaccelerator_mm_instance->mm); ZTS_UNLOCK();} while(0)
318 #define EACCELERATOR_UNLOCK_RW()  EACCELERATOR_UNLOCK()
319 #define EACCELERATOR_UNLOCK_RD()  EACCELERATOR_UNLOCK()
320
321 #define EACCELERATOR_BLOCK_INTERRUPTIONS()   HANDLE_BLOCK_INTERRUPTIONS()
322 #define EACCELERATOR_UNBLOCK_INTERRUPTIONS() HANDLE_UNBLOCK_INTERRUPTIONS()
323
324 #define MM_HASH_SIZE      256
325 #define MM_USER_HASH_SIZE 256
326 #define MM_HASH_MAX       (MM_HASH_SIZE-1)
327 #define MM_USER_HASH_MAX  (MM_USER_HASH_SIZE-1)
328
329 #define eaccelerator_malloc(size)        mm_malloc(eaccelerator_mm_instance->mm, size)
330 #define eaccelerator_free(x)             mm_free(eaccelerator_mm_instance->mm, x)
331 #define eaccelerator_malloc_nolock(size) mm_malloc_nolock(eaccelerator_mm_instance->mm, size)
332 #define eaccelerator_free_nolock(x)      mm_free_nolock(eaccelerator_mm_instance->mm, x)
333
334 typedef struct {
335   MM             *mm;
336   pid_t          owner;
337   size_t         total;
338   unsigned int   hash_cnt;
339   unsigned int   user_hash_cnt;
340   zend_bool      enabled;
341   zend_bool      optimizer_enabled;
342   unsigned int   rem_cnt;
343   time_t         last_prune;
344   mm_cache_entry *removed;
345   mm_lock_entry  *locks;
346
347   mm_cache_entry      *hash[MM_HASH_SIZE];
348   mm_user_cache_entry *user_hash[MM_USER_HASH_SIZE];
349 } eaccelerator_mm;
350
351 /*
352  * Globals (different for each process/thread)
353  */
354 ZEND_DECLARE_MODULE_GLOBALS(eaccelerator)
355
356 /*
357  * Globals (common for each process/thread)
358  */
359 static long eaccelerator_shm_size = 0;
360 static long eaccelerator_shm_max = 0;
361 static long eaccelerator_shm_ttl = 0;
362 static long eaccelerator_shm_prune_period = 0;
363 static long eaccelerator_debug = 0;
364 static zend_bool eaccelerator_check_mtime = 1;
365 static zend_bool eaccelerator_scripts_shm_only = 0;
366 static eaccelerator_cache_place eaccelerator_keys_cache_place     = eaccelerator_shm_and_disk;
367 static eaccelerator_cache_place eaccelerator_sessions_cache_place = eaccelerator_shm_and_disk;
368        eaccelerator_cache_place eaccelerator_content_cache_place  = eaccelerator_shm_and_disk;
369
370 static eaccelerator_mm* eaccelerator_mm_instance = NULL;
371 static int eaccelerator_is_zend_extension = 0;
372 static int eaccelerator_is_extension      = 0;
373 static zend_extension* ZendOptimizer = NULL;
374 #ifdef ZTS
375 static MUTEX_T mm_mutex;
376 #endif
377
378 static HashTable eaccelerator_global_function_table;
379 static HashTable eaccelerator_global_class_table;
380
381 static int binary_eaccelerator_version;
382 static int binary_php_version;
383 static int binary_zend_version;
384
385 /* saved original functions */
386 static zend_op_array *(*mm_saved_zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
387
388 #if defined(PROFILE_OPCODES) || defined(WITH_EACCELERATOR_EXECUTOR)
389 static void (*mm_saved_zend_execute)(zend_op_array *op_array TSRMLS_DC);
390 #endif
391
392 /* external declarations */
393 PHPAPI void php_stripslashes(char *str, int *len TSRMLS_DC);
394 PHPAPI char *php_get_uname();
395
396 ZEND_DLEXPORT zend_op_array* eaccelerator_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC);
397
398
399 #if defined(DEBUG) || defined(TEST_PERFORMANCE)  || defined(PROFILE_OPCODES)
400 #include <ctype.h>
401 #include <stdio.h>
402 static FILE *F_fp;
403
404 static void pad(TSRMLS_D) {
405   int i = MMCG(xpad);
406   while (i-- > 0) {
407     fputc('\t', F_fp);
408   }
409 }
410
411 static void start_time(struct timeval *tvstart) {
412   gettimeofday(tvstart, NULL);
413 }
414
415 static long elapsed_time(struct timeval *tvstart) {
416   struct timeval tvend;
417   int sec, usec;
418   gettimeofday(&tvend, NULL);
419   sec = tvend.tv_sec - tvstart->tv_sec;
420   usec = tvend.tv_usec - tvstart->tv_usec;
421   return sec * 1000000 + usec;
422 }
423 #endif  /* #if defined(DEBUG) || defined(TEST_PERFORMANCE)  || defined(PROFILE_OPCODES) */
424
425 static inline unsigned int hash_mm(const char *data, int len) {
426   unsigned int h;
427   const char *e = data + len;
428   for (h = 2166136261U; data < e; ) {
429     h *= 16777619;
430     h ^= *data++;
431   }
432   return h;
433 }
434
435 static mm_cache_entry* hash_find_mm(const char  *key,
436                                     struct stat *buf,
437                                     int         *nreloads,
438                                     time_t      ttl) {
439   unsigned int hv, slot;
440   mm_cache_entry *p, *q;
441
442 #ifdef EACCELERATOR_USE_INODE
443   hv = buf->st_dev + buf->st_ino;
444 #else
445   hv = hash_mm(key, strlen(key));
446 #endif
447   slot = hv & MM_HASH_MAX;
448
449   EACCELERATOR_LOCK_RW();
450   q = NULL;
451   p = eaccelerator_mm_instance->hash[slot];
452   while (p != NULL) {
453 #ifdef EACCELERATOR_USE_INODE
454     if (p->st_dev == buf->st_dev && p->st_ino == buf->st_ino) {
455       struct stat buf2;
456       if ((eaccelerator_check_mtime &&
457           (buf->st_mtime != p->mtime || buf->st_size != p->filesize)) ||
458           (strcmp(p->realfilename, key) != 0 &&
459            (stat(p->realfilename,&buf2) != 0 ||
460            buf2.st_dev != buf->st_dev ||
461            buf2.st_ino != buf->st_ino))) {
462 #else
463     if ((p->hv == hv) && (strcmp(p->realfilename, key) == 0)) {
464       if (eaccelerator_check_mtime &&
465           (buf->st_mtime != p->mtime || buf->st_size != p->filesize)) {
466 #endif
467         /* key is invalid. Remove it. */
468         *nreloads = p->nreloads+1;
469         if (q == NULL) {
470           eaccelerator_mm_instance->hash[slot] = p->next;
471         } else {
472           q->next = p->next;
473         }
474         eaccelerator_mm_instance->hash_cnt--;
475         if (p->use_cnt > 0) {
476           /* key is used by other process/thred. Shedule it to remove */
477           p->removed = 1;
478           p->next = eaccelerator_mm_instance->removed;
479           eaccelerator_mm_instance->removed = p;
480           eaccelerator_mm_instance->rem_cnt++;
481           EACCELERATOR_UNLOCK_RW();
482           return NULL;
483         } else {
484           /* key is unused. Remove it. */
485           eaccelerator_free_nolock(p);
486           EACCELERATOR_UNLOCK_RW();
487           return NULL;
488         }
489       } else {
490         /* key is valid */
491         p->nhits++;
492         p->use_cnt++;
493         p->ttl = ttl;
494         EACCELERATOR_UNLOCK_RW();
495         return p;
496       }
497     }
498     q = p;
499     p = p->next;
500   }
501   EACCELERATOR_UNLOCK_RW();
502   return NULL;
503 }
504
505 static void hash_add_mm(mm_cache_entry *x) {
506   mm_cache_entry *p,*q;
507   unsigned int slot;
508 #ifdef EACCELERATOR_USE_INODE
509   slot = (x->st_dev + x->st_ino) & MM_HASH_MAX;
510 #else
511   x->hv = hash_mm(x->realfilename, strlen(x->realfilename));
512   slot = x->hv & MM_HASH_MAX;
513 #endif
514
515   EACCELERATOR_LOCK_RW();
516   x->next = eaccelerator_mm_instance->hash[slot];
517   eaccelerator_mm_instance->hash[slot] = x;
518   eaccelerator_mm_instance->hash_cnt++;
519   q = x;
520   p = x->next;
521   while (p != NULL) {
522 #ifdef EACCELERATOR_USE_INODE
523     if ((p->st_dev == x->st_dev) && (p->st_ino == x->st_ino)) {
524 #else
525     if ((p->hv == x->hv) &&
526         (strcmp(p->realfilename, x->realfilename) == 0)) {
527 #endif
528       q->next = p->next;
529       eaccelerator_mm_instance->hash_cnt--;
530       eaccelerator_mm_instance->hash[slot]->nreloads += p->nreloads;
531       if (p->use_cnt > 0) {
532         /* key is used by other process/thred. Shedule it to remove */
533         p->removed = 1;
534         p->next = eaccelerator_mm_instance->removed;
535         eaccelerator_mm_instance->removed = p;
536         eaccelerator_mm_instance->rem_cnt++;
537         EACCELERATOR_UNLOCK_RW();
538         return;
539       } else {
540         /* key is unused. Remove it. */
541         eaccelerator_free_nolock(p);
542         EACCELERATOR_UNLOCK_RW();
543         return;
544       }
545     }
546     q = p;
547     p = p->next;
548   }
549   EACCELERATOR_UNLOCK_RW();
550 }
551
552 static int init_mm(TSRMLS_D) {
553   pid_t  owner = getpid();
554   MM     *mm;
555   size_t total;
556   char   mm_path[MAXPATHLEN];
557
558 /*  if (getppid() != 1) return SUCCESS; */ /*???*/
559 #ifdef ZEND_WIN32
560     snprintf(mm_path, MAXPATHLEN, "%s.%s", EACCELERATOR_MM_FILE, sapi_module.name);
561 #else
562     snprintf(mm_path, MAXPATHLEN, "%s.%s%d", EACCELERATOR_MM_FILE, sapi_module.name, getpid());
563 #endif
564 /*  snprintf(mm_path, MAXPATHLEN, "%s.%s%d", EACCELERATOR_MM_FILE, sapi_module.name, geteuid());*/
565   if ((eaccelerator_mm_instance = (eaccelerator_mm*)mm_attach(eaccelerator_shm_size*1024*1024, mm_path)) != NULL) {
566 #ifdef ZTS
567     mm_mutex = tsrm_mutex_alloc();
568 #endif
569     return SUCCESS;
570   }
571   mm = mm_create(eaccelerator_shm_size*1024*1024, mm_path);
572   if (!mm) {
573     return FAILURE;
574   }
575 #ifdef DEBUG
576 #ifdef ZEND_WIN32
577   fprintf(F_fp, "init_mm [%d]\n", getpid());
578 #else
579   fprintf(F_fp, "init_mm [%d,%d]\n", getpid(), getppid());
580 #endif
581   fflush(F_fp);
582 #endif
583 #ifdef ZTS
584   mm_mutex = tsrm_mutex_alloc();
585 #endif
586   total = mm_available(mm);
587   eaccelerator_mm_instance = mm_malloc(mm, sizeof(*eaccelerator_mm_instance));
588   if (!eaccelerator_mm_instance) {
589     return FAILURE;
590   }
591   mm_set_attach(mm, eaccelerator_mm_instance);
592   memset(eaccelerator_mm_instance, 0, sizeof(*eaccelerator_mm_instance));
593   eaccelerator_mm_instance->owner = owner;
594   eaccelerator_mm_instance->mm    = mm;
595   eaccelerator_mm_instance->total = total;
596   eaccelerator_mm_instance->hash_cnt = 0;
597   eaccelerator_mm_instance->rem_cnt  = 0;
598   eaccelerator_mm_instance->enabled = 1;
599   eaccelerator_mm_instance->optimizer_enabled = 1;
600   eaccelerator_mm_instance->removed = NULL;
601   eaccelerator_mm_instance->locks = NULL;
602   eaccelerator_mm_instance->user_hash_cnt = 0;
603   eaccelerator_mm_instance->last_prune = time(0);
604   EACCELERATOR_PROTECT();
605   return SUCCESS;
606 }
607
608 static void shutdown_mm(TSRMLS_D) {
609   if (eaccelerator_mm_instance) {
610 #ifdef ZEND_WIN32
611     if (eaccelerator_mm_instance->owner == getpid()) {
612 #else
613     if (getpgrp() == getpid()) {
614 #endif
615       MM *mm = eaccelerator_mm_instance->mm;
616 #ifdef DEBUG
617 #ifdef ZEND_WIN32
618       fprintf(F_fp, "shutdown_mm [%d]\n", getpid());
619 #else
620       fprintf(F_fp, "shutdown_mm [%d,%d]\n", getpid(), getppid());
621 #endif
622       fflush(F_fp);
623 #endif
624 #ifdef ZTS
625       tsrm_mutex_free(mm_mutex);
626 #endif
627       if (mm) {
628         mm_destroy(mm);
629       }
630       eaccelerator_mm_instance = NULL;
631     }
632   }
633 }
634
635 static void debug_printf(char *format, ...) {
636   char output_buf[512];
637   va_list args;
638
639   va_start(args, format);
640   vsnprintf(output_buf, sizeof(output_buf), format, args);
641   va_end(args);
642
643 #ifdef ZEND_WIN32
644   OutputDebugString(output_buf);
645 /*  zend_printf("EACCELERATOR: %s<br>\n",output_buf);*/
646 #else
647   fputs(output_buf, stderr);
648 #endif
649 }
650
651 /******************************************************************************/
652
653 #define FIXUP(x) if((x)!=NULL) {(x) = (void*)(((char*)(x)) + ((long)(MMCG(mem))));}
654
655 static void fixup_zval(zval* z TSRMLS_DC);
656
657 typedef void (*fixup_bucket_t)(void* TSRMLS_DC);
658
659 #define fixup_zval_hash(from) \
660   fixup_hash(from, (fixup_bucket_t)fixup_zval TSRMLS_CC)
661
662 #ifdef ZEND_ENGINE_2
663 static void fixup_property_info(zend_property_info* from TSRMLS_DC) {
664   FIXUP(from->name);
665 }
666 #endif
667
668 static void fixup_hash(HashTable* source, fixup_bucket_t fixup_bucket TSRMLS_DC) {
669   unsigned int i;
670   Bucket *p;
671
672   if (source->nNumOfElements > 0) {
673     if (!MMCG(compress)) {
674       if (source->arBuckets != NULL) {
675         FIXUP(source->arBuckets);
676         for (i = 0; i < source->nTableSize; i++) {
677           FIXUP(source->arBuckets[i]);
678         }
679       }
680     }
681     FIXUP(source->pListHead);
682     FIXUP(source->pListTail);
683
684     p = source->pListHead;
685     while (p) {
686       FIXUP(p->pNext);
687       FIXUP(p->pLast);
688       FIXUP(p->pData);
689       FIXUP(p->pDataPtr);
690       FIXUP(p->pListLast);
691       FIXUP(p->pListNext);
692       if (p->pDataPtr) {
693         fixup_bucket(p->pDataPtr TSRMLS_CC);
694         p->pData = &p->pDataPtr;
695       } else {
696         fixup_bucket(p->pData TSRMLS_CC);
697       }
698       p = p->pListNext;
699     }
700     source->pInternalPointer = source->pListHead;
701   }
702 }
703
704 static void fixup_zval(zval* zv TSRMLS_DC) {
705   switch (zv->type) {
706     case IS_CONSTANT:
707     case IS_STRING:
708       if (zv->value.str.val == NULL ||
709          zv->value.str.len == 0) {
710         zv->value.str.val = empty_string;
711         zv->value.str.len = 0;
712       } else {
713         FIXUP(zv->value.str.val);
714       }
715       break;
716     case IS_ARRAY:
717     case IS_CONSTANT_ARRAY:
718       if (zv->value.ht == NULL || zv->value.ht == &EG(symbol_table)) {
719       } else {
720         FIXUP(zv->value.ht);
721         fixup_zval_hash(zv->value.ht);
722       }
723       break;
724     case IS_OBJECT:
725       if (!MMCG(compress)) {
726         return;
727       }
728 #ifndef ZEND_ENGINE_2
729       FIXUP(zv->value.obj.ce);
730       if (zv->value.obj.properties != NULL) {
731         FIXUP(zv->value.obj.properties);
732         fixup_zval_hash(zv->value.obj.properties);
733       }
734 #endif
735     default:
736       break;
737   }
738 }
739
740 static void fixup_op_array(eaccelerator_op_array* from TSRMLS_DC) {
741   zend_op *opline;
742   zend_op *end;
743
744 #ifdef ZEND_ENGINE_2
745   if (from->num_args > 0) {
746     zend_uint i;
747     FIXUP(from->arg_info);
748     for (i = 0; i < from->num_args; i++) {
749       FIXUP(from->arg_info[i].name);
750       FIXUP(from->arg_info[i].class_name);
751     }
752   }
753 #else
754   FIXUP(from->arg_types);
755 #endif
756   FIXUP(from->function_name);
757 #ifdef ZEND_ENGINE_2
758   FIXUP(from->scope_name);
759 #endif
760   if (from->type == ZEND_INTERNAL_FUNCTION) {
761     return;
762   }
763
764   if (from->opcodes != NULL) {
765     FIXUP(from->opcodes);
766
767     opline = from->opcodes;
768     end = opline + from->last;
769     MMCG(compress) = 0;
770     for (;opline < end; opline++) {
771 /*
772       if (opline->result.op_type == IS_CONST) fixup_zval(&opline->result.u.constant  TSRMLS_CC);
773 */
774       if (opline->op1.op_type    == IS_CONST) fixup_zval(&opline->op1.u.constant TSRMLS_CC);
775       if (opline->op2.op_type    == IS_CONST) fixup_zval(&opline->op2.u.constant TSRMLS_CC);
776 #ifdef ZEND_ENGINE_2
777       switch (opline->opcode) {
778         case ZEND_JMP:
779           FIXUP(opline->op1.u.jmp_addr);
780           break;
781         case ZEND_JMPZ:
782         case ZEND_JMPNZ:
783         case ZEND_JMPZ_EX:
784         case ZEND_JMPNZ_EX:
785           FIXUP(opline->op2.u.jmp_addr);
786           break;
787       }
788       opline->handler = get_opcode_handler(opline->opcode TSRMLS_CC);
789 #endif
790     }
791     MMCG(compress) = 1;
792   }
793   FIXUP(from->brk_cont_array);
794 #ifdef ZEND_ENGINE_2
795         /* HOESH: try & catch support */
796         FIXUP(from->try_catch_array);
797 #endif
798   if (from->static_variables != NULL) {
799     FIXUP(from->static_variables);
800     fixup_zval_hash(from->static_variables);
801   }
802   FIXUP(from->filename);
803 #ifdef ZEND_ENGINE_2
804   FIXUP(from->doc_comment);
805 #endif
806 }
807
808 static void fixup_class_entry(eaccelerator_class_entry* from TSRMLS_DC) {
809   FIXUP(from->name);
810   FIXUP(from->parent);
811 #ifdef ZEND_ENGINE_2
812   FIXUP(from->filename);
813   FIXUP(from->doc_comment);
814   fixup_zval_hash(&from->constants_table);
815   fixup_zval_hash(&from->default_properties);
816   fixup_hash(&from->properties_info, (fixup_bucket_t)fixup_property_info TSRMLS_CC);
817   if (from->static_members != NULL) {
818     FIXUP(from->static_members);
819     fixup_zval_hash(from->static_members);
820   }
821 #else
822   fixup_zval_hash(&from->default_properties);
823 #endif
824   fixup_hash(&from->function_table, (fixup_bucket_t)fixup_op_array TSRMLS_CC);
825 }
826
827 static void eaccelerator_fixup(mm_cache_entry *p TSRMLS_DC) {
828   mm_fc_entry* q;
829
830   MMCG(mem) = (char*)((long)p - (long)p->next);
831   MMCG(compress) = 1;
832   p->next        = NULL;
833   FIXUP(p->op_array);
834   FIXUP(p->f_head);
835   FIXUP(p->c_head);
836   fixup_op_array(p->op_array TSRMLS_CC);
837   q = p->f_head;
838   while (q != NULL) {
839     FIXUP(q->fc);
840     fixup_op_array((eaccelerator_op_array*)q->fc TSRMLS_CC);
841     FIXUP(q->next);
842     q = q->next;
843   }
844   q = p->c_head;
845   while (q != NULL) {
846     FIXUP(q->fc);
847     fixup_class_entry((eaccelerator_class_entry*)q->fc TSRMLS_CC);
848     FIXUP(q->next);
849     q = q->next;
850   }
851 }
852
853 /******************************************************************************/
854
855 static int encode_version(const char *s) {
856   unsigned int v1 = 0;
857   unsigned int v2 = 0;
858   unsigned int v3 = 0;
859   unsigned int c;
860   char m = '.';
861   sscanf(s, "%u.%u%c%u",&v1,&v2,&m,&v3);
862   switch (m) {
863     case  'a': c = 0; break;
864     case  'b': c = 1; break;
865     case  '.': c = 2; break;
866     case  's': c = 15; break;
867     default: c = 2;
868   }
869   return ((v1 & 0xf) << 20) |
870          ((v2 & 0xff) << 12) |
871          ((c & 0xf) << 8) |
872          (v3 & 0xff);
873 }
874
875 static void decode_version(char *version, int v) {
876   int t = (v & 0x000f00) >> 8;
877   char c;
878   switch (t) {
879     case  0: c = 'a'; break;
880     case  1: c = 'b'; break;
881     case  2: c = '.'; break;
882     case 15: c = 's'; break;
883     default: c = '.';
884   }
885   snprintf(version, 16, "%d.%d%c%d", (v & 0xf00000) >> 20,
886                                      (v & 0x0ff000) >> 12,
887                                      c,
888                                      (v & 0x0000ff));
889 }
890
891 #ifdef EACCELERATOR_USE_INODE
892 static int eaccelerator_inode_key(char* s, dev_t dev, ino_t ino TSRMLS_DC) {
893   int n;
894   strncpy(s, MMCG(cache_dir), MAXPATHLEN-1);
895   strlcat(s, "/eaccelerator-", MAXPATHLEN-1);
896   n = strlen(s);
897   while (dev > 0) {
898     if (n >= MAXPATHLEN) return 0;
899     s[n++] = (dev % 10) +'0';
900     dev /= 10;
901   }
902   if (n >= MAXPATHLEN) return 0;
903   s[n++] = '.';
904   while (ino > 0) {
905     if (n >= MAXPATHLEN) return 0;
906     s[n++] = (ino % 10) +'0';
907     ino /= 10;
908   }
909   if (n >= MAXPATHLEN) return 0;
910   s[n++] = '\000';
911   return 1;
912 }
913 #endif
914
915 static int eaccelerator_md5(char* s, const char* prefix, const char* key TSRMLS_DC) {
916 #if defined(PHP_MAJOR_VERSION) && defined(PHP_MINOR_VERSION) && \
917     ((PHP_MAJOR_VERSION > 4) || (PHP_MAJOR_VERSION == 4 && PHP_MINOR_VERSION > 1))
918   char md5str[33];
919   PHP_MD5_CTX context;
920   unsigned char digest[16];
921
922   md5str[0] = '\0';
923   PHP_MD5Init(&context);
924   PHP_MD5Update(&context, key, strlen(key));
925   PHP_MD5Final(digest, &context);
926   make_digest(md5str, digest);
927   snprintf(s, MAXPATHLEN-1, "%s%s%s", MMCG(cache_dir), prefix, md5str);
928   return 1;
929 #else
930   zval retval;
931   zval md5;
932   zval param;
933   zval *params[1];
934
935   ZVAL_STRING(&md5, "md5", 0);
936   INIT_ZVAL(param);
937   params[0] = &param;
938   ZVAL_STRING(params[0], (char*)key, 0);
939   if (call_user_function(CG(function_table), (zval**)NULL, &md5, &retval, 1, params TSRMLS_CC) == SUCCESS &&
940       retval.type == IS_STRING &&
941       retval.value.str.len == 32) {
942     strncpy(s, MMCG(cache_dir), MAXPATHLEN-1);
943     strlcat(s, prefix, MAXPATHLEN);
944     strlcat(s, retval.value.str.val, MAXPATHLEN);
945     zval_dtor(&retval);
946     return 1;
947   }
948   s[0] ='\0';
949 #endif
950   return 0;
951 }
952
953 static void eaccelerator_prune(time_t t) {
954   unsigned int i;
955
956   EACCELERATOR_LOCK_RW();
957   eaccelerator_mm_instance->last_prune = t;
958   for (i = 0; i < MM_HASH_SIZE; i++) {
959     mm_cache_entry **p = &eaccelerator_mm_instance->hash[i];
960     while (*p != NULL) {
961       struct stat buf;
962       if (((*p)->ttl != 0 && (*p)->ttl < t && (*p)->use_cnt <= 0) ||
963           stat((*p)->realfilename,&buf) != 0 ||
964 #ifdef EACCELERATOR_USE_INODE
965           (*p)->st_dev != buf.st_dev ||
966           (*p)->st_ino != buf.st_ino ||
967 #endif
968           (*p)->mtime != buf.st_mtime ||
969           (*p)->filesize != buf.st_size) {
970         mm_cache_entry *r = *p;
971         *p = (*p)->next;
972         eaccelerator_mm_instance->hash_cnt--;
973         eaccelerator_free_nolock(r);
974       } else {
975         p = &(*p)->next;
976       }
977     }
978   }
979   EACCELERATOR_UNLOCK_RW();
980 }
981
982 static void* eaccelerator_malloc2(size_t size TSRMLS_DC) {
983   void *p = NULL;
984   time_t t;
985
986   if (eaccelerator_gc(TSRMLS_C) > 0) {
987     p = eaccelerator_malloc(size);
988     if (p != NULL) {
989       return p;
990     }
991   }
992   if (eaccelerator_shm_prune_period > 0) {
993     t = time(0);
994     if (t - eaccelerator_mm_instance->last_prune > eaccelerator_shm_prune_period) {
995       eaccelerator_prune(t);
996       p = eaccelerator_malloc(size);
997     }
998   }
999   return p;
1000 }
1001
1002 #define EACCELERATOR_CRC32(crc, ch)   (crc = (crc >> 8) ^ crc32tab[(crc ^ (ch)) & 0xff])
1003
1004 static const unsigned int crc32tab[256] = {
1005   0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
1006   0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
1007   0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
1008   0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
1009   0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
1010   0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
1011   0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
1012   0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
1013   0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
1014   0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
1015   0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
1016   0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
1017   0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
1018   0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
1019   0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
1020   0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
1021   0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
1022   0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
1023   0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
1024   0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
1025   0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
1026   0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
1027   0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
1028   0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
1029   0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
1030   0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
1031   0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
1032   0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
1033   0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
1034   0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
1035   0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
1036   0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
1037   0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
1038   0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
1039   0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
1040   0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
1041   0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
1042   0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
1043   0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
1044   0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
1045   0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
1046   0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
1047   0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
1048   0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
1049   0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
1050   0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
1051   0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
1052   0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
1053   0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
1054   0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
1055   0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
1056   0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
1057   0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
1058   0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
1059   0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
1060   0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
1061   0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
1062   0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
1063   0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
1064   0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1065   0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
1066   0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
1067   0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
1068   0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
1069 };
1070
1071 unsigned int eaccelerator_crc32(const char *p, size_t n) {
1072   unsigned int crc = ~0;
1073   for (; n--; ++p) {
1074     EACCELERATOR_CRC32(crc, *p);
1075   }
1076   return ~crc;
1077 }
1078
1079 static mm_cache_entry* hash_find_file(const char  *key,
1080                                       struct stat *buf TSRMLS_DC) {
1081   int f;
1082   char s[MAXPATHLEN];
1083   mm_file_header hdr;
1084   mm_cache_entry *p;
1085   int use_shm = 1;
1086
1087 #ifdef EACCELERATOR_USE_INODE
1088   struct stat buf2;
1089
1090   if (!eaccelerator_inode_key(s, buf->st_dev, buf->st_ino TSRMLS_CC)) {
1091     return NULL;
1092   }
1093 #else
1094   if (!eaccelerator_md5(s, "/eaccelerator-", key TSRMLS_CC)) {
1095     return NULL;
1096   }
1097 #endif
1098
1099   if ((f = open(s, O_RDONLY | O_BINARY)) > 0) {
1100     EACCELERATOR_FLOCK(f, LOCK_SH);
1101     if (read(f, &hdr, sizeof(hdr)) != sizeof(hdr)) {
1102       EACCELERATOR_FLOCK(f, LOCK_UN);
1103       close(f);
1104       return NULL;
1105     }
1106     if (strncmp(hdr.magic,"EACCELERATOR",8) != 0 ||
1107         hdr.eaccelerator_version != binary_eaccelerator_version ||
1108         hdr.zend_version != binary_zend_version ||
1109         hdr.php_version != binary_php_version) {
1110       EACCELERATOR_FLOCK(f, LOCK_UN);
1111       close(f);
1112       unlink(s);
1113       return NULL;
1114     }
1115     p = eaccelerator_malloc(hdr.size);
1116     if (p == NULL) {
1117       p = eaccelerator_malloc2(hdr.size TSRMLS_CC);
1118     }
1119     if (p == NULL) {
1120       p = emalloc(hdr.size);
1121       use_shm = 0;
1122     }
1123     if (p == NULL) {
1124       EACCELERATOR_FLOCK(f, LOCK_UN);
1125       close(f);
1126       return NULL;
1127     }
1128     if (read(f, p, hdr.size) != hdr.size ||
1129         p->size != hdr.size ||
1130         hdr.crc32 != eaccelerator_crc32((const char*)p,p->size)) {
1131       EACCELERATOR_FLOCK(f, LOCK_UN);
1132       close(f);
1133       unlink(s);
1134       if (use_shm) eaccelerator_free(p); else efree(p);
1135       return NULL;
1136     }
1137     EACCELERATOR_FLOCK(f, LOCK_UN);
1138     close(f);
1139 #ifdef EACCELERATOR_USE_INODE
1140     if (p->st_dev != buf->st_dev || p->st_ino != buf->st_ino) {
1141 #else
1142     if (strcmp(key,p->realfilename) != 0) {
1143 #endif
1144       if (use_shm) eaccelerator_free(p); else efree(p);
1145       return NULL;
1146     }
1147     if ((eaccelerator_check_mtime &&
1148         (buf->st_mtime != p->mtime || buf->st_size != p->filesize))
1149 #ifdef EACCELERATOR_USE_INODE
1150         ||
1151         (strcmp(p->realfilename, key) != 0 &&
1152          (stat(p->realfilename,&buf2) != 0 ||
1153          buf2.st_dev != buf->st_dev ||
1154          buf2.st_ino != buf->st_ino))
1155 #endif
1156        ) {
1157       /* key is invalid. Remove it. */
1158       if (use_shm) eaccelerator_free(p); else efree(p);
1159       unlink(s);
1160       return NULL;
1161     }
1162     eaccelerator_fixup(p TSRMLS_CC);
1163     if (use_shm) {
1164       p->nhits    = 1;
1165       p->nreloads = 1;
1166       p->use_cnt  = 1;
1167       p->removed  = 0;
1168       if (eaccelerator_shm_ttl > 0) {
1169         p->ttl = time(0) + eaccelerator_shm_ttl;
1170       } else {
1171         p->ttl = 0;
1172       }
1173       hash_add_mm(p);
1174     } else {
1175       p->use_cnt  = 0;
1176       p->removed  = 1;
1177     }
1178     return p;
1179   }
1180   return NULL;
1181 }
1182
1183 static int hash_add_file(mm_cache_entry *p TSRMLS_DC) {
1184   int f;
1185   int ret = 0;
1186   char s[MAXPATHLEN];
1187   mm_file_header hdr;
1188
1189 #ifdef EACCELERATOR_USE_INODE
1190   if (!eaccelerator_inode_key(s, p->st_dev, p->st_ino TSRMLS_CC)) {
1191     return 0;
1192   }
1193 #else
1194   if (!eaccelerator_md5(s, "/eaccelerator-", p->realfilename TSRMLS_CC)) {
1195     return 0;
1196   }
1197 #endif
1198
1199   unlink(s);
1200   f = open(s, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, S_IRUSR | S_IWUSR);
1201   if (f > 0) {
1202     EACCELERATOR_FLOCK(f, LOCK_EX);
1203     strcpy(hdr.magic,"EACCELERATOR");
1204     hdr.eaccelerator_version = binary_eaccelerator_version;
1205     hdr.zend_version    = binary_zend_version;
1206     hdr.php_version     = binary_php_version;
1207     hdr.size  = p->size;
1208     hdr.mtime = p->mtime;
1209     p->next = p;
1210     hdr.crc32 = eaccelerator_crc32((const char*)p,p->size);
1211     ret = (write(f, &hdr, sizeof(hdr)) == sizeof(hdr));
1212     if (ret) ret = (write(f, p, p->size) == p->size);
1213     EACCELERATOR_FLOCK(f, LOCK_UN);
1214     close(f);
1215   }
1216   return ret;
1217 }
1218