1/*
2   +----------------------------------------------------------------------+
3   | Zend OPcache                                                         |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2014 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt                                  |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Authors: Andi Gutmans <andi@zend.com>                                |
16   |          Zeev Suraski <zeev@zend.com>                                |
17   |          Stanislav Malyshev <stas@zend.com>                          |
18   |          Dmitry Stogov <dmitry@zend.com>                             |
19   +----------------------------------------------------------------------+
20*/
21
22#include "main/php.h"
23#include "main/php_globals.h"
24#include "zend.h"
25#include "zend_extensions.h"
26#include "zend_compile.h"
27#include "ZendAccelerator.h"
28#include "zend_persist.h"
29#include "zend_shared_alloc.h"
30#include "zend_accelerator_module.h"
31#include "zend_accelerator_blacklist.h"
32#include "zend_list.h"
33#include "zend_execute.h"
34#include "main/SAPI.h"
35#include "main/php_streams.h"
36#include "main/php_open_temporary_file.h"
37#include "zend_API.h"
38#include "zend_ini.h"
39#include "zend_virtual_cwd.h"
40#include "zend_accelerator_util_funcs.h"
41#include "zend_accelerator_hash.h"
42
43#ifndef ZEND_WIN32
44#include  <netdb.h>
45#endif
46
47#ifdef ZEND_WIN32
48typedef int uid_t;
49typedef int gid_t;
50#include <io.h>
51#endif
52
53#ifndef ZEND_WIN32
54# include <sys/time.h>
55#else
56# include <process.h>
57#endif
58
59#ifdef HAVE_UNISTD_H
60# include <unistd.h>
61#endif
62#include <fcntl.h>
63#include <signal.h>
64#include <time.h>
65
66#ifndef ZEND_WIN32
67# include <sys/types.h>
68# include <sys/ipc.h>
69#endif
70
71#include <sys/stat.h>
72#include <errno.h>
73
74#define SHM_PROTECT() \
75    do { \
76        if (ZCG(accel_directives).protect_memory) { \
77            zend_accel_shared_protect(1 TSRMLS_CC); \
78        } \
79    } while (0)
80#define SHM_UNPROTECT() \
81    do { \
82        if (ZCG(accel_directives).protect_memory) { \
83            zend_accel_shared_protect(0 TSRMLS_CC); \
84        } \
85    } while (0)
86
87ZEND_EXTENSION();
88
89#ifndef ZTS
90zend_accel_globals accel_globals;
91#else
92int accel_globals_id;
93#endif
94
95/* Points to the structure shared across all PHP processes */
96zend_accel_shared_globals *accel_shared_globals = NULL;
97
98/* true globals, no need for thread safety */
99zend_bool accel_startup_ok = 0;
100static char *zps_failure_reason = NULL;
101char *zps_api_failure_reason = NULL;
102
103static zend_op_array *(*accelerator_orig_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
104static int (*accelerator_orig_zend_stream_open_function)(const char *filename, zend_file_handle *handle  TSRMLS_DC);
105static char *(*accelerator_orig_zend_resolve_path)(const char *filename, int filename_len TSRMLS_DC);
106static void (*orig_chdir)(INTERNAL_FUNCTION_PARAMETERS) = NULL;
107static ZEND_INI_MH((*orig_include_path_on_modify)) = NULL;
108
109#ifdef ZEND_WIN32
110# define INCREMENT(v) InterlockedIncrement64(&ZCSG(v))
111# define DECREMENT(v) InterlockedDecrement64(&ZCSG(v))
112# define LOCKVAL(v)   (ZCSG(v))
113#endif
114
115#ifdef ZEND_WIN32
116static time_t zend_accel_get_time(void)
117{
118    FILETIME now;
119    GetSystemTimeAsFileTime(&now);
120
121    return (time_t) ((((((__int64)now.dwHighDateTime) << 32)|now.dwLowDateTime) - 116444736000000000L)/10000000);
122}
123#else
124# define zend_accel_get_time() time(NULL)
125#endif
126
127static inline int is_stream_path(const char *filename)
128{
129    const char *p;
130
131    for (p = filename; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
132    return ((*p == ':') && (p - filename > 1) && (p[1] == '/') && (p[2] == '/'));
133}
134
135static inline int is_cacheable_stream_path(const char *filename)
136{
137    return memcmp(filename, "file://", sizeof("file://") - 1) == 0 ||
138           memcmp(filename, "phar://", sizeof("phar://") - 1) == 0;
139}
140
141/* O+ overrides PHP chdir() function and remembers the current working directory
142 * in ZCG(cwd) and ZCG(cwd_len). Later accel_getcwd() can use stored value and
143 * avoid getcwd() call.
144 */
145static ZEND_FUNCTION(accel_chdir)
146{
147    char cwd[MAXPATHLEN];
148
149    orig_chdir(INTERNAL_FUNCTION_PARAM_PASSTHRU);
150    if (VCWD_GETCWD(cwd, MAXPATHLEN)) {
151        if (ZCG(cwd)) {
152            efree(ZCG(cwd));
153        }
154        ZCG(cwd_len) = strlen(cwd);
155        ZCG(cwd) = estrndup(cwd, ZCG(cwd_len));
156    } else {
157        if (ZCG(cwd)) {
158            efree(ZCG(cwd));
159            ZCG(cwd) = NULL;
160        }
161    }
162}
163
164static inline char* accel_getcwd(int *cwd_len TSRMLS_DC)
165{
166    if (ZCG(cwd)) {
167        *cwd_len = ZCG(cwd_len);
168        return ZCG(cwd);
169    } else {
170        char cwd[MAXPATHLEN + 1];
171
172        if (!VCWD_GETCWD(cwd, MAXPATHLEN)) {
173            return NULL;
174        }
175        *cwd_len = ZCG(cwd_len) = strlen(cwd);
176        ZCG(cwd) = estrndup(cwd, ZCG(cwd_len));
177        return ZCG(cwd);
178    }
179}
180
181void zend_accel_schedule_restart_if_necessary(zend_accel_restart_reason reason TSRMLS_DC)
182{
183    if ((((double) ZSMMG(wasted_shared_memory)) / ZCG(accel_directives).memory_consumption) >= ZCG(accel_directives).max_wasted_percentage) {
184        zend_accel_schedule_restart(reason TSRMLS_CC);
185    }
186}
187
188/* O+ tracks changes of "include_path" directive. It stores all the requested
189 * values in ZCG(include_paths) shared hash table, current value in
190 * ZCG(include_path)/ZCG(include_path_len) and one letter "path key" in
191 * ZCG(include_path_key).
192 */
193static ZEND_INI_MH(accel_include_path_on_modify)
194{
195    int ret = orig_include_path_on_modify(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
196
197    ZCG(include_path_key) = NULL;
198    if (ret == SUCCESS) {
199        ZCG(include_path) = new_value->val;
200        if (ZCG(include_path) && *ZCG(include_path)) {
201            ZCG(include_path_len) = new_value->len;
202
203            if (ZCG(enabled) && accel_startup_ok &&
204                (ZCG(counted) || ZCSG(accelerator_enabled))) {
205
206                ZCG(include_path_key) = zend_accel_hash_find(&ZCSG(include_paths), ZCG(include_path), ZCG(include_path_len));
207                if (!ZCG(include_path_key) &&
208                    !zend_accel_hash_is_full(&ZCSG(include_paths))) {
209                    SHM_UNPROTECT();
210                    zend_shared_alloc_lock(TSRMLS_C);
211
212                    ZCG(include_path_key) = zend_accel_hash_find(&ZCSG(include_paths), ZCG(include_path), ZCG(include_path_len));
213                    if (!ZCG(include_path_key) &&
214                        !zend_accel_hash_is_full(&ZCSG(include_paths))) {
215                        char *key;
216
217                        key = zend_shared_alloc(ZCG(include_path_len) + 2);
218                        if (key) {
219                            memcpy(key, ZCG(include_path), ZCG(include_path_len) + 1);
220                            key[ZCG(include_path_len) + 1] = 'A' + ZCSG(include_paths).num_entries;
221                            ZCG(include_path_key) = key + ZCG(include_path_len) + 1;
222                            zend_accel_hash_update(&ZCSG(include_paths), key, ZCG(include_path_len), 0, ZCG(include_path_key));
223                        } else {
224                            zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM TSRMLS_CC);
225                        }
226                    }
227
228                    zend_shared_alloc_unlock(TSRMLS_C);
229                    SHM_PROTECT();
230                }
231            } else {
232                ZCG(include_path_check) = 1;
233            }
234        } else {
235            ZCG(include_path) = "";
236            ZCG(include_path_len) = 0;
237        }
238    }
239    return ret;
240}
241
242/* Interned strings support */
243static zend_string *(*orig_new_interned_string)(zend_string *str TSRMLS_DC);
244static void (*orig_interned_strings_snapshot)(TSRMLS_D);
245static void (*orig_interned_strings_restore)(TSRMLS_D);
246
247/* O+ disables creation of interned strings by regular PHP compiler, instead,
248 * it creates interned strings in shared memory when saves a script.
249 * Such interned strings are shared across all PHP processes
250 */
251static zend_string *accel_new_interned_string_for_php(zend_string *str TSRMLS_DC)
252{
253    return str;
254}
255
256static void accel_interned_strings_snapshot_for_php(TSRMLS_D)
257{
258}
259
260static void accel_interned_strings_restore_for_php(TSRMLS_D)
261{
262}
263
264#ifndef ZTS
265static void accel_interned_strings_restore_state(TSRMLS_D)
266{
267    uint idx = ZCSG(interned_strings).nNumUsed;
268    uint nIndex;
269    Bucket *p;
270
271    ZCSG(interned_strings_top) = ZCSG(interned_strings_saved_top);
272    while (idx > 0) {
273        idx--;
274        p = ZCSG(interned_strings).arData + idx;
275        if ((char*)p->key < ZCSG(interned_strings_top)) break;
276        ZCSG(interned_strings).nNumUsed--;
277        ZCSG(interned_strings).nNumOfElements--;
278
279        nIndex = p->h & ZCSG(interned_strings).nTableMask;
280        if (ZCSG(interned_strings).arHash[nIndex] == idx) {
281            ZCSG(interned_strings).arHash[nIndex] = Z_NEXT(p->val);
282        } else {
283            uint prev = ZCSG(interned_strings).arHash[nIndex];
284            while (Z_NEXT(ZCSG(interned_strings).arData[prev].val) != idx) {
285                prev = Z_NEXT(ZCSG(interned_strings).arData[prev].val);
286            }
287            Z_NEXT(ZCSG(interned_strings).arData[prev].val) = Z_NEXT(p->val);
288        }
289    }
290}
291
292static void accel_interned_strings_save_state(TSRMLS_D)
293{
294    ZCSG(interned_strings_saved_top) = ZCSG(interned_strings_top);
295}
296#endif
297
298zend_string *accel_new_interned_string(zend_string *str TSRMLS_DC)
299{
300/* for now interned strings are supported only for non-ZTS build */
301#ifndef ZTS
302    zend_ulong h;
303    uint nIndex;
304    uint idx;
305    Bucket *p;
306
307    if (IS_ACCEL_INTERNED(str)) {
308        /* this is already an interned string */
309        return str;
310    }
311
312    h = zend_string_hash_val(str);
313    nIndex = h & ZCSG(interned_strings).nTableMask;
314
315    /* check for existing interned string */
316    idx = ZCSG(interned_strings).arHash[nIndex];
317    while (idx != INVALID_IDX) {
318        p = ZCSG(interned_strings).arData + idx;
319        if ((p->h == h) && (p->key->len == str->len)) {
320            if (!memcmp(p->key->val, str->val, str->len)) {
321                zend_string_release(str);
322                return p->key;
323            }
324        }
325        idx = Z_NEXT(p->val);
326    }
327
328    if (ZCSG(interned_strings_top) + ZEND_MM_ALIGNED_SIZE(_STR_HEADER_SIZE + str->len + 1) >=
329        ZCSG(interned_strings_end)) {
330        /* no memory, return the same non-interned string */
331        zend_accel_error(ACCEL_LOG_WARNING, "Interned string buffer overflow");
332        return str;
333    }
334
335    /* create new interning string in shared interned strings buffer */
336
337    idx = ZCSG(interned_strings).nNumUsed++;
338    ZCSG(interned_strings).nNumOfElements++;
339    p = ZCSG(interned_strings).arData + idx;
340    p->key = (zend_string*) ZCSG(interned_strings_top);
341    ZCSG(interned_strings_top) += ZEND_MM_ALIGNED_SIZE(_STR_HEADER_SIZE + str->len + 1);
342    p->h = h;
343    GC_REFCOUNT(p->key) = 1;
344#if 1
345    /* optimized single assignment */
346    GC_TYPE_INFO(p->key) = IS_STRING | ((IS_STR_INTERNED | IS_STR_PERMANENT) << 8);
347#else
348    GC_TYPE(p->key) = IS_STRING;
349    GC_FLAGS(p->key) = IS_STR_INTERNED | IS_STR_PERMANENT;
350#endif
351    p->key->h = str->h;
352    p->key->len = str->len;
353    memcpy(p->key->val, str->val, str->len);
354    ZVAL_STR(&p->val, p->key);
355    Z_NEXT(p->val) = ZCSG(interned_strings).arHash[nIndex];
356    ZCSG(interned_strings).arHash[nIndex] = idx;
357    zend_string_release(str);
358    return p->key;
359#else
360    return str;
361#endif
362}
363
364#ifndef ZTS
365/* Copy PHP interned strings from PHP process memory into the shared memory */
366static void accel_use_shm_interned_strings(TSRMLS_D)
367{
368    uint idx, j;
369    Bucket *p, *q;
370
371    /* empty string */
372    CG(empty_string) = accel_new_interned_string(CG(empty_string) TSRMLS_CC);
373    for (j = 0; j < 256; j++) {
374        char s[2];
375        s[0] = j;
376        s[1] = 0;
377        CG(one_char_string)[j] = accel_new_interned_string(zend_string_init(s, 1, 0) TSRMLS_CC);
378    }
379
380    /* function table hash keys */
381    for (idx = 0; idx < CG(function_table)->nNumUsed; idx++) {
382        p = CG(function_table)->arData + idx;
383        if (Z_TYPE(p->val) == IS_UNDEF) continue;
384        if (p->key) {
385            p->key = accel_new_interned_string(p->key TSRMLS_CC);
386        }
387    }
388
389    /* class table hash keys, class names, properties, methods, constants, etc */
390    for (idx = 0; idx < CG(class_table)->nNumUsed; idx++) {
391        zend_class_entry *ce;
392
393        p = CG(class_table)->arData + idx;
394        if (Z_TYPE(p->val) == IS_UNDEF) continue;
395        ce = (zend_class_entry*)Z_PTR(p->val);
396
397        if (p->key) {
398            p->key = accel_new_interned_string(p->key TSRMLS_CC);
399        }
400
401        if (ce->name) {
402            ce->name = accel_new_interned_string(ce->name TSRMLS_CC);
403        }
404
405        for (j = 0; j < ce->properties_info.nNumUsed; j++) {
406            zend_property_info *info;
407
408            q = ce->properties_info.arData + j;
409            if (Z_TYPE(q->val) == IS_UNDEF) continue;
410
411            info = (zend_property_info*)Z_PTR(q->val);
412
413            if (q->key) {
414                q->key = accel_new_interned_string(q->key TSRMLS_CC);
415            }
416
417            if (info->name) {
418                info->name = accel_new_interned_string(info->name TSRMLS_CC);
419            }
420        }
421
422        for (j = 0; j < ce->function_table.nNumUsed; j++) {
423            q = ce->function_table.arData + j;
424            if (Z_TYPE(q->val) == IS_UNDEF) continue;
425            if (q->key) {
426                q->key = accel_new_interned_string(q->key TSRMLS_CC);
427            }
428        }
429
430        for (j = 0; j < ce->constants_table.nNumUsed; j++) {
431            q = ce->constants_table.arData + j;
432            if (!Z_TYPE(q->val) == IS_UNDEF) continue;
433            if (q->key) {
434                q->key = accel_new_interned_string(q->key TSRMLS_CC);
435            }
436        }
437    }
438
439    /* constant hash keys */
440    for (idx = 0; idx < EG(zend_constants)->nNumUsed; idx++) {
441        p = EG(zend_constants)->arData + idx;
442        if (!Z_TYPE(p->val) == IS_UNDEF) continue;
443        if (p->key) {
444            p->key = accel_new_interned_string(p->key TSRMLS_CC);
445        }
446    }
447
448    /* auto globals hash keys and names */
449    for (idx = 0; idx < CG(auto_globals)->nNumUsed; idx++) {
450        zend_auto_global *auto_global;
451
452        p = CG(auto_globals)->arData + idx;
453        if (Z_TYPE(p->val) == IS_UNDEF) continue;
454
455        auto_global = (zend_auto_global*)Z_PTR(p->val);;
456
457        auto_global->name = accel_new_interned_string(auto_global->name TSRMLS_CC);
458        if (p->key) {
459            p->key = accel_new_interned_string(p->key TSRMLS_CC);
460        }
461    }
462}
463#endif
464
465static inline void accel_restart_enter(TSRMLS_D)
466{
467#ifdef ZEND_WIN32
468    INCREMENT(restart_in);
469#else
470    static const FLOCK_STRUCTURE(restart_in_progress, F_WRLCK, SEEK_SET, 2, 1);
471
472    if (fcntl(lock_file, F_SETLK, &restart_in_progress) == -1) {
473        zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(+1):  %s (%d)", strerror(errno), errno);
474    }
475#endif
476    ZCSG(restart_in_progress) = 1;
477}
478
479static inline void accel_restart_leave(TSRMLS_D)
480{
481#ifdef ZEND_WIN32
482    ZCSG(restart_in_progress) = 0;
483    DECREMENT(restart_in);
484#else
485    static const FLOCK_STRUCTURE(restart_finished, F_UNLCK, SEEK_SET, 2, 1);
486
487    ZCSG(restart_in_progress) = 0;
488    if (fcntl(lock_file, F_SETLK, &restart_finished) == -1) {
489        zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(-1):  %s (%d)", strerror(errno), errno);
490    }
491#endif
492}
493
494static inline int accel_restart_is_active(TSRMLS_D)
495{
496    if (ZCSG(restart_in_progress)) {
497#ifndef ZEND_WIN32
498        FLOCK_STRUCTURE(restart_check, F_WRLCK, SEEK_SET, 2, 1);
499
500        if (fcntl(lock_file, F_GETLK, &restart_check) == -1) {
501            zend_accel_error(ACCEL_LOG_DEBUG, "RestartC:  %s (%d)", strerror(errno), errno);
502            return FAILURE;
503        }
504        if (restart_check.l_type == F_UNLCK) {
505            ZCSG(restart_in_progress) = 0;
506            return 0;
507        } else {
508            return 1;
509        }
510#else
511        return LOCKVAL(restart_in) != 0;
512#endif
513    }
514    return 0;
515}
516
517/* Creates a read lock for SHM access */
518static inline void accel_activate_add(TSRMLS_D)
519{
520#ifdef ZEND_WIN32
521    INCREMENT(mem_usage);
522#else
523    static const FLOCK_STRUCTURE(mem_usage_lock, F_RDLCK, SEEK_SET, 1, 1);
524
525    if (fcntl(lock_file, F_SETLK, &mem_usage_lock) == -1) {
526        zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(+1):  %s (%d)", strerror(errno), errno);
527    }
528#endif
529}
530
531/* Releases a lock for SHM access */
532static inline void accel_deactivate_sub(TSRMLS_D)
533{
534#ifdef ZEND_WIN32
535    if (ZCG(counted)) {
536        DECREMENT(mem_usage);
537        ZCG(counted) = 0;
538    }
539#else
540    static const FLOCK_STRUCTURE(mem_usage_unlock, F_UNLCK, SEEK_SET, 1, 1);
541
542    if (fcntl(lock_file, F_SETLK, &mem_usage_unlock) == -1) {
543        zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(-1):  %s (%d)", strerror(errno), errno);
544    }
545#endif
546}
547
548static inline void accel_unlock_all(TSRMLS_D)
549{
550#ifdef ZEND_WIN32
551    accel_deactivate_sub(TSRMLS_C);
552#else
553    static const FLOCK_STRUCTURE(mem_usage_unlock_all, F_UNLCK, SEEK_SET, 0, 0);
554
555    if (fcntl(lock_file, F_SETLK, &mem_usage_unlock_all) == -1) {
556        zend_accel_error(ACCEL_LOG_DEBUG, "UnlockAll:  %s (%d)", strerror(errno), errno);
557    }
558#endif
559}
560
561#ifndef ZEND_WIN32
562static inline void kill_all_lockers(struct flock *mem_usage_check)
563{
564    int tries = 10;
565
566    /* so that other process won't try to force while we are busy cleaning up */
567    ZCSG(force_restart_time) = 0;
568    while (mem_usage_check->l_pid > 0) {
569        while (tries--) {
570            zend_accel_error(ACCEL_LOG_INFO, "Killed locker %d", mem_usage_check->l_pid);
571            if (kill(mem_usage_check->l_pid, SIGKILL)) {
572                break;
573            }
574            /* give it a chance to die */
575            usleep(20000);
576            if (kill(mem_usage_check->l_pid, 0)) {
577                /* can't kill it */
578                break;
579            }
580            usleep(10000);
581        }
582        if (!tries) {
583            zend_accel_error(ACCEL_LOG_INFO, "Can't kill %d after 20 tries!", mem_usage_check->l_pid);
584            ZCSG(force_restart_time) = time(NULL); /* restore forced restart request */
585        }
586
587        mem_usage_check->l_type = F_WRLCK;
588        mem_usage_check->l_whence = SEEK_SET;
589        mem_usage_check->l_start = 1;
590        mem_usage_check->l_len = 1;
591        mem_usage_check->l_pid = -1;
592        if (fcntl(lock_file, F_GETLK, mem_usage_check) == -1) {
593            zend_accel_error(ACCEL_LOG_DEBUG, "KLockers:  %s (%d)", strerror(errno), errno);
594            break;
595        }
596
597        if (mem_usage_check->l_type == F_UNLCK || mem_usage_check->l_pid <= 0) {
598            break;
599        }
600    }
601}
602#endif
603
604static inline int accel_is_inactive(TSRMLS_D)
605{
606#ifdef ZEND_WIN32
607    if (LOCKVAL(mem_usage) == 0) {
608        return SUCCESS;
609    }
610#else
611    FLOCK_STRUCTURE(mem_usage_check, F_WRLCK, SEEK_SET, 1, 1);
612
613    mem_usage_check.l_pid = -1;
614    if (fcntl(lock_file, F_GETLK, &mem_usage_check) == -1) {
615        zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC:  %s (%d)", strerror(errno), errno);
616        return FAILURE;
617    }
618    if (mem_usage_check.l_type == F_UNLCK) {
619        return SUCCESS;
620    }
621
622    if (ZCG(accel_directives).force_restart_timeout
623        && ZCSG(force_restart_time)
624        && time(NULL) >= ZCSG(force_restart_time)) {
625        zend_accel_error(ACCEL_LOG_WARNING, "Forced restart at %d (after %d seconds), locked by %d", time(NULL), ZCG(accel_directives).force_restart_timeout, mem_usage_check.l_pid);
626        kill_all_lockers(&mem_usage_check);
627
628        return FAILURE; /* next request should be able to restart it */
629    }
630#endif
631
632    return FAILURE;
633}
634
635static int zend_get_stream_timestamp(const char *filename, zend_stat_t *statbuf TSRMLS_DC)
636{
637    php_stream_wrapper *wrapper;
638    php_stream_statbuf stream_statbuf;
639    int ret, er;
640
641    if (!filename) {
642        return FAILURE;
643    }
644
645    wrapper = php_stream_locate_url_wrapper(filename, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC);
646    if (!wrapper) {
647        return FAILURE;
648    }
649    if (!wrapper->wops || !wrapper->wops->url_stat) {
650        statbuf->st_mtime = 1;
651        return SUCCESS; /* anything other than 0 is considered to be a valid timestamp */
652    }
653
654    er = EG(error_reporting);
655    EG(error_reporting) = 0;
656    zend_try {
657        ret = wrapper->wops->url_stat(wrapper, (char*)filename, PHP_STREAM_URL_STAT_QUIET, &stream_statbuf, NULL TSRMLS_CC);
658    } zend_catch {
659        ret = -1;
660    } zend_end_try();
661    EG(error_reporting) = er;
662
663    if (ret != 0) {
664        return FAILURE;
665    }
666
667    *statbuf = stream_statbuf.sb;
668    return SUCCESS;
669}
670
671#if ZEND_WIN32
672static accel_time_t zend_get_file_handle_timestamp_win(zend_file_handle *file_handle, size_t *size)
673{
674    static unsigned __int64 utc_base = 0;
675    static FILETIME utc_base_ft;
676    WIN32_FILE_ATTRIBUTE_DATA fdata;
677
678    if (!file_handle->opened_path) {
679        return 0;
680    }
681
682    if (!utc_base) {
683        SYSTEMTIME st;
684
685        st.wYear = 1970;
686        st.wMonth = 1;
687        st.wDay = 1;
688        st.wHour = 0;
689        st.wMinute = 0;
690        st.wSecond = 0;
691        st.wMilliseconds = 0;
692
693        SystemTimeToFileTime (&st, &utc_base_ft);
694        utc_base = (((unsigned __int64)utc_base_ft.dwHighDateTime) << 32) + utc_base_ft.dwLowDateTime;
695    }
696
697    if (GetFileAttributesEx(file_handle->opened_path, GetFileExInfoStandard, &fdata) != 0) {
698        unsigned __int64 ftime;
699
700        if (CompareFileTime (&fdata.ftLastWriteTime, &utc_base_ft) < 0) {
701            return 0;
702        }
703
704        ftime = (((unsigned __int64)fdata.ftLastWriteTime.dwHighDateTime) << 32) + fdata.ftLastWriteTime.dwLowDateTime - utc_base;
705        ftime /= 10000000L;
706
707        if (size) {
708            *size = (size_t)((((unsigned __int64)fdata.nFileSizeHigh) << 32) + (unsigned __int64)fdata.nFileSizeLow);
709        }
710        return (accel_time_t)ftime;
711    }
712    return 0;
713}
714#endif
715
716static accel_time_t zend_get_file_handle_timestamp(zend_file_handle *file_handle, size_t *size TSRMLS_DC)
717{
718    zend_stat_t statbuf;
719#ifdef ZEND_WIN32
720    accel_time_t res;
721#endif
722
723    if (sapi_module.get_stat &&
724        !EG(current_execute_data) &&
725        file_handle->filename == SG(request_info).path_translated) {
726
727        zend_stat_t *tmpbuf = sapi_module.get_stat(TSRMLS_C);
728
729        if (tmpbuf) {
730            if (size) {
731                *size = tmpbuf->st_size;
732            }
733            return tmpbuf->st_mtime;
734        }
735    }
736
737#ifdef ZEND_WIN32
738    res = zend_get_file_handle_timestamp_win(file_handle, size);
739    if (res) {
740        return res;
741    }
742#endif
743
744    switch (file_handle->type) {
745        case ZEND_HANDLE_FD:
746            if (zend_fstat(file_handle->handle.fd, &statbuf) == -1) {
747                return 0;
748            }
749            break;
750        case ZEND_HANDLE_FP:
751            if (zend_fstat(fileno(file_handle->handle.fp), &statbuf) == -1) {
752                if (zend_get_stream_timestamp(file_handle->filename, &statbuf TSRMLS_CC) != SUCCESS) {
753                    return 0;
754                }
755            }
756            break;
757        case ZEND_HANDLE_FILENAME:
758        case ZEND_HANDLE_MAPPED:
759            {
760                char *file_path = file_handle->opened_path;
761
762                if (file_path) {
763                    if (is_stream_path(file_path)) {
764                        if (zend_get_stream_timestamp(file_path, &statbuf TSRMLS_CC) == SUCCESS) {
765                            break;
766                        }
767                    }
768                    if (VCWD_STAT(file_path, &statbuf) != -1) {
769                        break;
770                    }
771                }
772
773                if (zend_get_stream_timestamp(file_handle->filename, &statbuf TSRMLS_CC) != SUCCESS) {
774                    return 0;
775                }
776                break;
777            }
778        case ZEND_HANDLE_STREAM:
779            {
780                php_stream *stream = (php_stream *)file_handle->handle.stream.handle;
781                php_stream_statbuf sb;
782                int ret, er;
783
784                if (!stream ||
785                    !stream->ops ||
786                    !stream->ops->stat) {
787                    return 0;
788                }
789
790                er = EG(error_reporting);
791                EG(error_reporting) = 0;
792                zend_try {
793                    ret = stream->ops->stat(stream, &sb TSRMLS_CC);
794                } zend_catch {
795                    ret = -1;
796                } zend_end_try();
797                EG(error_reporting) = er;
798                if (ret != 0) {
799                    return 0;
800                }
801
802                statbuf = sb.sb;
803            }
804            break;
805
806        default:
807            return 0;
808    }
809
810    if (size) {
811        *size = statbuf.st_size;
812    }
813    return statbuf.st_mtime;
814}
815
816static inline int do_validate_timestamps(zend_persistent_script *persistent_script, zend_file_handle *file_handle TSRMLS_DC)
817{
818    zend_file_handle ps_handle;
819    char *full_path_ptr = NULL;
820
821    /** check that the persistant script is indeed the same file we cached
822     * (if part of the path is a symlink than it possible that the user will change it)
823     * See bug #15140
824     */
825    if (file_handle->opened_path) {
826        if (strcmp(persistent_script->full_path->val, file_handle->opened_path) != 0) {
827            return FAILURE;
828        }
829    } else {
830        full_path_ptr = accelerator_orig_zend_resolve_path(file_handle->filename, strlen(file_handle->filename) TSRMLS_CC);
831        if (full_path_ptr && strcmp(persistent_script->full_path->val, full_path_ptr) != 0) {
832            efree(full_path_ptr);
833            return FAILURE;
834        }
835        file_handle->opened_path = full_path_ptr;
836    }
837
838    if (persistent_script->timestamp == 0) {
839        if (full_path_ptr) {
840            efree(full_path_ptr);
841            file_handle->opened_path = NULL;
842        }
843        return FAILURE;
844    }
845
846    if (zend_get_file_handle_timestamp(file_handle, NULL TSRMLS_CC) == persistent_script->timestamp) {
847        if (full_path_ptr) {
848            efree(full_path_ptr);
849            file_handle->opened_path = NULL;
850        }
851        return SUCCESS;
852    }
853    if (full_path_ptr) {
854        efree(full_path_ptr);
855        file_handle->opened_path = NULL;
856    }
857
858    ps_handle.type = ZEND_HANDLE_FILENAME;
859    ps_handle.filename = persistent_script->full_path->val;
860    ps_handle.opened_path = persistent_script->full_path->val;
861
862    if (zend_get_file_handle_timestamp(&ps_handle, NULL TSRMLS_CC) == persistent_script->timestamp) {
863        return SUCCESS;
864    }
865
866    return FAILURE;
867}
868
869int validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle TSRMLS_DC)
870{
871    if (ZCG(accel_directives).revalidate_freq &&
872        (persistent_script->dynamic_members.revalidate >= ZCSG(revalidate_at))) {
873        return SUCCESS;
874    } else if (do_validate_timestamps(persistent_script, file_handle TSRMLS_CC) == FAILURE) {
875        return FAILURE;
876    } else {
877        persistent_script->dynamic_members.revalidate = ZCSG(revalidate_at);
878        return SUCCESS;
879    }
880}
881
882static unsigned int zend_accel_script_checksum(zend_persistent_script *persistent_script)
883{
884    signed char *mem = (signed char*)persistent_script->mem;
885    size_t size = persistent_script->size;
886    size_t persistent_script_check_block_size = ((char *)&(persistent_script->dynamic_members)) - (char *)persistent_script;
887    unsigned int checksum = ADLER32_INIT;
888
889    if (mem < (signed char*)persistent_script) {
890        checksum = zend_adler32(checksum, mem, (signed char*)persistent_script - mem);
891        size -= (signed char*)persistent_script - mem;
892        mem  += (signed char*)persistent_script - mem;
893    }
894
895    zend_adler32(checksum, mem, persistent_script_check_block_size);
896    mem  += sizeof(*persistent_script);
897    size -= sizeof(*persistent_script);
898
899    if (size > 0) {
900        checksum = zend_adler32(checksum, mem, size);
901    }
902    return checksum;
903}
904
905/* Instead of resolving full real path name each time we need to identify file,
906 * we create a key that consist from requested file name, current working
907 * directory, current include_path, etc */
908char *accel_make_persistent_key_ex(zend_file_handle *file_handle, int path_length, int *key_len TSRMLS_DC)
909{
910    int key_length;
911
912    /* CWD and include_path don't matter for absolute file names and streams */
913    if (ZCG(accel_directives).use_cwd &&
914        !IS_ABSOLUTE_PATH(file_handle->filename, path_length) &&
915        !is_stream_path(file_handle->filename)) {
916        char *include_path = NULL;
917        int include_path_len = 0;
918        const char *parent_script = NULL;
919        int parent_script_len = 0;
920        int cur_len = 0;
921        int cwd_len;
922        char *cwd;
923
924        if ((cwd = accel_getcwd(&cwd_len TSRMLS_CC)) == NULL) {
925            /* we don't handle this well for now. */
926            zend_accel_error(ACCEL_LOG_INFO, "getcwd() failed for '%s' (%d), please try to set opcache.use_cwd to 0 in ini file", file_handle->filename, errno);
927            if (file_handle->opened_path) {
928                cwd = file_handle->opened_path;
929                cwd_len = strlen(cwd);
930            } else {
931                ZCG(key_len) = 0;
932                return NULL;
933            }
934        }
935
936        if (ZCG(include_path_key)) {
937            include_path = ZCG(include_path_key);
938            include_path_len = 1;
939        } else {
940            include_path = ZCG(include_path);
941            include_path_len = ZCG(include_path_len);
942            if (ZCG(include_path_check) &&
943                ZCG(enabled) && accel_startup_ok &&
944                (ZCG(counted) || ZCSG(accelerator_enabled)) &&
945                !zend_accel_hash_find(&ZCSG(include_paths), ZCG(include_path), ZCG(include_path_len)) &&
946                !zend_accel_hash_is_full(&ZCSG(include_paths))) {
947
948                SHM_UNPROTECT();
949                zend_shared_alloc_lock(TSRMLS_C);
950
951                ZCG(include_path_key) = zend_accel_hash_find(&ZCSG(include_paths), ZCG(include_path), ZCG(include_path_len));
952                if (ZCG(include_path_key)) {
953                    include_path = ZCG(include_path_key);
954                    include_path_len = 1;
955                } else if (!zend_accel_hash_is_full(&ZCSG(include_paths))) {
956                    char *key;
957
958                    key = zend_shared_alloc(ZCG(include_path_len) + 2);
959                    if (key) {
960                        memcpy(key, ZCG(include_path), ZCG(include_path_len) + 1);
961                        key[ZCG(include_path_len) + 1] = 'A' + ZCSG(include_paths).num_entries;
962                        ZCG(include_path_key) = key + ZCG(include_path_len) + 1;
963                        zend_accel_hash_update(&ZCSG(include_paths), key, ZCG(include_path_len), 0, ZCG(include_path_key));
964                        include_path = ZCG(include_path_key);
965                        include_path_len = 1;
966                    } else {
967                        zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM TSRMLS_CC);
968                    }
969                }
970
971                zend_shared_alloc_unlock(TSRMLS_C);
972                SHM_PROTECT();
973            }
974        }
975
976        /* Here we add to the key the parent script directory,
977           since fopen_wrappers from version 4.0.7 use current script's path
978           in include path too.
979        */
980        if (EG(current_execute_data) &&
981            (parent_script = zend_get_executed_filename(TSRMLS_C)) != NULL &&
982            parent_script[0] != '[') {
983
984            parent_script_len = strlen(parent_script);
985            while ((--parent_script_len > 0) && !IS_SLASH(parent_script[parent_script_len]));
986        }
987
988        /* Calculate key length */
989        key_length = cwd_len + path_length + include_path_len + 2;
990        if (parent_script_len) {
991            key_length += parent_script_len + 1;
992        }
993
994        /* Generate key
995         * Note - the include_path must be the last element in the key,
996         * since in itself, it may include colons (which we use to separate
997         * different components of the key)
998         */
999        if ((size_t)key_length >= sizeof(ZCG(key))) {
1000            ZCG(key_len) = 0;
1001            return NULL;
1002        }
1003        memcpy(ZCG(key), cwd, cwd_len);
1004        ZCG(key)[cwd_len] = ':';
1005
1006        memcpy(ZCG(key) + cwd_len + 1, file_handle->filename, path_length);
1007
1008        ZCG(key)[cwd_len + 1 + path_length] = ':';
1009
1010        cur_len = cwd_len + 1 + path_length + 1;
1011
1012        if (parent_script_len) {
1013            memcpy(ZCG(key) + cur_len, parent_script, parent_script_len);
1014            cur_len += parent_script_len;
1015            ZCG(key)[cur_len] = ':';
1016            cur_len++;
1017        }
1018        memcpy(ZCG(key) + cur_len, include_path, include_path_len);
1019        ZCG(key)[key_length] = '\0';
1020    } else {
1021        /* not use_cwd */
1022        key_length = path_length;
1023        if ((size_t)key_length >= sizeof(ZCG(key))) {
1024            ZCG(key_len) = 0;
1025            return NULL;
1026        }
1027        memcpy(ZCG(key), file_handle->filename, key_length + 1);
1028    }
1029
1030    *key_len = ZCG(key_len) = key_length;
1031    return ZCG(key);
1032}
1033
1034static inline char *accel_make_persistent_key(zend_file_handle *file_handle, int *key_len TSRMLS_DC)
1035{
1036    return accel_make_persistent_key_ex(file_handle, strlen(file_handle->filename), key_len TSRMLS_CC);
1037}
1038
1039int zend_accel_invalidate(const char *filename, int filename_len, zend_bool force TSRMLS_DC)
1040{
1041    char *realpath;
1042    zend_persistent_script *persistent_script;
1043
1044    if (!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled) || accelerator_shm_read_lock(TSRMLS_C) != SUCCESS) {
1045        return FAILURE;
1046    }
1047
1048    realpath = accelerator_orig_zend_resolve_path(filename, filename_len TSRMLS_CC);
1049
1050    if (!realpath) {
1051        return FAILURE;
1052    }
1053
1054    persistent_script = zend_accel_hash_find(&ZCSG(hash), realpath, strlen(realpath));
1055    if (persistent_script && !persistent_script->corrupted) {
1056        zend_file_handle file_handle;
1057
1058        file_handle.type = ZEND_HANDLE_FILENAME;
1059        file_handle.filename = realpath;
1060        file_handle.opened_path = realpath;
1061
1062        if (force ||
1063            !ZCG(accel_directives).validate_timestamps ||
1064            do_validate_timestamps(persistent_script, &file_handle TSRMLS_CC) == FAILURE) {
1065            SHM_UNPROTECT();
1066            zend_shared_alloc_lock(TSRMLS_C);
1067            if (!persistent_script->corrupted) {
1068                persistent_script->corrupted = 1;
1069                persistent_script->timestamp = 0;
1070                ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
1071                if (ZSMMG(memory_exhausted)) {
1072                    zend_accel_restart_reason reason =
1073                        zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
1074                    zend_accel_schedule_restart_if_necessary(reason TSRMLS_CC);
1075                }
1076            }
1077            zend_shared_alloc_unlock(TSRMLS_C);
1078            SHM_PROTECT();
1079        }
1080    }
1081
1082    accelerator_shm_read_unlock(TSRMLS_C);
1083    efree(realpath);
1084
1085    return SUCCESS;
1086}
1087
1088/* Adds another key for existing cached script */
1089static void zend_accel_add_key(char *key, unsigned int key_length, zend_accel_hash_entry *bucket TSRMLS_DC)
1090{
1091    if (!zend_accel_hash_find(&ZCSG(hash), key, key_length)) {
1092        if (zend_accel_hash_is_full(&ZCSG(hash))) {
1093            zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
1094            ZSMMG(memory_exhausted) = 1;
1095            zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH TSRMLS_CC);
1096        } else {
1097            char *new_key = zend_shared_alloc(key_length + 1);
1098            if (new_key) {
1099                memcpy(new_key, key, key_length + 1);
1100                if (zend_accel_hash_update(&ZCSG(hash), new_key, key_length, 1, bucket)) {
1101                    zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", new_key);
1102                }
1103            } else {
1104                zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM TSRMLS_CC);
1105            }
1106        }
1107    }
1108}
1109
1110static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_script *new_persistent_script, char *key, unsigned int key_length, int *from_shared_memory TSRMLS_DC)
1111{
1112    zend_accel_hash_entry *bucket;
1113    uint memory_used;
1114
1115    /* Check if script may be stored in shared memory */
1116    if (!zend_accel_script_persistable(new_persistent_script)) {
1117        return new_persistent_script;
1118    }
1119
1120    if (!zend_accel_script_optimize(new_persistent_script TSRMLS_CC)) {
1121        return new_persistent_script;
1122    }
1123
1124    if (!compact_persistent_script(new_persistent_script)) {
1125        return new_persistent_script;
1126    }
1127
1128    /* exclusive lock */
1129    zend_shared_alloc_lock(TSRMLS_C);
1130
1131    if (zend_accel_hash_is_full(&ZCSG(hash))) {
1132        zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
1133        ZSMMG(memory_exhausted) = 1;
1134        zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH TSRMLS_CC);
1135        zend_shared_alloc_unlock(TSRMLS_C);
1136        return new_persistent_script;
1137    }
1138
1139    /* Check if we still need to put the file into the cache (may be it was
1140     * already stored by another process. This final check is done under
1141     * exclusive lock) */
1142    bucket = zend_accel_hash_find_entry(&ZCSG(hash), new_persistent_script->full_path->val, new_persistent_script->full_path->len);
1143    if (bucket) {
1144        zend_persistent_script *existing_persistent_script = (zend_persistent_script *)bucket->data;
1145
1146        if (!existing_persistent_script->corrupted) {
1147            if (!ZCG(accel_directives).revalidate_path &&
1148                (!ZCG(accel_directives).validate_timestamps ||
1149                 (new_persistent_script->timestamp == existing_persistent_script->timestamp))) {
1150                zend_accel_add_key(key, key_length, bucket TSRMLS_CC);
1151            }
1152            zend_shared_alloc_unlock(TSRMLS_C);
1153            return new_persistent_script;
1154        }
1155    }
1156
1157    /* Calculate the required memory size */
1158    memory_used = zend_accel_script_persist_calc(new_persistent_script, key, key_length TSRMLS_CC);
1159
1160    /* Allocate shared memory */
1161    ZCG(mem) = zend_shared_alloc(memory_used);
1162    if (!ZCG(mem)) {
1163        zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM TSRMLS_CC);
1164        zend_shared_alloc_unlock(TSRMLS_C);
1165        return new_persistent_script;
1166    }
1167
1168    /* cleanup after calculation */
1169    new_persistent_script->mem  = ZCG(mem);
1170    new_persistent_script->size = memory_used;
1171
1172    /* Copy into shared memory */
1173    new_persistent_script = zend_accel_script_persist(new_persistent_script, &key, key_length TSRMLS_CC);
1174
1175    /* Consistency check */
1176    if ((char*)new_persistent_script->mem + new_persistent_script->size != (char*)ZCG(mem)) {
1177        zend_accel_error(
1178            ((char*)new_persistent_script->mem + new_persistent_script->size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
1179            "Internal error: wrong size calculation: %s start=0x%08x, end=0x%08x, real=0x%08x\n",
1180            new_persistent_script->full_path->val,
1181            new_persistent_script->mem,
1182            (char *)new_persistent_script->mem + new_persistent_script->size,
1183            ZCG(mem));
1184    }
1185
1186    new_persistent_script->dynamic_members.checksum = zend_accel_script_checksum(new_persistent_script);
1187
1188    /* store script structure in the hash table */
1189    bucket = zend_accel_hash_update(&ZCSG(hash), new_persistent_script->full_path->val, new_persistent_script->full_path->len, 0, new_persistent_script);
1190    if (bucket) {
1191        zend_accel_error(ACCEL_LOG_INFO, "Cached script '%s'", new_persistent_script->full_path);
1192        if (!ZCG(accel_directives).revalidate_path &&
1193            /* key may contain non-persistent PHAR aliases (see issues #115 and #149) */
1194            memcmp(key, "phar://", sizeof("phar://") - 1) != 0 &&
1195            (new_persistent_script->full_path->len != key_length ||
1196             memcmp(new_persistent_script->full_path->val, key, key_length) != 0)) {
1197            /* link key to the same persistent script in hash table */
1198            if (zend_accel_hash_update(&ZCSG(hash), key, key_length, 1, bucket)) {
1199                zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", key);
1200            } else {
1201                zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
1202                ZSMMG(memory_exhausted) = 1;
1203                zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH TSRMLS_CC);
1204            }
1205        }
1206    }
1207
1208    new_persistent_script->dynamic_members.memory_consumption = ZEND_ALIGNED_SIZE(new_persistent_script->size);
1209
1210    zend_shared_alloc_unlock(TSRMLS_C);
1211
1212    *from_shared_memory = 1;
1213    return new_persistent_script;
1214}
1215
1216static const struct jit_auto_global_info
1217{
1218    const char *name;
1219    size_t len;
1220} jit_auto_globals_info[] = {
1221    { "_SERVER",  sizeof("_SERVER")-1},
1222    { "_ENV",     sizeof("_ENV")-1},
1223    { "_REQUEST", sizeof("_REQUEST")-1},
1224    { "GLOBALS",  sizeof("GLOBALS")-1},
1225};
1226
1227static zend_string *jit_auto_globals_str[4];
1228
1229static int zend_accel_get_auto_globals(TSRMLS_D)
1230{
1231    int i, ag_size = (sizeof(jit_auto_globals_info) / sizeof(jit_auto_globals_info[0]));
1232    int n = 1;
1233    int mask = 0;
1234
1235    for (i = 0; i < ag_size ; i++) {
1236        if (zend_hash_exists(&EG(symbol_table).ht, jit_auto_globals_str[i])) {
1237            mask |= n;
1238        }
1239        n += n;
1240    }
1241    return mask;
1242}
1243
1244static int zend_accel_get_auto_globals_no_jit(TSRMLS_D)
1245{
1246    if (zend_hash_exists(&EG(symbol_table).ht, jit_auto_globals_str[3])) {
1247        return 8;
1248    }
1249    return 0;
1250}
1251
1252static void zend_accel_set_auto_globals(int mask TSRMLS_DC)
1253{
1254    int i, ag_size = (sizeof(jit_auto_globals_info) / sizeof(jit_auto_globals_info[0]));
1255    int n = 1;
1256
1257    for (i = 0; i < ag_size ; i++) {
1258        if ((mask & n) && !(ZCG(auto_globals_mask) & n)) {
1259            ZCG(auto_globals_mask) |= n;
1260            zend_is_auto_global(jit_auto_globals_str[i] TSRMLS_CC);
1261        }
1262        n += n;
1263    }
1264}
1265
1266static void zend_accel_init_auto_globals(TSRMLS_D)
1267{
1268    int i, ag_size = (sizeof(jit_auto_globals_info) / sizeof(jit_auto_globals_info[0]));
1269
1270    for (i = 0; i < ag_size ; i++) {
1271        jit_auto_globals_str[i] = zend_string_init(jit_auto_globals_info[i].name, jit_auto_globals_info[i].len, 1);
1272        zend_string_hash_val(jit_auto_globals_str[i]);
1273        jit_auto_globals_str[i] = accel_new_interned_string(jit_auto_globals_str[i] TSRMLS_CC);
1274    }
1275}
1276
1277static zend_persistent_script *compile_and_cache_file(zend_file_handle *file_handle, int type, char *key, unsigned int key_length, zend_op_array **op_array_p, int *from_shared_memory TSRMLS_DC)
1278{
1279    zend_persistent_script *new_persistent_script;
1280    zend_op_array *orig_active_op_array;
1281    HashTable *orig_function_table, *orig_class_table;
1282    zval orig_user_error_handler;
1283    zend_op_array *op_array;
1284    int do_bailout = 0;
1285    accel_time_t timestamp = 0;
1286    uint32_t orig_compiler_options = 0;
1287
1288    /* Try to open file */
1289    if (file_handle->type == ZEND_HANDLE_FILENAME) {
1290        if (accelerator_orig_zend_stream_open_function(file_handle->filename, file_handle TSRMLS_CC) == SUCCESS) {
1291            /* key may be changed by zend_stream_open_function() */
1292            if (key == ZCG(key)) {
1293                key_length = ZCG(key_len);
1294            }
1295        } else {
1296            *op_array_p = NULL;
1297            if (type == ZEND_REQUIRE) {
1298                zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename TSRMLS_CC);
1299                zend_bailout();
1300            } else {
1301                zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename TSRMLS_CC);
1302            }
1303            return NULL;
1304        }
1305    }
1306
1307    /* check blacklist right after ensuring that file was opened */
1308    if (file_handle->opened_path && zend_accel_blacklist_is_blacklisted(&accel_blacklist, file_handle->opened_path)) {
1309        ZCSG(blacklist_misses)++;
1310        *op_array_p = accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
1311        return NULL;
1312    }
1313
1314    if (file_handle->type == ZEND_HANDLE_STREAM &&
1315        (!strstr(file_handle->filename, ".phar") ||
1316         strstr(file_handle->filename, "://"))) {
1317        char *buf;
1318        size_t size;
1319
1320        /* Stream callbacks needs to be called in context of original
1321         * function and class tables (see: https://bugs.php.net/bug.php?id=64353)
1322         */
1323        if (zend_stream_fixup(file_handle, &buf, &size TSRMLS_CC) == FAILURE) {
1324            *op_array_p = NULL;
1325            return NULL;
1326        }
1327    }
1328
1329    if (ZCG(accel_directives).validate_timestamps ||
1330        ZCG(accel_directives).file_update_protection ||
1331        ZCG(accel_directives).max_file_size > 0) {
1332        size_t size = 0;
1333
1334        /* Obtain the file timestamps, *before* actually compiling them,
1335         * otherwise we have a race-condition.
1336         */
1337        timestamp = zend_get_file_handle_timestamp(file_handle, ZCG(accel_directives).max_file_size > 0 ? &size : NULL TSRMLS_CC);
1338
1339        /* If we can't obtain a timestamp (that means file is possibly socket)
1340         *  we won't cache it
1341         */
1342        if (timestamp == 0) {
1343            *op_array_p = accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
1344            return NULL;
1345        }
1346
1347        /* check if file is too new (may be it's not written completely yet) */
1348        if (ZCG(accel_directives).file_update_protection &&
1349            (ZCG(request_time) - ZCG(accel_directives).file_update_protection < timestamp)) {
1350            *op_array_p = accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
1351            return NULL;
1352        }
1353
1354        if (ZCG(accel_directives).max_file_size > 0 && size > (size_t)ZCG(accel_directives).max_file_size) {
1355            ZCSG(blacklist_misses)++;
1356            *op_array_p = accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
1357            return NULL;
1358        }
1359    }
1360
1361    new_persistent_script = create_persistent_script();
1362
1363    /* Save the original values for the op_array, function table and class table */
1364    orig_active_op_array = CG(active_op_array);
1365    orig_function_table = CG(function_table);
1366    orig_class_table = CG(class_table);
1367    ZVAL_COPY_VALUE(&orig_user_error_handler, &EG(user_error_handler));
1368
1369    /* Override them with ours */
1370    CG(function_table) = &ZCG(function_table);
1371    EG(class_table) = CG(class_table) = &new_persistent_script->class_table;
1372    ZVAL_UNDEF(&EG(user_error_handler));
1373
1374    zend_try {
1375        orig_compiler_options = CG(compiler_options);
1376        CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY;
1377        CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES;
1378        CG(compiler_options) |= ZEND_COMPILE_DELAYED_BINDING;
1379        CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION;
1380        op_array = *op_array_p = accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
1381        CG(compiler_options) = orig_compiler_options;
1382    } zend_catch {
1383        op_array = NULL;
1384        do_bailout = 1;
1385        CG(compiler_options) = orig_compiler_options;
1386    } zend_end_try();
1387
1388    /* Restore originals */
1389    CG(active_op_array) = orig_active_op_array;
1390    CG(function_table) = orig_function_table;
1391    EG(class_table) = CG(class_table) = orig_class_table;
1392    EG(user_error_handler) = orig_user_error_handler;
1393
1394    if (!op_array) {
1395        /* compilation failed */
1396        free_persistent_script(new_persistent_script, 1);
1397        zend_accel_free_user_functions(&ZCG(function_table) TSRMLS_CC);
1398        if (do_bailout) {
1399            zend_bailout();
1400        }
1401        return NULL;
1402    }
1403
1404    /* Build the persistent_script structure.
1405       Here we aren't sure we would store it, but we will need it
1406       further anyway.
1407    */
1408    zend_accel_move_user_functions(&ZCG(function_table), &new_persistent_script->function_table TSRMLS_CC);
1409    new_persistent_script->main_op_array = *op_array;
1410
1411    efree(op_array); /* we have valid persistent_script, so it's safe to free op_array */
1412
1413    /* Fill in the ping_auto_globals_mask for the new script. If jit for auto globals is enabled we
1414       will have to ping the used auto global variables before execution */
1415    if (PG(auto_globals_jit)) {
1416        new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals(TSRMLS_C);
1417    } else {
1418        new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals_no_jit(TSRMLS_C);
1419    }
1420
1421    if (ZCG(accel_directives).validate_timestamps) {
1422        /* Obtain the file timestamps, *before* actually compiling them,
1423         * otherwise we have a race-condition.
1424         */
1425        new_persistent_script->timestamp = timestamp;
1426        new_persistent_script->dynamic_members.revalidate = ZCSG(revalidate_at);
1427    }
1428
1429    if (file_handle->opened_path) {
1430        new_persistent_script->full_path = zend_string_init(file_handle->opened_path, strlen(file_handle->opened_path), 0);
1431    } else {
1432        new_persistent_script->full_path = zend_string_init(file_handle->filename, strlen(file_handle->filename), 0);
1433    }
1434    zend_string_hash_val(new_persistent_script->full_path);
1435
1436    /* Now persistent_script structure is ready in process memory */
1437    return cache_script_in_shared_memory(new_persistent_script, key, key_length, from_shared_memory TSRMLS_CC);
1438}
1439
1440/* zend_compile() replacement */
1441zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC)
1442{
1443    zend_persistent_script *persistent_script = NULL;
1444    char *key = NULL;
1445    int key_length;
1446    int from_shared_memory; /* if the script we've got is stored in SHM */
1447
1448    if (!file_handle->filename ||
1449        !ZCG(enabled) || !accel_startup_ok ||
1450        (!ZCG(counted) && !ZCSG(accelerator_enabled)) ||
1451        (ZCSG(restart_in_progress) && accel_restart_is_active(TSRMLS_C)) ||
1452        (is_stream_path(file_handle->filename) &&
1453         !is_cacheable_stream_path(file_handle->filename))) {
1454        /* The Accelerator is disabled, act as if without the Accelerator */
1455        return accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
1456    }
1457
1458    /* Make sure we only increase the currently running processes semaphore
1459     * once each execution (this function can be called more than once on
1460     * each execution)
1461     */
1462    if (!ZCG(counted)) {
1463        ZCG(counted) = 1;
1464        accel_activate_add(TSRMLS_C);
1465    }
1466
1467    /* In case this callback is called from include_once, require_once or it's
1468     * a main FastCGI request, the key must be already calculated, and cached
1469     * persistent script already found */
1470    if ((EG(current_execute_data) == NULL &&
1471         ZCG(cache_opline) == NULL &&
1472         file_handle->filename == SG(request_info).path_translated &&
1473         ZCG(cache_persistent_script)) ||
1474        (EG(current_execute_data) &&
1475         EG(current_execute_data)->func &&
1476         ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
1477         EG(current_execute_data)->opline == ZCG(cache_opline) &&
1478         EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL &&
1479         (EG(current_execute_data)->opline->extended_value == ZEND_INCLUDE_ONCE ||
1480          EG(current_execute_data)->opline->extended_value == ZEND_REQUIRE_ONCE))) {
1481        if (!ZCG(key_len)) {
1482            return accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
1483        }
1484        /* persistent script was already found by overridden open() or
1485         * resolve_path() callbacks */
1486        persistent_script = ZCG(cache_persistent_script);
1487        key = ZCG(key);
1488        key_length = ZCG(key_len);
1489    } else {
1490        /* try to find cached script by key */
1491        if ((key = accel_make_persistent_key(file_handle, &key_length TSRMLS_CC)) == NULL) {
1492            return accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
1493        }
1494        persistent_script = zend_accel_hash_find(&ZCSG(hash), key, key_length);
1495        if (!persistent_script) {
1496            /* try to find cached script by full real path */
1497            zend_accel_hash_entry *bucket;
1498
1499            /* open file to resolve the path */
1500            if (file_handle->type == ZEND_HANDLE_FILENAME &&
1501                accelerator_orig_zend_stream_open_function(file_handle->filename, file_handle TSRMLS_CC) == FAILURE) {
1502                if (type == ZEND_REQUIRE) {
1503                    zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename TSRMLS_CC);
1504                    zend_bailout();
1505                } else {
1506                    zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename TSRMLS_CC);
1507                }
1508                return NULL;
1509            }
1510
1511            if (file_handle->opened_path &&
1512                (bucket = zend_accel_hash_find_entry(&ZCSG(hash), file_handle->opened_path, strlen(file_handle->opened_path))) != NULL) {
1513
1514                persistent_script = (zend_persistent_script *)bucket->data;
1515                if (!ZCG(accel_directives).revalidate_path &&
1516                    !persistent_script->corrupted) {
1517                    SHM_UNPROTECT();
1518                    zend_shared_alloc_lock(TSRMLS_C);
1519                    zend_accel_add_key(key, key_length, bucket TSRMLS_CC);
1520                    zend_shared_alloc_unlock(TSRMLS_C);
1521                    SHM_PROTECT();
1522                }
1523            }
1524        }
1525    }
1526
1527    /* clear cache */
1528    ZCG(cache_opline) = NULL;
1529    ZCG(cache_persistent_script) = NULL;
1530
1531    if (persistent_script && persistent_script->corrupted) {
1532        persistent_script = NULL;
1533    }
1534
1535    SHM_UNPROTECT();
1536
1537    /* If script is found then validate_timestamps if option is enabled */
1538    if (persistent_script && ZCG(accel_directives).validate_timestamps) {
1539        if (validate_timestamp_and_record(persistent_script, file_handle TSRMLS_CC) == FAILURE) {
1540            zend_shared_alloc_lock(TSRMLS_C);
1541            if (!persistent_script->corrupted) {
1542                persistent_script->corrupted = 1;
1543                persistent_script->timestamp = 0;
1544                ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
1545                if (ZSMMG(memory_exhausted)) {
1546                    zend_accel_restart_reason reason =
1547                        zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
1548                    zend_accel_schedule_restart_if_necessary(reason TSRMLS_CC);
1549                }
1550            }
1551            zend_shared_alloc_unlock(TSRMLS_C);
1552            persistent_script = NULL;
1553        }
1554    }
1555
1556    /* if turned on - check the compiled script ADLER32 checksum */
1557    if (persistent_script && ZCG(accel_directives).consistency_checks
1558        && persistent_script->dynamic_members.hits % ZCG(accel_directives).consistency_checks == 0) {
1559
1560        unsigned int checksum = zend_accel_script_checksum(persistent_script);
1561        if (checksum != persistent_script->dynamic_members.checksum ) {
1562            /* The checksum is wrong */
1563            zend_accel_error(ACCEL_LOG_INFO, "Checksum failed for '%s':  expected=0x%0.8X, found=0x%0.8X",
1564                             persistent_script->full_path, persistent_script->dynamic_members.checksum, checksum);
1565            zend_shared_alloc_lock(TSRMLS_C);
1566            if (!persistent_script->corrupted) {
1567                persistent_script->corrupted = 1;
1568                persistent_script->timestamp = 0;
1569                ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
1570                if (ZSMMG(memory_exhausted)) {
1571                    zend_accel_restart_reason reason =
1572                        zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
1573                    zend_accel_schedule_restart_if_necessary(reason TSRMLS_CC);
1574                }
1575            }
1576            zend_shared_alloc_unlock(TSRMLS_C);
1577            persistent_script = NULL;
1578        }
1579    }
1580
1581    /* If script was not found or invalidated by validate_timestamps */
1582    if (!persistent_script) {
1583        uint32_t old_const_num = zend_hash_next_free_element(EG(zend_constants));
1584        zend_op_array *op_array;
1585
1586        /* Cache miss.. */
1587        ZCSG(misses)++;
1588
1589        /* No memory left. Behave like without the Accelerator */
1590        if (ZSMMG(memory_exhausted) || ZCSG(restart_pending)) {
1591            SHM_PROTECT();
1592            return accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
1593        }
1594
1595        /* Try and cache the script and assume that it is returned from_shared_memory.
1596         * If it isn't compile_and_cache_file() changes the flag to 0
1597         */
1598        from_shared_memory = 0;
1599        persistent_script = compile_and_cache_file(file_handle, type, key, key_length, &op_array, &from_shared_memory TSRMLS_CC);
1600
1601        /* Caching is disabled, returning op_array;
1602         * or something went wrong during compilation, returning NULL
1603         */
1604        if (!persistent_script) {
1605            SHM_PROTECT();
1606            return op_array;
1607        }
1608        if (from_shared_memory) {
1609            /* Delete immutable arrays moved into SHM */
1610            uint32_t new_const_num = zend_hash_next_free_element(EG(zend_constants));
1611            while (new_const_num > old_const_num) {
1612                new_const_num--;
1613                zend_hash_index_del(EG(zend_constants), new_const_num);
1614            }
1615        }
1616    } else {
1617
1618#if !ZEND_WIN32
1619        ZCSG(hits)++; /* TBFixed: may lose one hit */
1620        persistent_script->dynamic_members.hits++; /* see above */
1621#else
1622        INCREMENT(hits);
1623        InterlockedIncrement64(&persistent_script->dynamic_members.hits);
1624#endif
1625
1626        /* see bug #15471 (old BTS) */
1627        if (persistent_script->full_path) {
1628            if (!EG(current_execute_data) || !EG(current_execute_data)->opline ||
1629                !EG(current_execute_data)->func ||
1630                !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
1631                EG(current_execute_data)->opline->opcode != ZEND_INCLUDE_OR_EVAL ||
1632                (EG(current_execute_data)->opline->extended_value != ZEND_INCLUDE_ONCE &&
1633                 EG(current_execute_data)->opline->extended_value != ZEND_REQUIRE_ONCE)) {
1634                if (zend_hash_add_empty_element(&EG(included_files), persistent_script->full_path) != NULL) {
1635                    /* ext/phar has to load phar's metadata into memory */
1636                    if (strstr(persistent_script->full_path->val, ".phar") && !strstr(persistent_script->full_path->val, "://")) {
1637                        php_stream_statbuf ssb;
1638                        char *fname = emalloc(sizeof("phar://") + persistent_script->full_path->len);
1639
1640                        memcpy(fname, "phar://", sizeof("phar://") - 1);
1641                        memcpy(fname + sizeof("phar://") - 1, persistent_script->full_path->val, persistent_script->full_path->len + 1);
1642                        php_stream_stat_path(fname, &ssb);
1643                        efree(fname);
1644                    }
1645                }
1646            }
1647        }
1648        zend_file_handle_dtor(file_handle TSRMLS_CC);
1649        from_shared_memory = 1;
1650    }
1651
1652    persistent_script->dynamic_members.last_used = ZCG(request_time);
1653
1654    SHM_PROTECT();
1655
1656    /* Fetch jit auto globals used in the script before execution */
1657    if (persistent_script->ping_auto_globals_mask) {
1658        zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask TSRMLS_CC);
1659    }
1660
1661    return zend_accel_load_script(persistent_script, from_shared_memory TSRMLS_CC);
1662}
1663
1664/* zend_stream_open_function() replacement for PHP 5.3 and above */
1665static int persistent_stream_open_function(const char *filename, zend_file_handle *handle TSRMLS_DC)
1666{
1667    if (ZCG(enabled) && accel_startup_ok &&
1668        (ZCG(counted) || ZCSG(accelerator_enabled)) &&
1669        !ZCSG(restart_in_progress)) {
1670
1671        /* check if callback is called from include_once or it's a main request */
1672        if ((!EG(current_execute_data) &&
1673             filename == SG(request_info).path_translated) ||
1674            (EG(current_execute_data) &&
1675             EG(current_execute_data)->func &&
1676             ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
1677             EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL &&
1678             (EG(current_execute_data)->opline->extended_value == ZEND_INCLUDE_ONCE ||
1679              EG(current_execute_data)->opline->extended_value == ZEND_REQUIRE_ONCE))) {
1680            /* we are in include_once or FastCGI request */
1681            zend_persistent_script *persistent_script;
1682
1683            handle->filename = (char*)filename;
1684            handle->free_filename = 0;
1685
1686            /* check if cached script was already found by resolve_path() */
1687            if ((EG(current_execute_data) == NULL &&
1688                 ZCG(cache_opline) == NULL &&
1689                 ZCG(cache_persistent_script) != NULL) ||
1690                (EG(current_execute_data) &&
1691                 (ZCG(cache_opline) == EG(current_execute_data)->opline))) {
1692                persistent_script = ZCG(cache_persistent_script);
1693                handle->opened_path = estrndup(persistent_script->full_path->val, persistent_script->full_path->len);
1694                handle->type = ZEND_HANDLE_FILENAME;
1695                return SUCCESS;
1696#if 0
1697            } else {
1698                /* FIXME: It looks like this part is not needed any more */
1699                int filename_len = strlen(filename);
1700
1701                if ((IS_ABSOLUTE_PATH(filename, filename_len) ||
1702                     is_stream_path(filename)) &&
1703                    (persistent_script = zend_accel_hash_find(&ZCSG(hash), (char*)filename, filename_len)) != NULL &&
1704                    !persistent_script->corrupted) {
1705
1706                    handle->opened_path = estrndup(persistent_script->full_path, persistent_script->full_path_len);
1707                    handle->type = ZEND_HANDLE_FILENAME;
1708                    memcpy(ZCG(key), persistent_script->full_path, persistent_script->full_path_len + 1);
1709                    ZCG(key_len) = persistent_script->full_path_len;
1710                    ZCG(cache_opline) = EG(current_execute_data) ? EG(current_execute_data)->opline : NULL;
1711                    ZCG(cache_persistent_script) = EG(current_execute_data) ? persistent_script : NULL;
1712                    return SUCCESS;
1713                }
1714#endif
1715            }
1716        }
1717    }
1718    ZCG(cache_opline) = NULL;
1719    ZCG(cache_persistent_script) = NULL;
1720    return accelerator_orig_zend_stream_open_function(filename, handle TSRMLS_CC);
1721}
1722
1723/* zend_resolve_path() replacement for PHP 5.3 and above */
1724static char* persistent_zend_resolve_path(const char *filename, int filename_len TSRMLS_DC)
1725{
1726    if (ZCG(enabled) && accel_startup_ok &&
1727        (ZCG(counted) || ZCSG(accelerator_enabled)) &&
1728        !ZCSG(restart_in_progress)) {
1729
1730        /* check if callback is called from include_once or it's a main request */
1731        if ((!EG(current_execute_data) &&
1732             filename == SG(request_info).path_translated) ||
1733            (EG(current_execute_data) &&
1734             EG(current_execute_data)->func &&
1735             ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
1736             EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL &&
1737             (EG(current_execute_data)->opline->extended_value == ZEND_INCLUDE_ONCE ||
1738              EG(current_execute_data)->opline->extended_value == ZEND_REQUIRE_ONCE))) {
1739            /* we are in include_once or FastCGI request */
1740            zend_file_handle handle;
1741            char *key = NULL;
1742            int key_length;
1743            char *resolved_path;
1744            zend_accel_hash_entry *bucket;
1745            zend_persistent_script *persistent_script;
1746
1747            /* Check if requested file already cached (by full name) */
1748            if ((IS_ABSOLUTE_PATH(filename, filename_len) ||
1749                 is_stream_path(filename)) &&
1750                (bucket = zend_accel_hash_find_entry(&ZCSG(hash), (char*)filename, filename_len)) != NULL) {
1751                persistent_script = (zend_persistent_script *)bucket->data;
1752                if (persistent_script && !persistent_script->corrupted) {
1753                    memcpy(ZCG(key), persistent_script->full_path->val, persistent_script->full_path->len + 1);
1754                    ZCG(key_len) = persistent_script->full_path->len;
1755                    ZCG(cache_opline) = EG(current_execute_data) ? EG(current_execute_data)->opline : NULL;
1756                    ZCG(cache_persistent_script) = persistent_script;
1757                    return estrndup(persistent_script->full_path->val, persistent_script->full_path->len);
1758                }
1759            }
1760
1761            /* Check if requested file already cached (by key) */
1762            handle.filename = (char*)filename;
1763            handle.free_filename = 0;
1764            handle.opened_path = NULL;
1765            key = accel_make_persistent_key_ex(&handle, filename_len, &key_length TSRMLS_CC);
1766            if (!ZCG(accel_directives).revalidate_path &&
1767                key &&
1768                (persistent_script = zend_accel_hash_find(&ZCSG(hash), key, key_length)) != NULL &&
1769                !persistent_script->corrupted) {
1770
1771                /* we have persistent script */
1772                ZCG(cache_opline) = EG(current_execute_data) ? EG(current_execute_data)->opline : NULL;
1773                ZCG(cache_persistent_script) = persistent_script;
1774                return estrndup(persistent_script->full_path->val, persistent_script->full_path->len);
1775            }
1776
1777            /* find the full real path */
1778            resolved_path = accelerator_orig_zend_resolve_path(filename, filename_len TSRMLS_CC);
1779
1780            /* Check if requested file already cached (by real path) */
1781            if (resolved_path &&
1782                (bucket = zend_accel_hash_find_entry(&ZCSG(hash), resolved_path, strlen(resolved_path))) != NULL) {
1783                persistent_script = (zend_persistent_script *)bucket->data;
1784
1785                if (persistent_script && !persistent_script->corrupted) {
1786                    if (key && !ZCG(accel_directives).revalidate_path) {
1787                        /* add another "key" for the same bucket */
1788                        SHM_UNPROTECT();
1789                        zend_shared_alloc_lock(TSRMLS_C);
1790                        zend_accel_add_key(key, key_length, bucket TSRMLS_CC);
1791                        zend_shared_alloc_unlock(TSRMLS_C);
1792                        SHM_PROTECT();
1793                    }
1794                    ZCG(cache_opline) = (EG(current_execute_data) && key) ? EG(current_execute_data)->opline : NULL;
1795                    ZCG(cache_persistent_script) = key ? persistent_script : NULL;
1796                    return resolved_path;
1797                }
1798            }
1799            ZCG(cache_opline) = NULL;
1800            ZCG(cache_persistent_script) = NULL;
1801            return resolved_path;
1802        }
1803    }
1804    ZCG(cache_opline) = NULL;
1805    ZCG(cache_persistent_script) = NULL;
1806    return accelerator_orig_zend_resolve_path(filename, filename_len TSRMLS_CC);
1807}
1808
1809static void zend_reset_cache_vars(TSRMLS_D)
1810{
1811    ZSMMG(memory_exhausted) = 0;
1812    ZCSG(hits) = 0;
1813    ZCSG(misses) = 0;
1814    ZCSG(blacklist_misses) = 0;
1815    ZSMMG(wasted_shared_memory) = 0;
1816    ZCSG(restart_pending) = 0;
1817    ZCSG(force_restart_time) = 0;
1818}
1819
1820static void accel_activate(void)
1821{
1822    TSRMLS_FETCH();
1823
1824    if (!ZCG(enabled) || !accel_startup_ok) {
1825        return;
1826    }
1827
1828    SHM_UNPROTECT();
1829    /* PHP-5.4 and above return "double", but we use 1 sec precision */
1830    ZCG(auto_globals_mask) = 0;
1831    ZCG(request_time) = (time_t)sapi_get_request_time(TSRMLS_C);
1832    ZCG(cache_opline) = NULL;
1833    ZCG(cache_persistent_script) = NULL;
1834    ZCG(include_path_check) = !ZCG(include_path_key);
1835
1836    if (ZCG(counted)) {
1837#ifdef ZTS
1838        zend_accel_error(ACCEL_LOG_WARNING, "Stuck count for thread id %d", tsrm_thread_id());
1839#else
1840        zend_accel_error(ACCEL_LOG_WARNING, "Stuck count for pid %d", getpid());
1841#endif
1842        accel_unlock_all(TSRMLS_C);
1843        ZCG(counted) = 0;
1844    }
1845
1846    if (ZCSG(restart_pending)) {
1847        zend_shared_alloc_lock(TSRMLS_C);
1848        if (ZCSG(restart_pending) != 0) { /* check again, to ensure that the cache wasn't already cleaned by another process */
1849            if (accel_is_inactive(TSRMLS_C) == SUCCESS) {
1850                zend_accel_error(ACCEL_LOG_DEBUG, "Restarting!");
1851                ZCSG(restart_pending) = 0;
1852                switch ZCSG(restart_reason) {
1853                    case ACCEL_RESTART_OOM:
1854                        ZCSG(oom_restarts)++;
1855                        break;
1856                    case ACCEL_RESTART_HASH:
1857                        ZCSG(hash_restarts)++;
1858                        break;
1859                    case ACCEL_RESTART_USER:
1860                        ZCSG(manual_restarts)++;
1861                        break;
1862                }
1863                accel_restart_enter(TSRMLS_C);
1864
1865                zend_reset_cache_vars(TSRMLS_C);
1866                zend_accel_hash_clean(&ZCSG(hash));
1867
1868                /* include_paths keeps only the first path */
1869                if (ZCSG(include_paths).num_entries > 1) {
1870                    ZCSG(include_paths).num_entries = 1;
1871                    ZCSG(include_paths).num_direct_entries = 1;
1872                    memset(ZCSG(include_paths).hash_table, 0, sizeof(zend_accel_hash_entry*) * ZCSG(include_paths).max_num_entries);
1873                    ZCSG(include_paths).hash_table[zend_inline_hash_func(ZCSG(include_paths).hash_entries[0].key, ZCSG(include_paths).hash_entries[0].key_length) % ZCSG(include_paths).max_num_entries] = &ZCSG(include_paths).hash_entries[0];
1874                }
1875
1876#if !defined(ZTS)
1877                if (ZCG(accel_directives).interned_strings_buffer) {
1878                    accel_interned_strings_restore_state(TSRMLS_C);
1879                }
1880#endif
1881
1882                zend_shared_alloc_restore_state();
1883                ZCSG(accelerator_enabled) = ZCSG(cache_status_before_restart);
1884                ZCSG(last_restart_time) = ZCG(request_time);
1885                accel_restart_leave(TSRMLS_C);
1886            }
1887        }
1888        zend_shared_alloc_unlock(TSRMLS_C);
1889    }
1890
1891    /* check if ZCG(function_table) wasn't somehow polluted on the way */
1892    if (ZCG(internal_functions_count) != zend_hash_num_elements(&ZCG(function_table))) {
1893        zend_accel_error(ACCEL_LOG_WARNING, "Internal functions count changed - was %d, now %d", ZCG(internal_functions_count), zend_hash_num_elements(&ZCG(function_table)));
1894    }
1895
1896    if (ZCG(accel_directives).validate_timestamps) {
1897        time_t now = ZCG(request_time);
1898        if (now > ZCSG(revalidate_at) + (time_t)ZCG(accel_directives).revalidate_freq) {
1899            ZCSG(revalidate_at) = now;
1900        }
1901    }
1902
1903    ZCG(cwd) = NULL;
1904
1905    SHM_PROTECT();
1906}
1907
1908#if !ZEND_DEBUG
1909
1910/* Fast Request Shutdown
1911 * =====================
1912 * Zend Memory Manager frees memory by its own. We don't have to free each
1913 * allocated block separately, but we like to call all the destructors and
1914 * callbacks in exactly the same order.
1915 */
1916
1917static void accel_fast_hash_destroy(HashTable *ht)
1918{
1919    uint idx;
1920    Bucket *p;
1921
1922    for (idx = 0; idx < ht->nNumUsed; idx++) {
1923        p = ht->arData + idx;
1924        if (Z_TYPE(p->val) == IS_UNDEF) continue;
1925        ht->pDestructor(&p->val);
1926    }
1927}
1928
1929static void accel_fast_zval_dtor(zval *zvalue)
1930{
1931    if (Z_REFCOUNTED_P(zvalue) && Z_DELREF_P(zvalue) == 0) {
1932        switch (Z_TYPE_P(zvalue)) {
1933            case IS_ARRAY: {
1934                    TSRMLS_FETCH();
1935                    GC_REMOVE_FROM_BUFFER(Z_ARR_P(zvalue));
1936                    if (Z_ARR_P(zvalue) != &EG(symbol_table)) {
1937                        /* break possible cycles */
1938                        ZVAL_NULL(zvalue);
1939                        Z_ARRVAL_P(zvalue)->pDestructor = accel_fast_zval_dtor;
1940                        accel_fast_hash_destroy(Z_ARRVAL_P(zvalue));
1941                    }
1942                }
1943                break;
1944            case IS_OBJECT:
1945                {
1946                    TSRMLS_FETCH();
1947
1948                    OBJ_RELEASE(Z_OBJ_P(zvalue));
1949                }
1950                break;
1951            case IS_RESOURCE:
1952                {
1953                    TSRMLS_FETCH();
1954
1955                    /* destroy resource */
1956                    zend_list_delete(Z_RES_P(zvalue));
1957                }
1958                break;
1959            case IS_LONG:
1960            case IS_DOUBLE:
1961            case IS_FALSE:
1962            case IS_TRUE:
1963            case IS_NULL:
1964            case IS_STRING:
1965            case IS_CONSTANT:
1966            default:
1967                return;
1968                break;
1969        }
1970    }
1971}
1972
1973static int accel_clean_non_persistent_function(zval *zv TSRMLS_DC)
1974{
1975    zend_function *function = Z_PTR_P(zv);
1976
1977    if (function->type == ZEND_INTERNAL_FUNCTION) {
1978        return ZEND_HASH_APPLY_STOP;
1979    } else {
1980        if (function->op_array.static_variables) {
1981            function->op_array.static_variables->pDestructor = accel_fast_zval_dtor;
1982            accel_fast_hash_destroy(function->op_array.static_variables);
1983            function->op_array.static_variables = NULL;
1984        }
1985        return (--(*function->op_array.refcount) <= 0) ?
1986            ZEND_HASH_APPLY_REMOVE :
1987            ZEND_HASH_APPLY_KEEP;
1988    }
1989}
1990
1991static int accel_cleanup_function_data(zval *zv TSRMLS_DC)
1992{
1993    zend_function *function = Z_PTR_P(zv);
1994
1995    if (function->type == ZEND_USER_FUNCTION) {
1996        if (function->op_array.static_variables) {
1997            function->op_array.static_variables->pDestructor = accel_fast_zval_dtor;
1998            accel_fast_hash_destroy(function->op_array.static_variables);
1999            function->op_array.static_variables = NULL;
2000        }
2001    }
2002    return 0;
2003}
2004
2005static int accel_clean_non_persistent_class(zval *zv TSRMLS_DC)
2006{
2007    zend_class_entry *ce = Z_PTR_P(zv);
2008
2009    if (ce->type == ZEND_INTERNAL_CLASS) {
2010        return ZEND_HASH_APPLY_STOP;
2011    } else {
2012        if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
2013            zend_hash_apply(&ce->function_table, (apply_func_t) accel_cleanup_function_data TSRMLS_CC);
2014        }
2015        if (ce->static_members_table) {
2016            int i;
2017
2018            for (i = 0; i < ce->default_static_members_count; i++) {
2019                accel_fast_zval_dtor(&ce->static_members_table[i]);
2020                ZVAL_UNDEF(&ce->static_members_table[i]);
2021            }
2022            ce->static_members_table = NULL;
2023        }
2024        return ZEND_HASH_APPLY_REMOVE;
2025    }
2026}
2027
2028static int accel_clean_non_persistent_constant(zval *zv TSRMLS_DC)
2029{
2030    zend_constant *c = Z_PTR_P(zv);
2031
2032    if (c->flags & CONST_PERSISTENT) {
2033        return ZEND_HASH_APPLY_STOP;
2034    } else {
2035        return ZEND_HASH_APPLY_REMOVE;
2036    }
2037}
2038
2039static void zend_accel_fast_shutdown(TSRMLS_D)
2040{
2041    if (EG(full_tables_cleanup)) {
2042        EG(symbol_table).ht.pDestructor = accel_fast_zval_dtor;
2043    } else {
2044        dtor_func_t old_destructor;
2045
2046        if (EG(objects_store).top > 1 || zend_hash_num_elements(&EG(regular_list)) > 0) {
2047            /* We don't have to destroy all zvals if they cannot call any destructors */
2048
2049            old_destructor = EG(symbol_table).ht.pDestructor;
2050            EG(symbol_table).ht.pDestructor = accel_fast_zval_dtor;
2051            zend_try {
2052                zend_hash_graceful_reverse_destroy(&EG(symbol_table).ht);
2053            } zend_end_try();
2054            EG(symbol_table).ht.pDestructor = old_destructor;
2055        }
2056        zend_hash_init(&EG(symbol_table).ht, 8, NULL, NULL, 0);
2057        old_destructor = EG(function_table)->pDestructor;
2058        EG(function_table)->pDestructor = NULL;
2059        zend_hash_reverse_apply(EG(function_table), (apply_func_t) accel_clean_non_persistent_function TSRMLS_CC);
2060        EG(function_table)->pDestructor = old_destructor;
2061        old_destructor = EG(class_table)->pDestructor;
2062        EG(class_table)->pDestructor = NULL;
2063        zend_hash_reverse_apply(EG(class_table), (apply_func_t) accel_clean_non_persistent_class TSRMLS_CC);
2064        EG(class_table)->pDestructor = old_destructor;
2065        old_destructor = EG(zend_constants)->pDestructor;
2066        EG(zend_constants)->pDestructor = NULL;
2067        zend_hash_reverse_apply(EG(zend_constants), (apply_func_t) accel_clean_non_persistent_constant TSRMLS_CC);
2068        EG(zend_constants)->pDestructor = old_destructor;
2069    }
2070    CG(unclean_shutdown) = 1;
2071}
2072#endif
2073
2074static void accel_deactivate(void)
2075{
2076    /* ensure that we restore function_table and class_table
2077     * In general, they're restored by persistent_compile_file(), but in case
2078     * the script is aborted abnormally, they may become messed up.
2079     */
2080    TSRMLS_FETCH();
2081
2082    if (!ZCG(enabled) || !accel_startup_ok) {
2083        return;
2084    }
2085
2086    zend_shared_alloc_safe_unlock(TSRMLS_C); /* be sure we didn't leave cache locked */
2087    accel_unlock_all(TSRMLS_C);
2088    ZCG(counted) = 0;
2089
2090#if !ZEND_DEBUG
2091    if (ZCG(accel_directives).fast_shutdown) {
2092        zend_accel_fast_shutdown(TSRMLS_C);
2093    }
2094#endif
2095
2096    if (ZCG(cwd)) {
2097        efree(ZCG(cwd));
2098        ZCG(cwd) = NULL;
2099    }
2100
2101}
2102
2103static int accelerator_remove_cb(zend_extension *element1, zend_extension *element2)
2104{
2105    (void)element2; /* keep the compiler happy */
2106
2107    if (!strcmp(element1->name, ACCELERATOR_PRODUCT_NAME )) {
2108        element1->startup = NULL;
2109#if 0
2110        /* We have to call shutdown callback it to free TS resources */
2111        element1->shutdown = NULL;
2112#endif
2113        element1->activate = NULL;
2114        element1->deactivate = NULL;
2115        element1->op_array_handler = NULL;
2116
2117#ifdef __DEBUG_MESSAGES__
2118        fprintf(stderr, ACCELERATOR_PRODUCT_NAME " is disabled: %s\n", (zps_failure_reason ? zps_failure_reason : "unknown error"));
2119        fflush(stderr);
2120#endif
2121    }
2122
2123    return 0;
2124}
2125
2126static void zps_startup_failure(char *reason, char *api_reason, int (*cb)(zend_extension *, zend_extension *) TSRMLS_DC)
2127{
2128    accel_startup_ok = 0;
2129    zps_failure_reason = reason;
2130    zps_api_failure_reason = api_reason?api_reason:reason;
2131    zend_llist_del_element(&zend_extensions, NULL, (int (*)(void *, void *))cb);
2132}
2133
2134static inline int accel_find_sapi(TSRMLS_D)
2135{
2136    static const char *supported_sapis[] = {
2137        "apache",
2138        "fastcgi",
2139        "cli-server",
2140        "cgi-fcgi",
2141        "fpm-fcgi",
2142        "isapi",
2143        "apache2filter",
2144        "apache2handler",
2145        "litespeed",
2146        NULL
2147    };
2148    const char **sapi_name;
2149
2150    if (sapi_module.name) {
2151        for (sapi_name = supported_sapis; *sapi_name; sapi_name++) {
2152            if (strcmp(sapi_module.name, *sapi_name) == 0) {
2153                return SUCCESS;
2154            }
2155        }
2156        if (ZCG(accel_directives).enable_cli &&
2157            strcmp(sapi_module.name, "cli") == 0) {
2158            return SUCCESS;
2159        }
2160    }
2161
2162    return FAILURE;
2163}
2164
2165static int zend_accel_init_shm(TSRMLS_D)
2166{
2167    zend_shared_alloc_lock(TSRMLS_C);
2168
2169    accel_shared_globals = zend_shared_alloc(sizeof(zend_accel_shared_globals));
2170    if (!accel_shared_globals) {
2171        zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
2172        return FAILURE;
2173    }
2174    ZSMMG(app_shared_globals) = accel_shared_globals;
2175
2176    zend_accel_hash_init(&ZCSG(hash), ZCG(accel_directives).max_accelerated_files);
2177    zend_accel_hash_init(&ZCSG(include_paths), 32);
2178
2179    ZCSG(interned_strings_start) = ZCSG(interned_strings_end) = NULL;
2180# ifndef ZTS
2181    zend_hash_init(&ZCSG(interned_strings), (ZCG(accel_directives).interned_strings_buffer * 1024 * 1024) / (sizeof(Bucket) + sizeof(Bucket*) + 8 /* average string length */), NULL, NULL, 1);
2182    if (ZCG(accel_directives).interned_strings_buffer) {
2183        ZCSG(interned_strings).nTableMask = ZCSG(interned_strings).nTableSize - 1;
2184        ZCSG(interned_strings).arData = zend_shared_alloc(ZCSG(interned_strings).nTableSize * sizeof(Bucket));
2185        ZCSG(interned_strings).arHash = (uint32_t*)zend_shared_alloc(ZCSG(interned_strings).nTableSize * sizeof(uint32_t));
2186        ZCSG(interned_strings_start) = zend_shared_alloc((ZCG(accel_directives).interned_strings_buffer * 1024 * 1024));
2187        if (!ZCSG(interned_strings).arData || !ZCSG(interned_strings_start)) {
2188            zend_accel_error(ACCEL_LOG_FATAL, ACCELERATOR_PRODUCT_NAME " cannot allocate buffer for interned strings");
2189            return FAILURE;
2190        }
2191        memset(ZCSG(interned_strings).arHash, INVALID_IDX, ZCSG(interned_strings).nTableSize * sizeof(uint32_t));
2192        ZCSG(interned_strings_end)   = ZCSG(interned_strings_start) + (ZCG(accel_directives).interned_strings_buffer * 1024 * 1024);
2193        ZCSG(interned_strings_top)   = ZCSG(interned_strings_start);
2194
2195//      orig_interned_strings_start = CG(interned_strings_start);
2196//      orig_interned_strings_end = CG(interned_strings_end);
2197//      CG(interned_strings_start) = ZCSG(interned_strings_start);
2198//      CG(interned_strings_end) = ZCSG(interned_strings_end);
2199    }
2200# endif
2201
2202    orig_new_interned_string = zend_new_interned_string;
2203    orig_interned_strings_snapshot = zend_interned_strings_snapshot;
2204    orig_interned_strings_restore = zend_interned_strings_restore;
2205    zend_new_interned_string = accel_new_interned_string_for_php;
2206    zend_interned_strings_snapshot = accel_interned_strings_snapshot_for_php;
2207    zend_interned_strings_restore = accel_interned_strings_restore_for_php;
2208
2209# ifndef ZTS
2210    if (ZCG(accel_directives).interned_strings_buffer) {
2211        accel_use_shm_interned_strings(TSRMLS_C);
2212        accel_interned_strings_save_state(TSRMLS_C);
2213    }
2214# endif
2215
2216    zend_reset_cache_vars(TSRMLS_C);
2217
2218    ZCSG(oom_restarts) = 0;
2219    ZCSG(hash_restarts) = 0;
2220    ZCSG(manual_restarts) = 0;
2221
2222    ZCSG(accelerator_enabled) = 1;
2223    ZCSG(start_time) = zend_accel_get_time();
2224    ZCSG(last_restart_time) = 0;
2225    ZCSG(restart_in_progress) = 0;
2226
2227    zend_shared_alloc_unlock(TSRMLS_C);
2228
2229    return SUCCESS;
2230}
2231
2232static void accel_globals_ctor(zend_accel_globals *accel_globals TSRMLS_DC)
2233{
2234    memset(accel_globals, 0, sizeof(zend_accel_globals));
2235    zend_hash_init(&accel_globals->function_table, zend_hash_num_elements(CG(function_table)), NULL, ZEND_FUNCTION_DTOR, 1);
2236    zend_accel_copy_internal_functions(TSRMLS_C);
2237}
2238
2239static void accel_globals_internal_func_dtor(zval *zv)
2240{
2241    free(Z_PTR_P(zv));
2242}
2243
2244static void accel_globals_dtor(zend_accel_globals *accel_globals TSRMLS_DC)
2245{
2246    accel_globals->function_table.pDestructor = accel_globals_internal_func_dtor;
2247    zend_hash_destroy(&accel_globals->function_table);
2248}
2249
2250static int accel_startup(zend_extension *extension)
2251{
2252    zend_function *func;
2253    zend_ini_entry *ini_entry;
2254    TSRMLS_FETCH();
2255
2256#ifdef ZTS
2257    accel_globals_id = ts_allocate_id(&accel_globals_id, sizeof(zend_accel_globals), (ts_allocate_ctor) accel_globals_ctor, (ts_allocate_dtor) accel_globals_dtor);
2258#else
2259    accel_globals_ctor(&accel_globals);
2260#endif
2261
2262#ifdef ZEND_WIN32
2263    _setmaxstdio(2048); /* The default configuration is limited to 512 stdio files */
2264#endif
2265
2266    if (start_accel_module(TSRMLS_C) == FAILURE) {
2267        accel_startup_ok = 0;
2268        zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": module registration failed!");
2269        return FAILURE;
2270    }
2271
2272    /* no supported SAPI found - disable acceleration and stop initialization */
2273    if (accel_find_sapi(TSRMLS_C) == FAILURE) {
2274        accel_startup_ok = 0;
2275        if (!ZCG(accel_directives).enable_cli &&
2276            strcmp(sapi_module.name, "cli") == 0) {
2277            zps_startup_failure("Opcode Caching is disabled for CLI", NULL, accelerator_remove_cb TSRMLS_CC);
2278        } else {
2279            zps_startup_failure("Opcode Caching is only supported in Apache, ISAPI, FPM, FastCGI and LiteSpeed SAPIs", NULL, accelerator_remove_cb TSRMLS_CC);
2280        }
2281        return SUCCESS;
2282    }
2283
2284    if (ZCG(enabled) == 0) {
2285        return SUCCESS ;
2286    }
2287/********************************************/
2288/* End of non-SHM dependent initializations */
2289/********************************************/
2290    switch (zend_shared_alloc_startup(ZCG(accel_directives).memory_consumption)) {
2291        case ALLOC_SUCCESS:
2292            if (zend_accel_init_shm(TSRMLS_C) == FAILURE) {
2293                accel_startup_ok = 0;
2294                return FAILURE;
2295            }
2296            break;
2297        case ALLOC_FAILURE:
2298            accel_startup_ok = 0;
2299            zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - probably not enough shared memory.");
2300            return SUCCESS;
2301        case SUCCESSFULLY_REATTACHED:
2302            accel_shared_globals = (zend_accel_shared_globals *) ZSMMG(app_shared_globals);
2303            zend_shared_alloc_lock(TSRMLS_C);
2304            orig_new_interned_string = zend_new_interned_string;
2305            orig_interned_strings_snapshot = zend_interned_strings_snapshot;
2306            orig_interned_strings_restore = zend_interned_strings_restore;
2307
2308            zend_new_interned_string = accel_new_interned_string_for_php;
2309            zend_interned_strings_snapshot = accel_interned_strings_snapshot_for_php;
2310            zend_interned_strings_restore = accel_interned_strings_restore_for_php;
2311#ifndef ZTS
2312            accel_use_shm_interned_strings(TSRMLS_C);
2313#endif
2314            zend_shared_alloc_unlock(TSRMLS_C);
2315            break;
2316        case FAILED_REATTACHED:
2317            accel_startup_ok = 0;
2318            zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - can not reattach to exiting shared memory.");
2319            return SUCCESS;
2320            break;
2321    }
2322
2323    /* from this point further, shared memory is supposed to be OK */
2324
2325    /* Init auto-global strings */
2326    zend_accel_init_auto_globals(TSRMLS_C);
2327
2328    /* Override compiler */
2329    accelerator_orig_compile_file = zend_compile_file;
2330    zend_compile_file = persistent_compile_file;
2331
2332    /* Override stream opener function (to eliminate open() call caused by
2333     * include/require statements ) */
2334    accelerator_orig_zend_stream_open_function = zend_stream_open_function;
2335    zend_stream_open_function = persistent_stream_open_function;
2336
2337    /* Override path resolver function (to eliminate stat() calls caused by
2338     * include_once/require_once statements */
2339    accelerator_orig_zend_resolve_path = zend_resolve_path;
2340    zend_resolve_path = persistent_zend_resolve_path;
2341
2342    if (ZCG(accel_directives).validate_timestamps) {
2343        ZCSG(revalidate_at) = zend_accel_get_time() + ZCG(accel_directives).revalidate_freq;
2344    }
2345
2346    /* Override chdir() function */
2347    if ((func = zend_hash_str_find_ptr(CG(function_table), "chdir", sizeof("chdir")-1)) != NULL &&
2348        func->type == ZEND_INTERNAL_FUNCTION) {
2349        orig_chdir = func->internal_function.handler;
2350        func->internal_function.handler = ZEND_FN(accel_chdir);
2351    }
2352    ZCG(cwd) = NULL;
2353
2354    /* Override "include_path" modifier callback */
2355    if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), "include_path", sizeof("include_path")-1)) != NULL) {
2356        ZCG(include_path) = INI_STR("include_path");
2357        ZCG(include_path_key) = NULL;
2358        if (ZCG(include_path) && *ZCG(include_path)) {
2359            ZCG(include_path_len) = strlen(ZCG(include_path));
2360            ZCG(include_path_key) = zend_accel_hash_find(&ZCSG(include_paths), ZCG(include_path), ZCG(include_path_len));
2361            if (!ZCG(include_path_key) &&
2362                !zend_accel_hash_is_full(&ZCSG(include_paths))) {
2363                char *key;
2364
2365                zend_shared_alloc_lock(TSRMLS_C);
2366                key = zend_shared_alloc(ZCG(include_path_len) + 2);
2367                if (key) {
2368                    memcpy(key, ZCG(include_path), ZCG(include_path_len) + 1);
2369                    key[ZCG(include_path_len) + 1] = 'A' + ZCSG(include_paths).num_entries;
2370                    ZCG(include_path_key) = key + ZCG(include_path_len) + 1;
2371                    zend_accel_hash_update(&ZCSG(include_paths), key, ZCG(include_path_len), 0, ZCG(include_path_key));
2372                } else {
2373                    zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM TSRMLS_CC);
2374                }
2375                zend_shared_alloc_unlock(TSRMLS_C);
2376            }
2377        } else {
2378            ZCG(include_path) = "";
2379            ZCG(include_path_len) = 0;
2380        }
2381        orig_include_path_on_modify = ini_entry->on_modify;
2382        ini_entry->on_modify = accel_include_path_on_modify;
2383    }
2384
2385    zend_shared_alloc_lock(TSRMLS_C);
2386    zend_shared_alloc_save_state();
2387    zend_shared_alloc_unlock(TSRMLS_C);
2388
2389    SHM_PROTECT();
2390
2391    accel_startup_ok = 1;
2392
2393    /* Override file_exists(), is_file() and is_readable() */
2394    zend_accel_override_file_functions(TSRMLS_C);
2395
2396    /* Load black list */
2397    accel_blacklist.entries = NULL;
2398    if (ZCG(enabled) && accel_startup_ok &&
2399        ZCG(accel_directives).user_blacklist_filename &&
2400        *ZCG(accel_directives.user_blacklist_filename)) {
2401        zend_accel_blacklist_init(&accel_blacklist);
2402        zend_accel_blacklist_load(&accel_blacklist, ZCG(accel_directives.user_blacklist_filename));
2403    }
2404
2405#if 0
2406    /* FIXME: We probably don't need it here */
2407    zend_accel_copy_internal_functions(TSRMLS_C);
2408#endif
2409
2410    return SUCCESS;
2411}
2412
2413static void accel_free_ts_resources()
2414{
2415#ifndef ZTS
2416    accel_globals_dtor(&accel_globals);
2417#else
2418    ts_free_id(accel_globals_id);
2419#endif
2420}
2421
2422void accel_shutdown(TSRMLS_D)
2423{
2424    zend_ini_entry *ini_entry;
2425
2426    zend_accel_blacklist_shutdown(&accel_blacklist);
2427
2428    if (!ZCG(enabled) || !accel_startup_ok) {
2429        accel_free_ts_resources();
2430        return;
2431    }
2432
2433    if (ZCG(accel_directives).interned_strings_buffer) {
2434#ifndef ZTS
2435        zend_hash_clean(CG(auto_globals));
2436        zend_hash_clean(CG(function_table));
2437        zend_hash_clean(CG(class_table));
2438        zend_hash_clean(EG(zend_constants));
2439#endif
2440    }
2441
2442    zend_new_interned_string = orig_new_interned_string;
2443    zend_interned_strings_snapshot = orig_interned_strings_snapshot;
2444    zend_interned_strings_restore = orig_interned_strings_restore;
2445
2446    accel_free_ts_resources();
2447    zend_shared_alloc_shutdown();
2448    zend_compile_file = accelerator_orig_compile_file;
2449
2450    if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), "include_path", sizeof("include_path")-1)) != NULL) {
2451        ini_entry->on_modify = orig_include_path_on_modify;
2452    }
2453}
2454
2455void zend_accel_schedule_restart(zend_accel_restart_reason reason TSRMLS_DC)
2456{
2457    if (ZCSG(restart_pending)) {
2458        /* don't schedule twice */
2459        return;
2460    }
2461    zend_accel_error(ACCEL_LOG_DEBUG, "Restart Scheduled!");
2462
2463    SHM_UNPROTECT();
2464    ZCSG(restart_pending) = 1;
2465    ZCSG(restart_reason) = reason;
2466    ZCSG(cache_status_before_restart) = ZCSG(accelerator_enabled);
2467    ZCSG(accelerator_enabled) = 0;
2468
2469    if (ZCG(accel_directives).force_restart_timeout) {
2470        ZCSG(force_restart_time) = zend_accel_get_time() + ZCG(accel_directives).force_restart_timeout;
2471    } else {
2472        ZCSG(force_restart_time) = 0;
2473    }
2474    SHM_PROTECT();
2475}
2476
2477/* this is needed because on WIN32 lock is not decreased unless ZCG(counted) is set */
2478#ifdef ZEND_WIN32
2479#define accel_deactivate_now() ZCG(counted) = 1; accel_deactivate_sub(TSRMLS_C)
2480#else
2481#define accel_deactivate_now() accel_deactivate_sub(TSRMLS_C)
2482#endif
2483
2484/* ensures it is OK to read SHM
2485    if it's not OK (restart in progress) returns FAILURE
2486    if OK returns SUCCESS
2487    MUST call accelerator_shm_read_unlock after done lock operations
2488*/
2489int accelerator_shm_read_lock(TSRMLS_D)
2490{
2491    if (ZCG(counted)) {
2492        /* counted means we are holding read lock for SHM, so that nothing bad can happen */
2493        return SUCCESS;
2494    } else {
2495        /* here accelerator is active but we do not hold SHM lock. This means restart was scheduled
2496            or is in progress now */
2497        accel_activate_add(TSRMLS_C); /* acquire usage lock */
2498        /* Now if we weren't inside restart, restart would not begin until we remove usage lock */
2499        if (ZCSG(restart_in_progress)) {
2500            /* we already were inside restart this means it's not safe to touch shm */
2501            accel_deactivate_now(); /* drop usage lock */
2502            return FAILURE;
2503        }
2504    }
2505    return SUCCESS;
2506}
2507
2508/* must be called ONLY after SUCCESSFUL accelerator_shm_read_lock */
2509void accelerator_shm_read_unlock(TSRMLS_D)
2510{
2511    if (!ZCG(counted)) {
2512        /* counted is 0 - meaning we had to readlock manually, release readlock now */
2513        accel_deactivate_now();
2514    }
2515}
2516
2517ZEND_EXT_API zend_extension zend_extension_entry = {
2518    ACCELERATOR_PRODUCT_NAME,               /* name */
2519    ACCELERATOR_VERSION,                    /* version */
2520    "Zend Technologies",                    /* author */
2521    "http://www.zend.com/",                 /* URL */
2522    "Copyright (c) 1999-2014",              /* copyright */
2523    accel_startup,                          /* startup */
2524    NULL,                                   /* shutdown */
2525    accel_activate,                         /* per-script activation */
2526    accel_deactivate,                       /* per-script deactivation */
2527    NULL,                                   /* message handler */
2528    NULL,                                   /* op_array handler */
2529    NULL,                                   /* extended statement handler */
2530    NULL,                                   /* extended fcall begin handler */
2531    NULL,                                   /* extended fcall end handler */
2532    NULL,                                   /* op_array ctor */
2533    NULL,                                   /* op_array dtor */
2534    STANDARD_ZEND_EXTENSION_PROPERTIES
2535};
2536