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