This source file includes following definitions.
- php_get_stream_filters_hash_global
- _php_get_stream_filters_hash
- php_stream_filter_register_factory
- php_stream_filter_unregister_factory
- php_stream_filter_register_factory_volatile
- php_stream_bucket_new
- php_stream_bucket_make_writeable
- php_stream_bucket_split
- php_stream_bucket_delref
- php_stream_bucket_prepend
- php_stream_bucket_append
- php_stream_bucket_unlink
- php_stream_filter_create
- _php_stream_filter_alloc
- php_stream_filter_free
- php_stream_filter_prepend_ex
- _php_stream_filter_prepend
- php_stream_filter_append_ex
- _php_stream_filter_append
- _php_stream_filter_flush
- php_stream_filter_remove
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 #include "php.h"
22 #include "php_globals.h"
23 #include "php_network.h"
24 #include "php_open_temporary_file.h"
25 #include "ext/standard/file.h"
26 #include <stddef.h>
27 #include <fcntl.h>
28
29 #include "php_streams_int.h"
30
31
32 static HashTable stream_filters_hash;
33
34
35 PHPAPI HashTable *php_get_stream_filters_hash_global(void)
36 {
37 return &stream_filters_hash;
38 }
39
40
41 PHPAPI HashTable *_php_get_stream_filters_hash(void)
42 {
43 return (FG(stream_filters) ? FG(stream_filters) : &stream_filters_hash);
44 }
45
46
47 PHPAPI int php_stream_filter_register_factory(const char *filterpattern, php_stream_filter_factory *factory)
48 {
49 return zend_hash_str_add_ptr(&stream_filters_hash, filterpattern, strlen(filterpattern), factory) ? SUCCESS : FAILURE;
50 }
51
52 PHPAPI int php_stream_filter_unregister_factory(const char *filterpattern)
53 {
54 return zend_hash_str_del(&stream_filters_hash, filterpattern, strlen(filterpattern));
55 }
56
57
58 PHPAPI int php_stream_filter_register_factory_volatile(const char *filterpattern, php_stream_filter_factory *factory)
59 {
60 if (!FG(stream_filters)) {
61 ALLOC_HASHTABLE(FG(stream_filters));
62 zend_hash_init(FG(stream_filters), zend_hash_num_elements(&stream_filters_hash), NULL, NULL, 1);
63 zend_hash_copy(FG(stream_filters), &stream_filters_hash, NULL);
64 }
65
66 return zend_hash_str_add_ptr(FG(stream_filters), (char*)filterpattern, strlen(filterpattern), factory) ? SUCCESS : FAILURE;
67 }
68
69
70
71 PHPAPI php_stream_bucket *php_stream_bucket_new(php_stream *stream, char *buf, size_t buflen, int own_buf, int buf_persistent)
72 {
73 int is_persistent = php_stream_is_persistent(stream);
74 php_stream_bucket *bucket;
75
76 bucket = (php_stream_bucket*)pemalloc(sizeof(php_stream_bucket), is_persistent);
77
78 if (bucket == NULL) {
79 return NULL;
80 }
81
82 bucket->next = bucket->prev = NULL;
83
84 if (is_persistent && !buf_persistent) {
85
86 bucket->buf = pemalloc(buflen, 1);
87
88 if (bucket->buf == NULL) {
89 pefree(bucket, 1);
90 return NULL;
91 }
92
93 memcpy(bucket->buf, buf, buflen);
94 bucket->buflen = buflen;
95 bucket->own_buf = 1;
96 } else {
97 bucket->buf = buf;
98 bucket->buflen = buflen;
99 bucket->own_buf = own_buf;
100 }
101 bucket->is_persistent = is_persistent;
102 bucket->refcount = 1;
103 bucket->brigade = NULL;
104
105 return bucket;
106 }
107
108
109
110
111
112
113
114
115 PHPAPI php_stream_bucket *php_stream_bucket_make_writeable(php_stream_bucket *bucket)
116 {
117 php_stream_bucket *retval;
118
119 php_stream_bucket_unlink(bucket);
120
121 if (bucket->refcount == 1 && bucket->own_buf) {
122 return bucket;
123 }
124
125 retval = (php_stream_bucket*)pemalloc(sizeof(php_stream_bucket), bucket->is_persistent);
126 memcpy(retval, bucket, sizeof(*retval));
127
128 retval->buf = pemalloc(retval->buflen, retval->is_persistent);
129 memcpy(retval->buf, bucket->buf, retval->buflen);
130
131 retval->refcount = 1;
132 retval->own_buf = 1;
133
134 php_stream_bucket_delref(bucket);
135
136 return retval;
137 }
138
139 PHPAPI int php_stream_bucket_split(php_stream_bucket *in, php_stream_bucket **left, php_stream_bucket **right, size_t length)
140 {
141 *left = (php_stream_bucket*)pecalloc(1, sizeof(php_stream_bucket), in->is_persistent);
142 *right = (php_stream_bucket*)pecalloc(1, sizeof(php_stream_bucket), in->is_persistent);
143
144 if (*left == NULL || *right == NULL) {
145 goto exit_fail;
146 }
147
148 (*left)->buf = pemalloc(length, in->is_persistent);
149 (*left)->buflen = length;
150 memcpy((*left)->buf, in->buf, length);
151 (*left)->refcount = 1;
152 (*left)->own_buf = 1;
153 (*left)->is_persistent = in->is_persistent;
154
155 (*right)->buflen = in->buflen - length;
156 (*right)->buf = pemalloc((*right)->buflen, in->is_persistent);
157 memcpy((*right)->buf, in->buf + length, (*right)->buflen);
158 (*right)->refcount = 1;
159 (*right)->own_buf = 1;
160 (*right)->is_persistent = in->is_persistent;
161
162 return SUCCESS;
163
164 exit_fail:
165 if (*right) {
166 if ((*right)->buf) {
167 pefree((*right)->buf, in->is_persistent);
168 }
169 pefree(*right, in->is_persistent);
170 }
171 if (*left) {
172 if ((*left)->buf) {
173 pefree((*left)->buf, in->is_persistent);
174 }
175 pefree(*left, in->is_persistent);
176 }
177 return FAILURE;
178 }
179
180 PHPAPI void php_stream_bucket_delref(php_stream_bucket *bucket)
181 {
182 if (--bucket->refcount == 0) {
183 if (bucket->own_buf) {
184 pefree(bucket->buf, bucket->is_persistent);
185 }
186 pefree(bucket, bucket->is_persistent);
187 }
188 }
189
190 PHPAPI void php_stream_bucket_prepend(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket)
191 {
192 bucket->next = brigade->head;
193 bucket->prev = NULL;
194
195 if (brigade->head) {
196 brigade->head->prev = bucket;
197 } else {
198 brigade->tail = bucket;
199 }
200 brigade->head = bucket;
201 bucket->brigade = brigade;
202 }
203
204 PHPAPI void php_stream_bucket_append(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket)
205 {
206 if (brigade->tail == bucket) {
207 return;
208 }
209
210 bucket->prev = brigade->tail;
211 bucket->next = NULL;
212
213 if (brigade->tail) {
214 brigade->tail->next = bucket;
215 } else {
216 brigade->head = bucket;
217 }
218 brigade->tail = bucket;
219 bucket->brigade = brigade;
220 }
221
222 PHPAPI void php_stream_bucket_unlink(php_stream_bucket *bucket)
223 {
224 if (bucket->prev) {
225 bucket->prev->next = bucket->next;
226 } else if (bucket->brigade) {
227 bucket->brigade->head = bucket->next;
228 }
229 if (bucket->next) {
230 bucket->next->prev = bucket->prev;
231 } else if (bucket->brigade) {
232 bucket->brigade->tail = bucket->prev;
233 }
234 bucket->brigade = NULL;
235 bucket->next = bucket->prev = NULL;
236 }
237
238
239
240
241
242
243
244
245
246
247
248
249
250 PHPAPI php_stream_filter *php_stream_filter_create(const char *filtername, zval *filterparams, int persistent)
251 {
252 HashTable *filter_hash = (FG(stream_filters) ? FG(stream_filters) : &stream_filters_hash);
253 php_stream_filter_factory *factory = NULL;
254 php_stream_filter *filter = NULL;
255 int n;
256 char *period;
257
258 n = (int)strlen(filtername);
259
260 if (NULL != (factory = zend_hash_str_find_ptr(filter_hash, filtername, n))) {
261 filter = factory->create_filter(filtername, filterparams, persistent);
262 } else if ((period = strrchr(filtername, '.'))) {
263
264 char *wildname;
265
266 wildname = emalloc(n+3);
267 memcpy(wildname, filtername, n+1);
268 period = wildname + (period - filtername);
269 while (period && !filter) {
270 *period = '\0';
271 strncat(wildname, ".*", 2);
272 if (NULL != (factory = zend_hash_str_find_ptr(filter_hash, wildname, strlen(wildname)))) {
273 filter = factory->create_filter(filtername, filterparams, persistent);
274 }
275
276 *period = '\0';
277 period = strrchr(wildname, '.');
278 }
279 efree(wildname);
280 }
281
282 if (filter == NULL) {
283
284 if (factory == NULL)
285 php_error_docref(NULL, E_WARNING, "unable to locate filter \"%s\"", filtername);
286 else
287 php_error_docref(NULL, E_WARNING, "unable to create or locate filter \"%s\"", filtername);
288 }
289
290 return filter;
291 }
292
293 PHPAPI php_stream_filter *_php_stream_filter_alloc(php_stream_filter_ops *fops, void *abstract, int persistent STREAMS_DC)
294 {
295 php_stream_filter *filter;
296
297 filter = (php_stream_filter*) pemalloc_rel_orig(sizeof(php_stream_filter), persistent);
298 memset(filter, 0, sizeof(php_stream_filter));
299
300 filter->fops = fops;
301 Z_PTR(filter->abstract) = abstract;
302 filter->is_persistent = persistent;
303
304 return filter;
305 }
306
307 PHPAPI void php_stream_filter_free(php_stream_filter *filter)
308 {
309 if (filter->fops->dtor)
310 filter->fops->dtor(filter);
311 pefree(filter, filter->is_persistent);
312 }
313
314 PHPAPI int php_stream_filter_prepend_ex(php_stream_filter_chain *chain, php_stream_filter *filter)
315 {
316 filter->next = chain->head;
317 filter->prev = NULL;
318
319 if (chain->head) {
320 chain->head->prev = filter;
321 } else {
322 chain->tail = filter;
323 }
324 chain->head = filter;
325 filter->chain = chain;
326
327 return SUCCESS;
328 }
329
330 PHPAPI void _php_stream_filter_prepend(php_stream_filter_chain *chain, php_stream_filter *filter)
331 {
332 php_stream_filter_prepend_ex(chain, filter);
333 }
334
335 PHPAPI int php_stream_filter_append_ex(php_stream_filter_chain *chain, php_stream_filter *filter)
336 {
337 php_stream *stream = chain->stream;
338
339 filter->prev = chain->tail;
340 filter->next = NULL;
341 if (chain->tail) {
342 chain->tail->next = filter;
343 } else {
344 chain->head = filter;
345 }
346 chain->tail = filter;
347 filter->chain = chain;
348
349 if (&(stream->readfilters) == chain && (stream->writepos - stream->readpos) > 0) {
350
351 php_stream_bucket_brigade brig_in = { NULL, NULL }, brig_out = { NULL, NULL };
352 php_stream_bucket_brigade *brig_inp = &brig_in, *brig_outp = &brig_out;
353 php_stream_filter_status_t status;
354 php_stream_bucket *bucket;
355 size_t consumed = 0;
356
357 bucket = php_stream_bucket_new(stream, (char*) stream->readbuf + stream->readpos, stream->writepos - stream->readpos, 0, 0);
358 php_stream_bucket_append(brig_inp, bucket);
359 status = filter->fops->filter(stream, filter, brig_inp, brig_outp, &consumed, PSFS_FLAG_NORMAL);
360
361 if (stream->readpos + consumed > (uint)stream->writepos) {
362
363 status = PSFS_ERR_FATAL;
364 }
365
366 switch (status) {
367 case PSFS_ERR_FATAL:
368 while (brig_in.head) {
369 bucket = brig_in.head;
370 php_stream_bucket_unlink(bucket);
371 php_stream_bucket_delref(bucket);
372 }
373 while (brig_out.head) {
374 bucket = brig_out.head;
375 php_stream_bucket_unlink(bucket);
376 php_stream_bucket_delref(bucket);
377 }
378 php_error_docref(NULL, E_WARNING, "Filter failed to process pre-buffered data");
379 return FAILURE;
380 case PSFS_FEED_ME:
381
382
383
384 stream->readpos = 0;
385 stream->writepos = 0;
386 break;
387 case PSFS_PASS_ON:
388
389
390
391
392 stream->writepos = 0;
393 stream->readpos = 0;
394
395 while (brig_outp->head) {
396 bucket = brig_outp->head;
397
398
399 if (stream->readbuflen - stream->writepos < bucket->buflen) {
400 stream->readbuflen += bucket->buflen;
401 stream->readbuf = perealloc(stream->readbuf, stream->readbuflen, stream->is_persistent);
402 }
403 memcpy(stream->readbuf + stream->writepos, bucket->buf, bucket->buflen);
404 stream->writepos += bucket->buflen;
405
406 php_stream_bucket_unlink(bucket);
407 php_stream_bucket_delref(bucket);
408 }
409 break;
410 }
411 }
412
413 return SUCCESS;
414 }
415
416 PHPAPI void _php_stream_filter_append(php_stream_filter_chain *chain, php_stream_filter *filter)
417 {
418 if (php_stream_filter_append_ex(chain, filter) != SUCCESS) {
419 if (chain->head == filter) {
420 chain->head = NULL;
421 chain->tail = NULL;
422 } else {
423 filter->prev->next = NULL;
424 chain->tail = filter->prev;
425 }
426 }
427 }
428
429 PHPAPI int _php_stream_filter_flush(php_stream_filter *filter, int finish)
430 {
431 php_stream_bucket_brigade brig_a = { NULL, NULL }, brig_b = { NULL, NULL }, *inp = &brig_a, *outp = &brig_b, *brig_temp;
432 php_stream_bucket *bucket;
433 php_stream_filter_chain *chain;
434 php_stream_filter *current;
435 php_stream *stream;
436 size_t flushed_size = 0;
437 long flags = (finish ? PSFS_FLAG_FLUSH_CLOSE : PSFS_FLAG_FLUSH_INC);
438
439 if (!filter->chain || !filter->chain->stream) {
440
441 return FAILURE;
442 }
443
444 chain = filter->chain;
445 stream = chain->stream;
446
447 for(current = filter; current; current = current->next) {
448 php_stream_filter_status_t status;
449
450 status = filter->fops->filter(stream, current, inp, outp, NULL, flags);
451 if (status == PSFS_FEED_ME) {
452
453 return SUCCESS;
454 }
455 if (status == PSFS_ERR_FATAL) {
456 return FAILURE;
457 }
458
459
460 brig_temp = inp;
461 inp = outp;
462 outp = brig_temp;
463 outp->head = NULL;
464 outp->tail = NULL;
465
466 flags = PSFS_FLAG_NORMAL;
467 }
468
469
470
471
472 for(bucket = inp->head; bucket; bucket = bucket->next) {
473 flushed_size += bucket->buflen;
474 }
475
476 if (flushed_size == 0) {
477
478 return SUCCESS;
479 }
480
481 if (chain == &(stream->readfilters)) {
482
483 if (stream->readpos > 0) {
484
485 memcpy(stream->readbuf, stream->readbuf + stream->readpos, stream->writepos - stream->readpos);
486 stream->readpos = 0;
487 stream->writepos -= stream->readpos;
488 }
489 if (flushed_size > (stream->readbuflen - stream->writepos)) {
490
491 stream->readbuf = perealloc(stream->readbuf, stream->writepos + flushed_size + stream->chunk_size, stream->is_persistent);
492 }
493 while ((bucket = inp->head)) {
494 memcpy(stream->readbuf + stream->writepos, bucket->buf, bucket->buflen);
495 stream->writepos += bucket->buflen;
496 php_stream_bucket_unlink(bucket);
497 php_stream_bucket_delref(bucket);
498 }
499 } else if (chain == &(stream->writefilters)) {
500
501 while ((bucket = inp->head)) {
502 stream->ops->write(stream, bucket->buf, bucket->buflen);
503 php_stream_bucket_unlink(bucket);
504 php_stream_bucket_delref(bucket);
505 }
506 }
507
508 return SUCCESS;
509 }
510
511 PHPAPI php_stream_filter *php_stream_filter_remove(php_stream_filter *filter, int call_dtor)
512 {
513 if (filter->prev) {
514 filter->prev->next = filter->next;
515 } else {
516 filter->chain->head = filter->next;
517 }
518 if (filter->next) {
519 filter->next->prev = filter->prev;
520 } else {
521 filter->chain->tail = filter->prev;
522 }
523
524 if (filter->res) {
525 zend_list_delete(filter->res);
526 }
527
528 if (call_dtor) {
529 php_stream_filter_free(filter);
530 return NULL;
531 }
532 return filter;
533 }
534
535
536
537
538
539
540
541
542