1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 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: Wez Furlong <wez@thebrainroom.com> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: plain_wrapper.c 275506 2009-02-10 16:14:27Z iliaa $ */
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 "ext/standard/flock_compat.h"
27 : #include "ext/standard/php_filestat.h"
28 : #include <stddef.h>
29 : #include <fcntl.h>
30 : #if HAVE_SYS_WAIT_H
31 : #include <sys/wait.h>
32 : #endif
33 : #if HAVE_SYS_FILE_H
34 : #include <sys/file.h>
35 : #endif
36 : #ifdef HAVE_SYS_MMAN_H
37 : #include <sys/mman.h>
38 : #endif
39 : #include "SAPI.h"
40 :
41 : #include "php_streams_int.h"
42 :
43 : #define php_stream_fopen_from_fd_int(fd, mode, persistent_id) _php_stream_fopen_from_fd_int((fd), (mode), (persistent_id) STREAMS_CC TSRMLS_CC)
44 : #define php_stream_fopen_from_fd_int_rel(fd, mode, persistent_id) _php_stream_fopen_from_fd_int((fd), (mode), (persistent_id) STREAMS_REL_CC TSRMLS_CC)
45 : #define php_stream_fopen_from_file_int(file, mode) _php_stream_fopen_from_file_int((file), (mode) STREAMS_CC TSRMLS_CC)
46 : #define php_stream_fopen_from_file_int_rel(file, mode) _php_stream_fopen_from_file_int((file), (mode) STREAMS_REL_CC TSRMLS_CC)
47 :
48 : /* parse standard "fopen" modes into open() flags */
49 : PHPAPI int php_stream_parse_fopen_modes(const char *mode, int *open_flags)
50 46906 : {
51 : int flags;
52 :
53 46906 : switch (mode[0]) {
54 : case 'r':
55 24433 : flags = 0;
56 24433 : break;
57 : case 'w':
58 19844 : flags = O_TRUNC|O_CREAT;
59 19844 : break;
60 : case 'a':
61 1374 : flags = O_CREAT|O_APPEND;
62 1374 : break;
63 : case 'x':
64 1232 : flags = O_CREAT|O_EXCL;
65 1232 : break;
66 : case 'c':
67 0 : flags = O_CREAT;
68 0 : break;
69 : default:
70 : /* unknown mode */
71 23 : return FAILURE;
72 : }
73 :
74 46883 : if (strchr(mode, '+')) {
75 4030 : flags |= O_RDWR;
76 42853 : } else if (flags) {
77 19114 : flags |= O_WRONLY;
78 : } else {
79 23739 : flags |= O_RDONLY;
80 : }
81 :
82 : #if defined(_O_TEXT) && defined(O_BINARY)
83 : if (strchr(mode, 't')) {
84 : flags |= _O_TEXT;
85 : } else {
86 : flags |= O_BINARY;
87 : }
88 : #endif
89 :
90 46883 : *open_flags = flags;
91 46883 : return SUCCESS;
92 : }
93 :
94 :
95 : /* {{{ ------- STDIO stream implementation -------*/
96 :
97 : typedef struct {
98 : FILE *file;
99 : int fd; /* underlying file descriptor */
100 : unsigned is_process_pipe:1; /* use pclose instead of fclose */
101 : unsigned is_pipe:1; /* don't try and seek */
102 : unsigned cached_fstat:1; /* sb is valid */
103 : unsigned _reserved:29;
104 :
105 : int lock_flag; /* stores the lock state */
106 : char *temp_file_name; /* if non-null, this is the path to a temporary file that
107 : * is to be deleted when the stream is closed */
108 : #if HAVE_FLUSHIO
109 : char last_op;
110 : #endif
111 :
112 : #if HAVE_MMAP
113 : char *last_mapped_addr;
114 : size_t last_mapped_len;
115 : #endif
116 : #ifdef PHP_WIN32
117 : char *last_mapped_addr;
118 : HANDLE file_mapping;
119 : #endif
120 :
121 : struct stat sb;
122 : } php_stdio_stream_data;
123 : #define PHP_STDIOP_GET_FD(anfd, data) anfd = (data)->file ? fileno((data)->file) : (data)->fd
124 :
125 : static int do_fstat(php_stdio_stream_data *d, int force)
126 124797 : {
127 124797 : if (!d->cached_fstat || force) {
128 : int fd;
129 : int r;
130 :
131 124797 : PHP_STDIOP_GET_FD(fd, d);
132 124797 : r = fstat(fd, &d->sb);
133 124797 : d->cached_fstat = r == 0;
134 :
135 124797 : return r;
136 : }
137 0 : return 0;
138 : }
139 :
140 : static php_stream *_php_stream_fopen_from_fd_int(int fd, const char *mode, const char *persistent_id STREAMS_DC TSRMLS_DC)
141 81902 : {
142 : php_stdio_stream_data *self;
143 :
144 81902 : self = pemalloc_rel_orig(sizeof(*self), persistent_id);
145 81902 : memset(self, 0, sizeof(*self));
146 81902 : self->file = NULL;
147 81902 : self->is_pipe = 0;
148 81902 : self->lock_flag = LOCK_UN;
149 81902 : self->is_process_pipe = 0;
150 81902 : self->temp_file_name = NULL;
151 81902 : self->fd = fd;
152 :
153 81902 : return php_stream_alloc_rel(&php_stream_stdio_ops, self, persistent_id, mode);
154 : }
155 :
156 : static php_stream *_php_stream_fopen_from_file_int(FILE *file, const char *mode STREAMS_DC TSRMLS_DC)
157 40239 : {
158 : php_stdio_stream_data *self;
159 :
160 40239 : self = emalloc_rel_orig(sizeof(*self));
161 40239 : memset(self, 0, sizeof(*self));
162 40239 : self->file = file;
163 40239 : self->is_pipe = 0;
164 40239 : self->lock_flag = LOCK_UN;
165 40239 : self->is_process_pipe = 0;
166 40239 : self->temp_file_name = NULL;
167 40239 : self->fd = fileno(file);
168 :
169 40239 : return php_stream_alloc_rel(&php_stream_stdio_ops, self, 0, mode);
170 : }
171 :
172 : PHPAPI php_stream *_php_stream_fopen_temporary_file(const char *dir, const char *pfx, char **opened_path STREAMS_DC TSRMLS_DC)
173 0 : {
174 0 : int fd = php_open_temporary_fd(dir, pfx, opened_path TSRMLS_CC);
175 :
176 0 : if (fd != -1) {
177 0 : php_stream *stream = php_stream_fopen_from_fd_int_rel(fd, "r+b", NULL);
178 0 : if (stream) {
179 0 : return stream;
180 : }
181 0 : close(fd);
182 :
183 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to allocate stream");
184 :
185 0 : return NULL;
186 : }
187 0 : return NULL;
188 : }
189 :
190 : PHPAPI php_stream *_php_stream_fopen_tmpfile(int dummy STREAMS_DC TSRMLS_DC)
191 73 : {
192 73 : char *opened_path = NULL;
193 73 : int fd = php_open_temporary_fd(NULL, "php", &opened_path TSRMLS_CC);
194 :
195 73 : if (fd != -1) {
196 73 : php_stream *stream = php_stream_fopen_from_fd_int_rel(fd, "r+b", NULL);
197 73 : if (stream) {
198 73 : php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
199 73 : stream->wrapper = &php_plain_files_wrapper;
200 73 : stream->orig_path = estrdup(opened_path);
201 :
202 73 : self->temp_file_name = opened_path;
203 73 : self->lock_flag = LOCK_UN;
204 :
205 73 : return stream;
206 : }
207 0 : close(fd);
208 :
209 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to allocate stream");
210 :
211 0 : return NULL;
212 : }
213 0 : return NULL;
214 : }
215 :
216 : PHPAPI php_stream *_php_stream_fopen_from_fd(int fd, const char *mode, const char *persistent_id STREAMS_DC TSRMLS_DC)
217 77751 : {
218 77751 : php_stream *stream = php_stream_fopen_from_fd_int_rel(fd, mode, persistent_id);
219 :
220 77751 : if (stream) {
221 77751 : php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
222 :
223 : #ifdef S_ISFIFO
224 : /* detect if this is a pipe */
225 77751 : if (self->fd >= 0) {
226 77751 : self->is_pipe = (do_fstat(self, 0) == 0 && S_ISFIFO(self->sb.st_mode)) ? 1 : 0;
227 : }
228 : #elif defined(PHP_WIN32)
229 : {
230 : zend_uintptr_t handle = _get_osfhandle(self->fd);
231 :
232 : if (handle != (zend_uintptr_t)INVALID_HANDLE_VALUE) {
233 : self->is_pipe = GetFileType((HANDLE)handle) == FILE_TYPE_PIPE;
234 : }
235 : }
236 : #endif
237 :
238 77751 : if (self->is_pipe) {
239 40428 : stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
240 : } else {
241 37323 : stream->position = lseek(self->fd, 0, SEEK_CUR);
242 : #ifdef ESPIPE
243 37323 : if (stream->position == (off_t)-1 && errno == ESPIPE) {
244 0 : stream->position = 0;
245 0 : stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
246 0 : self->is_pipe = 1;
247 : }
248 : #endif
249 : }
250 : }
251 :
252 77751 : return stream;
253 : }
254 :
255 : PHPAPI php_stream *_php_stream_fopen_from_file(FILE *file, const char *mode STREAMS_DC TSRMLS_DC)
256 40239 : {
257 40239 : php_stream *stream = php_stream_fopen_from_file_int_rel(file, mode);
258 :
259 40239 : if (stream) {
260 40239 : php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
261 :
262 : #ifdef S_ISFIFO
263 : /* detect if this is a pipe */
264 40239 : if (self->fd >= 0) {
265 40239 : self->is_pipe = (do_fstat(self, 0) == 0 && S_ISFIFO(self->sb.st_mode)) ? 1 : 0;
266 : }
267 : #elif defined(PHP_WIN32)
268 : {
269 : zend_uintptr_t handle = _get_osfhandle(self->fd);
270 :
271 : if (handle != (zend_uintptr_t)INVALID_HANDLE_VALUE) {
272 : self->is_pipe = GetFileType((HANDLE)handle) == FILE_TYPE_PIPE;
273 : }
274 : }
275 : #endif
276 :
277 40239 : if (self->is_pipe) {
278 40233 : stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
279 : } else {
280 6 : stream->position = ftell(file);
281 : }
282 : }
283 :
284 40239 : return stream;
285 : }
286 :
287 : PHPAPI php_stream *_php_stream_fopen_from_pipe(FILE *file, const char *mode STREAMS_DC TSRMLS_DC)
288 124 : {
289 : php_stdio_stream_data *self;
290 : php_stream *stream;
291 :
292 124 : self = emalloc_rel_orig(sizeof(*self));
293 124 : memset(self, 0, sizeof(*self));
294 124 : self->file = file;
295 124 : self->is_pipe = 1;
296 124 : self->lock_flag = LOCK_UN;
297 124 : self->is_process_pipe = 1;
298 124 : self->fd = fileno(file);
299 124 : self->temp_file_name = NULL;
300 :
301 124 : stream = php_stream_alloc_rel(&php_stream_stdio_ops, self, 0, mode);
302 124 : stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
303 124 : return stream;
304 : }
305 :
306 : static size_t php_stdiop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
307 86127 : {
308 86127 : php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
309 :
310 : assert(data != NULL);
311 :
312 86127 : if (data->fd >= 0) {
313 86127 : int bytes_written = write(data->fd, buf, count);
314 86127 : if (bytes_written < 0) return 0;
315 86072 : return (size_t) bytes_written;
316 : } else {
317 :
318 : #if HAVE_FLUSHIO
319 : if (!data->is_pipe && data->last_op == 'r') {
320 : fseek(data->file, 0, SEEK_CUR);
321 : }
322 : data->last_op = 'w';
323 : #endif
324 :
325 0 : return fwrite(buf, 1, count, data->file);
326 : }
327 : }
328 :
329 : static size_t php_stdiop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
330 684826 : {
331 684826 : php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
332 : size_t ret;
333 :
334 : assert(data != NULL);
335 :
336 684826 : if (data->fd >= 0) {
337 684823 : ret = read(data->fd, buf, count);
338 :
339 684823 : if (ret == (size_t)-1 && errno == EINTR) {
340 : /* Read was interrupted, retry once,
341 : If read still fails, giveup with feof==0
342 : so script can retry if desired */
343 0 : ret = read(data->fd, buf, count);
344 : }
345 :
346 684823 : stream->eof = (ret == 0 || (ret == (size_t)-1 && errno != EWOULDBLOCK && errno != EINTR && errno != EBADF));
347 :
348 : } else {
349 : #if HAVE_FLUSHIO
350 : if (!data->is_pipe && data->last_op == 'w')
351 : fseek(data->file, 0, SEEK_CUR);
352 : data->last_op = 'r';
353 : #endif
354 :
355 3 : ret = fread(buf, 1, count, data->file);
356 :
357 3 : stream->eof = feof(data->file);
358 : }
359 684826 : return ret;
360 : }
361 :
362 : static int php_stdiop_close(php_stream *stream, int close_handle TSRMLS_DC)
363 122373 : {
364 : int ret;
365 122373 : php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
366 :
367 : assert(data != NULL);
368 :
369 : #if HAVE_MMAP
370 122373 : if (data->last_mapped_addr) {
371 0 : munmap(data->last_mapped_addr, data->last_mapped_len);
372 0 : data->last_mapped_addr = NULL;
373 : }
374 : #elif defined(PHP_WIN32)
375 : if (data->last_mapped_addr) {
376 : UnmapViewOfFile(data->last_mapped_addr);
377 : data->last_mapped_addr = NULL;
378 : }
379 : if (data->file_mapping) {
380 : CloseHandle(data->file_mapping);
381 : data->file_mapping = NULL;
382 : }
383 : #endif
384 :
385 122373 : if (close_handle) {
386 122373 : if (data->lock_flag != LOCK_UN) {
387 54 : php_stream_lock(stream, LOCK_UN);
388 : }
389 122373 : if (data->file) {
390 40541 : if (data->is_process_pipe) {
391 124 : errno = 0;
392 124 : ret = pclose(data->file);
393 :
394 : #if HAVE_SYS_WAIT_H
395 124 : if (WIFEXITED(ret)) {
396 124 : ret = WEXITSTATUS(ret);
397 : }
398 : #endif
399 : } else {
400 40417 : ret = fclose(data->file);
401 40417 : data->file = NULL;
402 : }
403 81832 : } else if (data->fd != -1) {
404 81832 : ret = close(data->fd);
405 81832 : data->fd = -1;
406 : } else {
407 0 : return 0; /* everything should be closed already -> success */
408 : }
409 122373 : if (data->temp_file_name) {
410 73 : unlink(data->temp_file_name);
411 : /* temporary streams are never persistent */
412 73 : efree(data->temp_file_name);
413 73 : data->temp_file_name = NULL;
414 : }
415 : } else {
416 0 : ret = 0;
417 0 : data->file = NULL;
418 0 : data->fd = -1;
419 : }
420 :
421 122373 : pefree(data, stream->is_persistent);
422 :
423 122373 : return ret;
424 : }
425 :
426 : static int php_stdiop_flush(php_stream *stream TSRMLS_DC)
427 123143 : {
428 123143 : php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
429 :
430 : assert(data != NULL);
431 :
432 : /*
433 : * stdio buffers data in user land. By calling fflush(3), this
434 : * data is send to the kernel using write(2). fsync'ing is
435 : * something completely different.
436 : */
437 123143 : if (data->file) {
438 40547 : return fflush(data->file);
439 : }
440 82596 : return 0;
441 : }
442 :
443 : static int php_stdiop_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC)
444 11840 : {
445 11840 : php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
446 : int ret;
447 :
448 : assert(data != NULL);
449 :
450 11840 : if (data->is_pipe) {
451 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot seek on a pipe");
452 0 : return -1;
453 : }
454 :
455 11840 : if (data->fd >= 0) {
456 : off_t result;
457 :
458 11840 : result = lseek(data->fd, offset, whence);
459 11840 : if (result == (off_t)-1)
460 189 : return -1;
461 :
462 11651 : *newoffset = result;
463 11651 : return 0;
464 :
465 : } else {
466 0 : ret = fseek(data->file, offset, whence);
467 0 : *newoffset = ftell(data->file);
468 0 : return ret;
469 : }
470 : }
471 :
472 : static int php_stdiop_cast(php_stream *stream, int castas, void **ret TSRMLS_DC)
473 2454291 : {
474 : int fd;
475 2454291 : php_stdio_stream_data *data = (php_stdio_stream_data*) stream->abstract;
476 :
477 : assert(data != NULL);
478 :
479 : /* as soon as someone touches the stdio layer, buffering may ensue,
480 : * so we need to stop using the fd directly in that case */
481 :
482 2454291 : switch (castas) {
483 : case PHP_STREAM_AS_STDIO:
484 71 : if (ret) {
485 :
486 71 : if (data->file == NULL) {
487 : /* we were opened as a plain file descriptor, so we
488 : * need fdopen now */
489 70 : data->file = fdopen(data->fd, stream->mode);
490 70 : if (data->file == NULL) {
491 0 : return FAILURE;
492 : }
493 : }
494 :
495 71 : *(FILE**)ret = data->file;
496 71 : data->fd = -1;
497 : }
498 71 : return SUCCESS;
499 :
500 : case PHP_STREAM_AS_FD_FOR_SELECT:
501 2453968 : PHP_STDIOP_GET_FD(fd, data);
502 2453968 : if (fd < 0) {
503 0 : return FAILURE;
504 : }
505 2453968 : if (ret) {
506 2453968 : *(int*)ret = fd;
507 : }
508 2453968 : return SUCCESS;
509 :
510 : case PHP_STREAM_AS_FD:
511 252 : PHP_STDIOP_GET_FD(fd, data);
512 :
513 252 : if (fd < 0) {
514 0 : return FAILURE;
515 : }
516 252 : if (data->file) {
517 8 : fflush(data->file);
518 : }
519 252 : if (ret) {
520 249 : *(int*)ret = fd;
521 : }
522 252 : return SUCCESS;
523 : default:
524 0 : return FAILURE;
525 : }
526 : }
527 :
528 : static int php_stdiop_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
529 2183 : {
530 : int ret;
531 2183 : php_stdio_stream_data *data = (php_stdio_stream_data*) stream->abstract;
532 :
533 : assert(data != NULL);
534 :
535 2183 : ret = do_fstat(data, 1);
536 2183 : memcpy(&ssb->sb, &data->sb, sizeof(ssb->sb));
537 2183 : return ret;
538 : }
539 :
540 : static int php_stdiop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
541 25666 : {
542 25666 : php_stdio_stream_data *data = (php_stdio_stream_data*) stream->abstract;
543 : size_t size;
544 : int fd;
545 : #ifdef O_NONBLOCK
546 : /* FIXME: make this work for win32 */
547 : int flags;
548 : int oldval;
549 : #endif
550 :
551 25666 : PHP_STDIOP_GET_FD(fd, data);
552 :
553 25666 : switch(option) {
554 : case PHP_STREAM_OPTION_BLOCKING:
555 1 : if (fd == -1)
556 0 : return -1;
557 : #ifdef O_NONBLOCK
558 1 : flags = fcntl(fd, F_GETFL, 0);
559 1 : oldval = (flags & O_NONBLOCK) ? 0 : 1;
560 1 : if (value)
561 0 : flags &= ~O_NONBLOCK;
562 : else
563 1 : flags |= O_NONBLOCK;
564 :
565 1 : if (-1 == fcntl(fd, F_SETFL, flags))
566 0 : return -1;
567 1 : return oldval;
568 : #else
569 : return -1; /* not yet implemented */
570 : #endif
571 :
572 : case PHP_STREAM_OPTION_WRITE_BUFFER:
573 :
574 0 : if (data->file == NULL) {
575 0 : return -1;
576 : }
577 :
578 0 : if (ptrparam)
579 0 : size = *(size_t *)ptrparam;
580 : else
581 0 : size = BUFSIZ;
582 :
583 0 : switch(value) {
584 : case PHP_STREAM_BUFFER_NONE:
585 0 : stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
586 0 : return setvbuf(data->file, NULL, _IONBF, 0);
587 :
588 : case PHP_STREAM_BUFFER_LINE:
589 0 : stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER;
590 0 : return setvbuf(data->file, NULL, _IOLBF, size);
591 :
592 : case PHP_STREAM_BUFFER_FULL:
593 0 : stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER;
594 0 : return setvbuf(data->file, NULL, _IOFBF, size);
595 :
596 : default:
597 0 : return -1;
598 : }
599 : break;
600 :
601 : case PHP_STREAM_OPTION_LOCKING:
602 301 : if (fd == -1) {
603 0 : return -1;
604 : }
605 :
606 301 : if ((zend_uintptr_t) ptrparam == PHP_STREAM_LOCK_SUPPORTED) {
607 52 : return 0;
608 : }
609 :
610 249 : if (!flock(fd, value)) {
611 249 : data->lock_flag = value;
612 249 : return 0;
613 : } else {
614 0 : return -1;
615 : }
616 : break;
617 :
618 : case PHP_STREAM_OPTION_MMAP_API:
619 : #if HAVE_MMAP
620 : {
621 1537 : php_stream_mmap_range *range = (php_stream_mmap_range*)ptrparam;
622 : int prot, flags;
623 :
624 1537 : switch (value) {
625 : case PHP_STREAM_MMAP_SUPPORTED:
626 546 : return fd == -1 ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK;
627 :
628 : case PHP_STREAM_MMAP_MAP_RANGE:
629 546 : do_fstat(data, 1);
630 546 : if (range->length == 0 && range->offset > 0 && range->offset < data->sb.st_size) {
631 17 : range->length = data->sb.st_size - range->offset;
632 : }
633 546 : if (range->length == 0 || range->length > data->sb.st_size) {
634 517 : range->length = data->sb.st_size;
635 : }
636 546 : if (range->offset >= data->sb.st_size) {
637 84 : range->offset = data->sb.st_size;
638 84 : range->length = 0;
639 : }
640 546 : switch (range->mode) {
641 : case PHP_STREAM_MAP_MODE_READONLY:
642 0 : prot = PROT_READ;
643 0 : flags = MAP_PRIVATE;
644 0 : break;
645 : case PHP_STREAM_MAP_MODE_READWRITE:
646 0 : prot = PROT_READ | PROT_WRITE;
647 0 : flags = MAP_PRIVATE;
648 0 : break;
649 : case PHP_STREAM_MAP_MODE_SHARED_READONLY:
650 546 : prot = PROT_READ;
651 546 : flags = MAP_SHARED;
652 546 : break;
653 : case PHP_STREAM_MAP_MODE_SHARED_READWRITE:
654 0 : prot = PROT_READ | PROT_WRITE;
655 0 : flags = MAP_SHARED;
656 0 : break;
657 : default:
658 0 : return PHP_STREAM_OPTION_RETURN_ERR;
659 : }
660 546 : range->mapped = (char*)mmap(NULL, range->length, prot, flags, fd, range->offset);
661 546 : if (range->mapped == (char*)MAP_FAILED) {
662 101 : range->mapped = NULL;
663 101 : return PHP_STREAM_OPTION_RETURN_ERR;
664 : }
665 : /* remember the mapping */
666 445 : data->last_mapped_addr = range->mapped;
667 445 : data->last_mapped_len = range->length;
668 445 : return PHP_STREAM_OPTION_RETURN_OK;
669 :
670 : case PHP_STREAM_MMAP_UNMAP:
671 445 : if (data->last_mapped_addr) {
672 445 : munmap(data->last_mapped_addr, data->last_mapped_len);
673 445 : data->last_mapped_addr = NULL;
674 :
675 445 : return PHP_STREAM_OPTION_RETURN_OK;
676 : }
677 0 : return PHP_STREAM_OPTION_RETURN_ERR;
678 : }
679 : }
680 : #elif defined(PHP_WIN32)
681 : {
682 : php_stream_mmap_range *range = (php_stream_mmap_range*)ptrparam;
683 : HANDLE hfile = (HANDLE)_get_osfhandle(fd);
684 : DWORD prot, acc, loffs = 0, delta = 0;
685 :
686 : switch (value) {
687 : case PHP_STREAM_MMAP_SUPPORTED:
688 : return hfile == INVALID_HANDLE_VALUE ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK;
689 :
690 : case PHP_STREAM_MMAP_MAP_RANGE:
691 : switch (range->mode) {
692 : case PHP_STREAM_MAP_MODE_READONLY:
693 : prot = PAGE_READONLY;
694 : acc = FILE_MAP_READ;
695 : break;
696 : case PHP_STREAM_MAP_MODE_READWRITE:
697 : prot = PAGE_READWRITE;
698 : acc = FILE_MAP_READ | FILE_MAP_WRITE;
699 : break;
700 : case PHP_STREAM_MAP_MODE_SHARED_READONLY:
701 : prot = PAGE_READONLY;
702 : acc = FILE_MAP_READ;
703 : /* TODO: we should assign a name for the mapping */
704 : break;
705 : case PHP_STREAM_MAP_MODE_SHARED_READWRITE:
706 : prot = PAGE_READWRITE;
707 : acc = FILE_MAP_READ | FILE_MAP_WRITE;
708 : /* TODO: we should assign a name for the mapping */
709 : break;
710 : }
711 :
712 : /* create a mapping capable of viewing the whole file (this costs no real resources) */
713 : data->file_mapping = CreateFileMapping(hfile, NULL, prot, 0, 0, NULL);
714 :
715 : if (data->file_mapping == NULL) {
716 : return PHP_STREAM_OPTION_RETURN_ERR;
717 : }
718 :
719 : size = GetFileSize(hfile, NULL);
720 : if (range->length == 0 && range->offset > 0 && range->offset < size) {
721 : range->length = size - range->offset;
722 : }
723 : if (range->length == 0 || range->length > size) {
724 : range->length = size;
725 : }
726 : if (range->offset >= size) {
727 : range->offset = size;
728 : range->length = 0;
729 : }
730 :
731 : /* figure out how big a chunk to map to be able to view the part that we need */
732 : if (range->offset != 0) {
733 : SYSTEM_INFO info;
734 : DWORD gran;
735 :
736 : GetSystemInfo(&info);
737 : gran = info.dwAllocationGranularity;
738 : loffs = (range->offset / gran) * gran;
739 : delta = range->offset - loffs;
740 : }
741 :
742 : data->last_mapped_addr = MapViewOfFile(data->file_mapping, acc, 0, loffs, range->length + delta);
743 :
744 : if (data->last_mapped_addr) {
745 : /* give them back the address of the start offset they requested */
746 : range->mapped = data->last_mapped_addr + delta;
747 : return PHP_STREAM_OPTION_RETURN_OK;
748 : }
749 :
750 : CloseHandle(data->file_mapping);
751 : data->file_mapping = NULL;
752 :
753 : return PHP_STREAM_OPTION_RETURN_ERR;
754 :
755 : case PHP_STREAM_MMAP_UNMAP:
756 : if (data->last_mapped_addr) {
757 : UnmapViewOfFile(data->last_mapped_addr);
758 : data->last_mapped_addr = NULL;
759 : CloseHandle(data->file_mapping);
760 : data->file_mapping = NULL;
761 : return PHP_STREAM_OPTION_RETURN_OK;
762 : }
763 : return PHP_STREAM_OPTION_RETURN_ERR;
764 :
765 : default:
766 : return PHP_STREAM_OPTION_RETURN_ERR;
767 : }
768 : }
769 :
770 : #endif
771 0 : return PHP_STREAM_OPTION_RETURN_NOTIMPL;
772 :
773 : case PHP_STREAM_OPTION_TRUNCATE_API:
774 774 : switch (value) {
775 : case PHP_STREAM_TRUNCATE_SUPPORTED:
776 377 : return fd == -1 ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK;
777 :
778 : case PHP_STREAM_TRUNCATE_SET_SIZE: {
779 397 : ptrdiff_t new_size = *(ptrdiff_t*)ptrparam;
780 397 : if (new_size < 0) {
781 50 : return PHP_STREAM_OPTION_RETURN_ERR;
782 : }
783 347 : return ftruncate(fd, new_size) == 0 ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR;
784 : }
785 : }
786 :
787 : default:
788 23053 : return PHP_STREAM_OPTION_RETURN_NOTIMPL;
789 : }
790 : }
791 :
792 : PHPAPI php_stream_ops php_stream_stdio_ops = {
793 : php_stdiop_write, php_stdiop_read,
794 : php_stdiop_close, php_stdiop_flush,
795 : "STDIO",
796 : php_stdiop_seek,
797 : php_stdiop_cast,
798 : php_stdiop_stat,
799 : php_stdiop_set_option
800 : };
801 : /* }}} */
802 :
803 : /* {{{ plain files opendir/readdir implementation */
804 : static size_t php_plain_files_dirstream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
805 49355 : {
806 49355 : DIR *dir = (DIR*)stream->abstract;
807 : /* avoid libc5 readdir problems */
808 : char entry[sizeof(struct dirent)+MAXPATHLEN];
809 49355 : struct dirent *result = (struct dirent *)&entry;
810 49355 : php_stream_dirent *ent = (php_stream_dirent*)buf;
811 :
812 : /* avoid problems if someone mis-uses the stream */
813 49355 : if (count != sizeof(php_stream_dirent))
814 0 : return 0;
815 :
816 49355 : if (php_readdir_r(dir, (struct dirent *)entry, &result) == 0 && result) {
817 46826 : PHP_STRLCPY(ent->d_name, result->d_name, sizeof(ent->d_name), strlen(result->d_name));
818 46826 : return sizeof(php_stream_dirent);
819 : }
820 2529 : return 0;
821 : }
822 :
823 : static int php_plain_files_dirstream_close(php_stream *stream, int close_handle TSRMLS_DC)
824 2663 : {
825 2663 : return closedir((DIR *)stream->abstract);
826 : }
827 :
828 : static int php_plain_files_dirstream_rewind(php_stream *stream, off_t offset, int whence, off_t *newoffs TSRMLS_DC)
829 10 : {
830 10 : rewinddir((DIR *)stream->abstract);
831 10 : return 0;
832 : }
833 :
834 : static php_stream_ops php_plain_files_dirstream_ops = {
835 : NULL, php_plain_files_dirstream_read,
836 : php_plain_files_dirstream_close, NULL,
837 : "dir",
838 : php_plain_files_dirstream_rewind,
839 : NULL, /* cast */
840 : NULL, /* stat */
841 : NULL /* set_option */
842 : };
843 :
844 : static php_stream *php_plain_files_dir_opener(php_stream_wrapper *wrapper, char *path, char *mode,
845 : int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
846 2745 : {
847 2745 : DIR *dir = NULL;
848 2745 : php_stream *stream = NULL;
849 :
850 2745 : if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(path TSRMLS_CC)) {
851 24 : return NULL;
852 : }
853 :
854 2721 : if (PG(safe_mode) &&(!php_checkuid(path, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
855 0 : return NULL;
856 : }
857 :
858 2721 : dir = VCWD_OPENDIR(path);
859 :
860 : #ifdef PHP_WIN32
861 : if (dir && dir->finished) {
862 : closedir(dir);
863 : dir = NULL;
864 : }
865 : #endif
866 2721 : if (dir) {
867 2663 : stream = php_stream_alloc(&php_plain_files_dirstream_ops, dir, 0, mode);
868 2663 : if (stream == NULL)
869 0 : closedir(dir);
870 : }
871 :
872 2721 : return stream;
873 : }
874 : /* }}} */
875 :
876 : /* {{{ php_stream_fopen */
877 : PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, char **opened_path, int options STREAMS_DC TSRMLS_DC)
878 46906 : {
879 46906 : char *realpath = NULL;
880 : int open_flags;
881 : int fd;
882 : php_stream *ret;
883 46906 : int persistent = options & STREAM_OPEN_PERSISTENT;
884 46906 : char *persistent_id = NULL;
885 :
886 46906 : if (FAILURE == php_stream_parse_fopen_modes(mode, &open_flags)) {
887 23 : if (options & REPORT_ERRORS) {
888 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "`%s' is not a valid mode for fopen", mode);
889 : }
890 23 : return NULL;
891 : }
892 :
893 46883 : if ((realpath = expand_filepath(filename, NULL TSRMLS_CC)) == NULL) {
894 0 : return NULL;
895 : }
896 :
897 46883 : if (persistent) {
898 13 : spprintf(&persistent_id, 0, "streams_stdio_%d_%s", open_flags, realpath);
899 13 : switch (php_stream_from_persistent_id(persistent_id, &ret TSRMLS_CC)) {
900 : case PHP_STREAM_PERSISTENT_SUCCESS:
901 0 : if (opened_path) {
902 0 : *opened_path = realpath;
903 0 : realpath = NULL;
904 : }
905 : /* fall through */
906 :
907 : case PHP_STREAM_PERSISTENT_FAILURE:
908 0 : if (realpath) {
909 0 : efree(realpath);
910 : }
911 0 : efree(persistent_id);;
912 0 : return ret;
913 : }
914 : }
915 :
916 46883 : fd = open(realpath, open_flags, 0666);
917 :
918 46883 : if (fd != -1) {
919 :
920 41401 : if (options & STREAM_OPEN_FOR_INCLUDE) {
921 4078 : ret = php_stream_fopen_from_fd_int_rel(fd, mode, persistent_id);
922 : } else {
923 37323 : ret = php_stream_fopen_from_fd_rel(fd, mode, persistent_id);
924 : }
925 :
926 41401 : if (ret) {
927 41401 : if (opened_path) {
928 4130 : *opened_path = realpath;
929 4130 : realpath = NULL;
930 : }
931 41401 : if (realpath) {
932 37271 : efree(realpath);
933 : }
934 41401 : if (persistent_id) {
935 13 : efree(persistent_id);
936 : }
937 :
938 : /* WIN32 always set ISREG flag */
939 : #ifndef PHP_WIN32
940 : /* sanity checks for include/require.
941 : * We check these after opening the stream, so that we save
942 : * on fstat() syscalls */
943 41401 : if (options & STREAM_OPEN_FOR_INCLUDE) {
944 4078 : php_stdio_stream_data *self = (php_stdio_stream_data*)ret->abstract;
945 : int r;
946 :
947 4078 : r = do_fstat(self, 0);
948 4078 : if ((r == 0 && !S_ISREG(self->sb.st_mode))) {
949 1 : if (opened_path) {
950 1 : efree(*opened_path);
951 1 : *opened_path = NULL;
952 : }
953 1 : php_stream_close(ret);
954 1 : return NULL;
955 : }
956 : }
957 : #endif
958 :
959 41400 : return ret;
960 : }
961 0 : close(fd);
962 : }
963 5482 : efree(realpath);
964 5482 : if (persistent_id) {
965 0 : efree(persistent_id);
966 : }
967 5482 : return NULL;
968 : }
969 : /* }}} */
970 :
971 :
972 : static php_stream *php_plain_files_stream_opener(php_stream_wrapper *wrapper, char *path, char *mode,
973 : int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
974 41691 : {
975 41691 : if ((options & USE_PATH) && PG(include_path) != NULL) {
976 4317 : return php_stream_fopen_with_path_rel(path, mode, PG(include_path), opened_path, options);
977 : }
978 :
979 37374 : if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(path TSRMLS_CC)) {
980 40 : return NULL;
981 : }
982 :
983 37334 : if ((options & ENFORCE_SAFE_MODE) && PG(safe_mode) && (!php_checkuid(path, mode, CHECKUID_CHECK_MODE_PARAM)))
984 0 : return NULL;
985 :
986 37334 : return php_stream_fopen_rel(path, mode, opened_path, options);
987 : }
988 :
989 : static int php_plain_files_url_stater(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC)
990 63884 : {
991 :
992 63884 : if (strncmp(url, "file://", sizeof("file://") - 1) == 0) {
993 0 : url += sizeof("file://") - 1;
994 : }
995 :
996 63884 : if (PG(safe_mode) &&(!php_checkuid_ex(url, NULL, CHECKUID_CHECK_FILE_AND_DIR, (flags & PHP_STREAM_URL_STAT_QUIET) ? CHECKUID_NO_ERRORS : 0))) {
997 0 : return -1;
998 : }
999 :
1000 63884 : if (php_check_open_basedir_ex(url, (flags & PHP_STREAM_URL_STAT_QUIET) ? 0 : 1 TSRMLS_CC)) {
1001 8 : return -1;
1002 : }
1003 :
1004 : #ifdef HAVE_SYMLINK
1005 63876 : if (flags & PHP_STREAM_URL_STAT_LINK) {
1006 106 : return VCWD_LSTAT(url, &ssb->sb);
1007 : } else
1008 : #endif
1009 63770 : return VCWD_STAT(url, &ssb->sb);
1010 : }
1011 :
1012 : static int php_plain_files_unlink(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC)
1013 132131 : {
1014 : char *p;
1015 : int ret;
1016 :
1017 132131 : if ((p = strstr(url, "://")) != NULL) {
1018 0 : url = p + 3;
1019 : }
1020 :
1021 132131 : if (options & ENFORCE_SAFE_MODE) {
1022 132131 : if (PG(safe_mode) && !php_checkuid(url, NULL, CHECKUID_CHECK_FILE_AND_DIR)) {
1023 0 : return 0;
1024 : }
1025 :
1026 132131 : if (php_check_open_basedir(url TSRMLS_CC)) {
1027 7 : return 0;
1028 : }
1029 : }
1030 :
1031 132124 : ret = VCWD_UNLINK(url);
1032 132124 : if (ret == -1) {
1033 115145 : if (options & REPORT_ERRORS) {
1034 115145 : php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "%s", strerror(errno));
1035 : }
1036 115145 : return 0;
1037 : }
1038 :
1039 : /* Clear stat cache */
1040 16979 : php_clear_stat_cache(TSRMLS_C);
1041 :
1042 16979 : return 1;
1043 : }
1044 :
1045 : static int php_plain_files_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC)
1046 81 : {
1047 : char *p;
1048 : int ret;
1049 :
1050 81 : if (!url_from || !url_to) {
1051 0 : return 0;
1052 : }
1053 :
1054 81 : if ((p = strstr(url_from, "://")) != NULL) {
1055 0 : url_from = p + 3;
1056 : }
1057 :
1058 81 : if ((p = strstr(url_to, "://")) != NULL) {
1059 0 : url_to = p + 3;
1060 : }
1061 :
1062 81 : if (PG(safe_mode) && (!php_checkuid(url_from, NULL, CHECKUID_CHECK_FILE_AND_DIR) ||
1063 : !php_checkuid(url_to, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
1064 0 : return 0;
1065 : }
1066 :
1067 81 : if (php_check_open_basedir(url_from TSRMLS_CC) || php_check_open_basedir(url_to TSRMLS_CC)) {
1068 5 : return 0;
1069 : }
1070 :
1071 76 : ret = VCWD_RENAME(url_from, url_to);
1072 :
1073 76 : if (ret == -1) {
1074 : #ifdef EXDEV
1075 26 : if (errno == EXDEV) {
1076 : struct stat sb;
1077 0 : if (php_copy_file(url_from, url_to TSRMLS_CC) == SUCCESS) {
1078 0 : if (VCWD_STAT(url_from, &sb) == 0) {
1079 : #if !defined(TSRM_WIN32) && !defined(NETWARE)
1080 0 : if (VCWD_CHMOD(url_to, sb.st_mode)) {
1081 0 : if (errno == EPERM) {
1082 0 : php_error_docref2(NULL TSRMLS_CC, url_from, url_to, E_WARNING, "%s", strerror(errno));
1083 0 : VCWD_UNLINK(url_from);
1084 0 : return 1;
1085 : }
1086 0 : php_error_docref2(NULL TSRMLS_CC, url_from, url_to, E_WARNING, "%s", strerror(errno));
1087 0 : return 0;
1088 : }
1089 0 : if (VCWD_CHOWN(url_to, sb.st_uid, sb.st_gid)) {
1090 0 : if (errno == EPERM) {
1091 0 : php_error_docref2(NULL TSRMLS_CC, url_from, url_to, E_WARNING, "%s", strerror(errno));
1092 0 : VCWD_UNLINK(url_from);
1093 0 : return 1;
1094 : }
1095 0 : php_error_docref2(NULL TSRMLS_CC, url_from, url_to, E_WARNING, "%s", strerror(errno));
1096 0 : return 0;
1097 : }
1098 : #endif
1099 0 : VCWD_UNLINK(url_from);
1100 0 : return 1;
1101 : }
1102 : }
1103 0 : php_error_docref2(NULL TSRMLS_CC, url_from, url_to, E_WARNING, "%s", strerror(errno));
1104 0 : return 0;
1105 : }
1106 : #endif
1107 26 : php_error_docref2(NULL TSRMLS_CC, url_from, url_to, E_WARNING, "%s", strerror(errno));
1108 26 : return 0;
1109 : }
1110 :
1111 : /* Clear stat cache */
1112 50 : php_clear_stat_cache(TSRMLS_C);
1113 :
1114 50 : return 1;
1115 : }
1116 :
1117 : static int php_plain_files_mkdir(php_stream_wrapper *wrapper, char *dir, int mode, int options, php_stream_context *context TSRMLS_DC)
1118 1623 : {
1119 1623 : int ret, recursive = options & PHP_STREAM_MKDIR_RECURSIVE;
1120 : char *p;
1121 :
1122 1623 : if ((p = strstr(dir, "://")) != NULL) {
1123 0 : dir = p + 3;
1124 : }
1125 :
1126 1623 : if (!recursive) {
1127 1078 : ret = php_mkdir(dir, mode TSRMLS_CC);
1128 : } else {
1129 : /* we look for directory separator from the end of string, thus hopefuly reducing our work load */
1130 : char *e, *buf;
1131 : struct stat sb;
1132 545 : int dir_len = strlen(dir);
1133 545 : int offset = 0;
1134 :
1135 545 : buf = estrndup(dir, dir_len);
1136 :
1137 : #ifdef PHP_WIN32
1138 : e = buf;
1139 : while (*e) {
1140 : if (*e == '/') {
1141 : *e = DEFAULT_SLASH;
1142 : }
1143 : e++;
1144 : }
1145 : #else
1146 545 : e = buf + dir_len;
1147 : #endif
1148 :
1149 545 : if ((p = memchr(buf, DEFAULT_SLASH, dir_len))) {
1150 531 : offset = p - buf + 1;
1151 : }
1152 :
1153 545 : if (p && dir_len == 1) {
1154 : /* buf == "DEFAULT_SLASH" */
1155 : }
1156 : else {
1157 : /* find a top level directory we need to create */
1158 1637 : while ( (p = strrchr(buf + offset, DEFAULT_SLASH)) || (offset != 1 && (p = strrchr(buf, DEFAULT_SLASH))) ) {
1159 1077 : int n = 0;
1160 :
1161 1077 : *p = '\0';
1162 2155 : while (p > buf && *(p-1) == DEFAULT_SLASH) {
1163 1 : ++n;
1164 1 : --p;
1165 1 : *p = '\0';
1166 : }
1167 1077 : if (VCWD_STAT(buf, &sb) == 0) {
1168 : while (1) {
1169 530 : *p = DEFAULT_SLASH;
1170 530 : if (!n) break;
1171 0 : --n;
1172 0 : ++p;
1173 0 : }
1174 530 : break;
1175 : }
1176 : }
1177 : }
1178 :
1179 545 : if (p == buf) {
1180 0 : ret = php_mkdir(dir, mode TSRMLS_CC);
1181 545 : } else if (!(ret = php_mkdir(buf, mode TSRMLS_CC))) {
1182 544 : if (!p) {
1183 15 : p = buf;
1184 : }
1185 : /* create any needed directories if the creation of the 1st directory worked */
1186 10394 : while (++p != e) {
1187 9306 : if (*p == '\0') {
1188 548 : *p = DEFAULT_SLASH;
1189 548 : if ((*(p+1) != '\0') &&
1190 : (ret = VCWD_MKDIR(buf, (mode_t)mode)) < 0) {
1191 0 : if (options & REPORT_ERRORS) {
1192 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
1193 : }
1194 0 : break;
1195 : }
1196 : }
1197 : }
1198 : }
1199 545 : efree(buf);
1200 : }
1201 1623 : if (ret < 0) {
1202 : /* Failure */
1203 49 : return 0;
1204 : } else {
1205 : /* Success */
1206 1574 : return 1;
1207 : }
1208 : }
1209 :
1210 : static int php_plain_files_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC)
1211 1636 : {
1212 1636 : if (PG(safe_mode) &&(!php_checkuid(url, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
1213 0 : return 0;
1214 : }
1215 :
1216 1636 : if (php_check_open_basedir(url TSRMLS_CC)) {
1217 5 : return 0;
1218 : }
1219 :
1220 1631 : if (VCWD_RMDIR(url) < 0) {
1221 30 : php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "%s", strerror(errno));
1222 30 : return 0;
1223 : }
1224 :
1225 : /* Clear stat cache */
1226 1601 : php_clear_stat_cache(TSRMLS_C);
1227 :
1228 1601 : return 1;
1229 : }
1230 :
1231 : static php_stream_wrapper_ops php_plain_files_wrapper_ops = {
1232 : php_plain_files_stream_opener,
1233 : NULL,
1234 : NULL,
1235 : php_plain_files_url_stater,
1236 : php_plain_files_dir_opener,
1237 : "plainfile",
1238 : php_plain_files_unlink,
1239 : php_plain_files_rename,
1240 : php_plain_files_mkdir,
1241 : php_plain_files_rmdir
1242 : };
1243 :
1244 : php_stream_wrapper php_plain_files_wrapper = {
1245 : &php_plain_files_wrapper_ops,
1246 : NULL,
1247 : 0
1248 : };
1249 :
1250 : /* {{{ php_stream_fopen_with_path */
1251 : PHPAPI php_stream *_php_stream_fopen_with_path(char *filename, char *mode, char *path, char **opened_path, int options STREAMS_DC TSRMLS_DC)
1252 4317 : {
1253 : /* code ripped off from fopen_wrappers.c */
1254 : char *pathbuf, *ptr, *end;
1255 : char *exec_fname;
1256 : char trypath[MAXPATHLEN];
1257 : struct stat sb;
1258 : php_stream *stream;
1259 : int path_length;
1260 : int filename_length;
1261 : int exec_fname_length;
1262 :
1263 4317 : if (opened_path) {
1264 4122 : *opened_path = NULL;
1265 : }
1266 :
1267 4317 : if(!filename) {
1268 0 : return NULL;
1269 : }
1270 :
1271 4317 : filename_length = strlen(filename);
1272 :
1273 : /* Relative path open */
1274 4317 : if (*filename == '.' && (IS_SLASH(filename[1]) || filename[1] == '.')) {
1275 : /* further checks, we could have ....... filenames */
1276 8 : ptr = filename + 1;
1277 8 : if (*ptr == '.') {
1278 6 : while (*(++ptr) == '.');
1279 6 : if (!IS_SLASH(*ptr)) { /* not a relative path after all */
1280 1 : goto not_relative_path;
1281 : }
1282 : }
1283 :
1284 :
1285 7 : if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(filename TSRMLS_CC)) {
1286 6 : return NULL;
1287 : }
1288 :
1289 1 : if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) {
1290 0 : return NULL;
1291 : }
1292 1 : return php_stream_fopen_rel(filename, mode, opened_path, options);
1293 : }
1294 :
1295 : /*
1296 : * files in safe_mode_include_dir (or subdir) are excluded from
1297 : * safe mode GID/UID checks
1298 : */
1299 :
1300 4310 : not_relative_path:
1301 :
1302 : /* Absolute path open */
1303 4310 : if (IS_ABSOLUTE_PATH(filename, filename_length)) {
1304 :
1305 1580 : if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(filename TSRMLS_CC)) {
1306 0 : return NULL;
1307 : }
1308 :
1309 1580 : if ((php_check_safe_mode_include_dir(filename TSRMLS_CC)) == 0)
1310 : /* filename is in safe_mode_include_dir (or subdir) */
1311 1580 : return php_stream_fopen_rel(filename, mode, opened_path, options);
1312 :
1313 0 : if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM)))
1314 0 : return NULL;
1315 :
1316 0 : return php_stream_fopen_rel(filename, mode, opened_path, options);
1317 : }
1318 :
1319 : #ifdef PHP_WIN32
1320 : if (IS_SLASH(filename[0])) {
1321 : size_t cwd_len;
1322 : char *cwd;
1323 : cwd = virtual_getcwd_ex(&cwd_len TSRMLS_CC);
1324 : /* getcwd() will return always return [DRIVE_LETTER]:/) on windows. */
1325 : *(cwd+3) = '\0';
1326 :
1327 : if (snprintf(trypath, MAXPATHLEN, "%s%s", cwd, filename) >= MAXPATHLEN) {
1328 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s/%s path was truncated to %d", cwd, filename, MAXPATHLEN);
1329 : }
1330 :
1331 : free(cwd);
1332 :
1333 : if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(trypath TSRMLS_CC)) {
1334 : return NULL;
1335 : }
1336 : if ((php_check_safe_mode_include_dir(trypath TSRMLS_CC)) == 0) {
1337 : return php_stream_fopen_rel(trypath, mode, opened_path, options);
1338 : }
1339 : if (PG(safe_mode) && (!php_checkuid(trypath, mode, CHECKUID_CHECK_MODE_PARAM))) {
1340 : return NULL;
1341 : }
1342 :
1343 : return php_stream_fopen_rel(trypath, mode, opened_path, options);
1344 : }
1345 : #endif
1346 :
1347 2730 : if (!path || (path && !*path)) {
1348 0 : if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) {
1349 0 : return NULL;
1350 : }
1351 0 : return php_stream_fopen_rel(filename, mode, opened_path, options);
1352 : }
1353 :
1354 : /* check in provided path */
1355 : /* append the calling scripts' current working directory
1356 : * as a fall back case
1357 : */
1358 2730 : if (zend_is_executing(TSRMLS_C)) {
1359 2729 : exec_fname = zend_get_executed_filename(TSRMLS_C);
1360 2729 : exec_fname_length = strlen(exec_fname);
1361 2729 : path_length = strlen(path);
1362 :
1363 58085 : while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
1364 2729 : if ((exec_fname && exec_fname[0] == '[')
1365 : || exec_fname_length<=0) {
1366 : /* [no active file] or no path */
1367 0 : pathbuf = estrdup(path);
1368 : } else {
1369 2729 : pathbuf = (char *) emalloc(exec_fname_length + path_length +1 +1);
1370 2729 : memcpy(pathbuf, path, path_length);
1371 2729 : pathbuf[path_length] = DEFAULT_DIR_SEPARATOR;
1372 2729 : memcpy(pathbuf+path_length+1, exec_fname, exec_fname_length);
1373 2729 : pathbuf[path_length + exec_fname_length +1] = '\0';
1374 : }
1375 : } else {
1376 1 : pathbuf = estrdup(path);
1377 : }
1378 :
1379 2730 : ptr = pathbuf;
1380 :
1381 10835 : while (ptr && *ptr) {
1382 8061 : end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
1383 8061 : if (end != NULL) {
1384 5411 : *end = '\0';
1385 5411 : end++;
1386 : }
1387 8061 : if (*ptr == '\0') {
1388 22 : goto stream_skip;
1389 : }
1390 8039 : if (snprintf(trypath, MAXPATHLEN, "%s/%s", ptr, filename) >= MAXPATHLEN) {
1391 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s/%s path was truncated to %d", ptr, filename, MAXPATHLEN);
1392 : }
1393 :
1394 8039 : if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir_ex(trypath, 0 TSRMLS_CC)) {
1395 48 : goto stream_skip;
1396 : }
1397 :
1398 7991 : if (PG(safe_mode)) {
1399 0 : if (VCWD_STAT(trypath, &sb) == 0) {
1400 : /* file exists ... check permission */
1401 0 : if ((php_check_safe_mode_include_dir(trypath TSRMLS_CC) == 0) ||
1402 : php_checkuid_ex(trypath, mode, CHECKUID_CHECK_MODE_PARAM, CHECKUID_NO_ERRORS)) {
1403 : /* UID ok, or trypath is in safe_mode_include_dir */
1404 0 : stream = php_stream_fopen_rel(trypath, mode, opened_path, options);
1405 0 : goto stream_done;
1406 : }
1407 : }
1408 0 : goto stream_skip;
1409 : }
1410 7991 : stream = php_stream_fopen_rel(trypath, mode, opened_path, options);
1411 7991 : if (stream) {
1412 2686 : stream_done:
1413 2686 : efree(pathbuf);
1414 2686 : return stream;
1415 : }
1416 5375 : stream_skip:
1417 5375 : ptr = end;
1418 : } /* end provided path */
1419 :
1420 44 : efree(pathbuf);
1421 44 : return NULL;
1422 :
1423 : }
1424 : /* }}} */
1425 :
1426 : /*
1427 : * Local variables:
1428 : * tab-width: 4
1429 : * c-basic-offset: 4
1430 : * End:
1431 : * vim600: noet sw=4 ts=4 fdm=marker
1432 : * vim<600: noet sw=4 ts=4
1433 : */
|