1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 2.00 of the Zend 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.zend.com/license/2_00.txt. |
11 | If you did not receive a copy of the Zend license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@zend.com so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Wez Furlong <wez@thebrainroom.com> |
16 | Scott MacVicar <scottmac@php.net> |
17 | Nuno Lopes <nlopess@php.net> |
18 | Marcus Boerger <helly@php.net> |
19 +----------------------------------------------------------------------+
20 */
21
22 #include "zend.h"
23 #include "zend_compile.h"
24 #include "zend_stream.h"
25
26 ZEND_DLIMPORT int isatty(int fd);
27
zend_stream_stdio_reader(void * handle,char * buf,size_t len)28 static ssize_t zend_stream_stdio_reader(void *handle, char *buf, size_t len) /* {{{ */
29 {
30 return fread(buf, 1, len, (FILE*)handle);
31 } /* }}} */
32
zend_stream_stdio_closer(void * handle)33 static void zend_stream_stdio_closer(void *handle) /* {{{ */
34 {
35 if (handle && (FILE*)handle != stdin) {
36 fclose((FILE*)handle);
37 }
38 } /* }}} */
39
zend_stream_stdio_fsizer(void * handle)40 static size_t zend_stream_stdio_fsizer(void *handle) /* {{{ */
41 {
42 zend_stat_t buf;
43 if (handle && zend_fstat(fileno((FILE*)handle), &buf) == 0) {
44 #ifdef S_ISREG
45 if (!S_ISREG(buf.st_mode)) {
46 return 0;
47 }
48 #endif
49 return buf.st_size;
50 }
51 return -1;
52 } /* }}} */
53
zend_stream_fsize(zend_file_handle * file_handle)54 static size_t zend_stream_fsize(zend_file_handle *file_handle) /* {{{ */
55 {
56 ZEND_ASSERT(file_handle->type == ZEND_HANDLE_STREAM);
57 if (file_handle->handle.stream.isatty) {
58 return 0;
59 }
60 return file_handle->handle.stream.fsizer(file_handle->handle.stream.handle);
61 } /* }}} */
62
zend_stream_init_fp(zend_file_handle * handle,FILE * fp,const char * filename)63 ZEND_API void zend_stream_init_fp(zend_file_handle *handle, FILE *fp, const char *filename) {
64 memset(handle, 0, sizeof(zend_file_handle));
65 handle->type = ZEND_HANDLE_FP;
66 handle->handle.fp = fp;
67 handle->filename = filename;
68 }
69
zend_stream_init_filename(zend_file_handle * handle,const char * filename)70 ZEND_API void zend_stream_init_filename(zend_file_handle *handle, const char *filename) {
71 memset(handle, 0, sizeof(zend_file_handle));
72 handle->type = ZEND_HANDLE_FILENAME;
73 handle->filename = filename;
74 }
75
zend_stream_open(const char * filename,zend_file_handle * handle)76 ZEND_API zend_result zend_stream_open(const char *filename, zend_file_handle *handle) /* {{{ */
77 {
78 zend_string *opened_path;
79 if (zend_stream_open_function) {
80 return zend_stream_open_function(filename, handle);
81 }
82
83 zend_stream_init_fp(handle, zend_fopen(filename, &opened_path), filename);
84 handle->opened_path = opened_path;
85 return handle->handle.fp ? SUCCESS : FAILURE;
86 } /* }}} */
87
zend_stream_getc(zend_file_handle * file_handle)88 static int zend_stream_getc(zend_file_handle *file_handle) /* {{{ */
89 {
90 char buf;
91
92 if (file_handle->handle.stream.reader(file_handle->handle.stream.handle, &buf, sizeof(buf))) {
93 return (int)buf;
94 }
95 return EOF;
96 } /* }}} */
97
zend_stream_read(zend_file_handle * file_handle,char * buf,size_t len)98 static ssize_t zend_stream_read(zend_file_handle *file_handle, char *buf, size_t len) /* {{{ */
99 {
100 if (file_handle->handle.stream.isatty) {
101 int c = '*';
102 size_t n;
103
104 for (n = 0; n < len && (c = zend_stream_getc(file_handle)) != EOF && c != '\n'; ++n) {
105 buf[n] = (char)c;
106 }
107 if (c == '\n') {
108 buf[n++] = (char)c;
109 }
110
111 return n;
112 }
113 return file_handle->handle.stream.reader(file_handle->handle.stream.handle, buf, len);
114 } /* }}} */
115
zend_stream_fixup(zend_file_handle * file_handle,char ** buf,size_t * len)116 ZEND_API zend_result zend_stream_fixup(zend_file_handle *file_handle, char **buf, size_t *len) /* {{{ */
117 {
118 size_t file_size;
119
120 if (file_handle->buf) {
121 *buf = file_handle->buf;
122 *len = file_handle->len;
123 return SUCCESS;
124 }
125
126 if (file_handle->type == ZEND_HANDLE_FILENAME) {
127 if (zend_stream_open(file_handle->filename, file_handle) == FAILURE) {
128 return FAILURE;
129 }
130 }
131
132 if (file_handle->type == ZEND_HANDLE_FP) {
133 if (!file_handle->handle.fp) {
134 return FAILURE;
135 }
136
137 file_handle->type = ZEND_HANDLE_STREAM;
138 file_handle->handle.stream.handle = file_handle->handle.fp;
139 file_handle->handle.stream.isatty = isatty(fileno((FILE *)file_handle->handle.stream.handle));
140 file_handle->handle.stream.reader = (zend_stream_reader_t)zend_stream_stdio_reader;
141 file_handle->handle.stream.closer = (zend_stream_closer_t)zend_stream_stdio_closer;
142 file_handle->handle.stream.fsizer = (zend_stream_fsizer_t)zend_stream_stdio_fsizer;
143 }
144
145 file_size = zend_stream_fsize(file_handle);
146 if (file_size == (size_t)-1) {
147 return FAILURE;
148 }
149
150 if (file_size) {
151 ssize_t read;
152 size_t size = 0;
153 *buf = safe_emalloc(1, file_size, ZEND_MMAP_AHEAD);
154 while ((read = zend_stream_read(file_handle, *buf + size, file_size - size)) > 0) {
155 size += read;
156 }
157 if (read < 0) {
158 efree(*buf);
159 return FAILURE;
160 }
161 file_handle->buf = *buf;
162 file_handle->len = size;
163 } else {
164 size_t size = 0, remain = 4*1024;
165 ssize_t read;
166 *buf = emalloc(remain);
167
168 while ((read = zend_stream_read(file_handle, *buf + size, remain)) > 0) {
169 size += read;
170 remain -= read;
171
172 if (remain == 0) {
173 *buf = safe_erealloc(*buf, size, 2, 0);
174 remain = size;
175 }
176 }
177 if (read < 0) {
178 efree(*buf);
179 return FAILURE;
180 }
181
182 file_handle->len = size;
183 if (size && remain < ZEND_MMAP_AHEAD) {
184 *buf = safe_erealloc(*buf, size, 1, ZEND_MMAP_AHEAD);
185 }
186 file_handle->buf = *buf;
187 }
188
189 if (file_handle->len == 0) {
190 *buf = erealloc(*buf, ZEND_MMAP_AHEAD);
191 file_handle->buf = *buf;
192 }
193
194 memset(file_handle->buf + file_handle->len, 0, ZEND_MMAP_AHEAD);
195
196 *buf = file_handle->buf;
197 *len = file_handle->len;
198
199 return SUCCESS;
200 } /* }}} */
201
zend_file_handle_dtor(zend_file_handle * fh)202 ZEND_API void zend_file_handle_dtor(zend_file_handle *fh) /* {{{ */
203 {
204 switch (fh->type) {
205 case ZEND_HANDLE_FP:
206 fclose(fh->handle.fp);
207 break;
208 case ZEND_HANDLE_STREAM:
209 if (fh->handle.stream.closer && fh->handle.stream.handle) {
210 fh->handle.stream.closer(fh->handle.stream.handle);
211 }
212 fh->handle.stream.handle = NULL;
213 break;
214 case ZEND_HANDLE_FILENAME:
215 /* We're only supposed to get here when destructing the used_files hash,
216 * which doesn't really contain open files, but references to their names/paths
217 */
218 break;
219 }
220 if (fh->opened_path) {
221 zend_string_release_ex(fh->opened_path, 0);
222 fh->opened_path = NULL;
223 }
224 if (fh->buf) {
225 efree(fh->buf);
226 fh->buf = NULL;
227 }
228 if (fh->free_filename && fh->filename) {
229 efree((char*)fh->filename);
230 fh->filename = NULL;
231 }
232 }
233 /* }}} */
234
235 /* return int to be compatible with Zend linked list API */
zend_compare_file_handles(zend_file_handle * fh1,zend_file_handle * fh2)236 ZEND_API int zend_compare_file_handles(zend_file_handle *fh1, zend_file_handle *fh2) /* {{{ */
237 {
238 if (fh1->type != fh2->type) {
239 return 0;
240 }
241 switch (fh1->type) {
242 case ZEND_HANDLE_FILENAME:
243 return strcmp(fh1->filename, fh2->filename) == 0;
244 case ZEND_HANDLE_FP:
245 return fh1->handle.fp == fh2->handle.fp;
246 case ZEND_HANDLE_STREAM:
247 return fh1->handle.stream.handle == fh2->handle.stream.handle;
248 default:
249 return 0;
250 }
251 return 0;
252 } /* }}} */
253