php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
plain_wrapper.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Wez Furlong <wez@thebrainroom.com> |
14 +----------------------------------------------------------------------+
15 */
16
17#include "php.h"
18#include "php_globals.h"
19#include "php_network.h"
21#include "ext/standard/file.h"
24#include <stddef.h>
25#include <fcntl.h>
26#ifdef HAVE_SYS_WAIT_H
27#include <sys/wait.h>
28#endif
29#ifdef HAVE_SYS_FILE_H
30#include <sys/file.h>
31#endif
32#ifdef HAVE_SYS_MMAN_H
33#include <sys/mman.h>
34#endif
35#include "SAPI.h"
36
37#include "php_streams_int.h"
38#ifdef PHP_WIN32
39# include "win32/winutil.h"
40# include "win32/time.h"
41# include "win32/ioutil.h"
42# include "win32/readdir.h"
43# include <limits.h>
44#endif
45
46#define php_stream_fopen_from_fd_int(fd, mode, persistent_id) _php_stream_fopen_from_fd_int((fd), (mode), (persistent_id) STREAMS_CC)
47#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)
48#define php_stream_fopen_from_file_int(file, mode) _php_stream_fopen_from_file_int((file), (mode) STREAMS_CC)
49#define php_stream_fopen_from_file_int_rel(file, mode) _php_stream_fopen_from_file_int((file), (mode) STREAMS_REL_CC)
50
51#ifndef PHP_WIN32
52extern int php_get_uid_by_name(const char *name, uid_t *uid);
53extern int php_get_gid_by_name(const char *name, gid_t *gid);
54#endif
55
56#if defined(PHP_WIN32)
57# define PLAIN_WRAP_BUF_SIZE(st) ((unsigned int)(st > INT_MAX ? INT_MAX : st))
58#define fsync _commit
59#define fdatasync fsync
60#else
61# define PLAIN_WRAP_BUF_SIZE(st) (st)
62# if !defined(HAVE_FDATASYNC)
63# define fdatasync fsync
64# elif defined(__APPLE__)
65 // The symbol is present, however not in the headers
66 extern int fdatasync(int);
67# endif
68#endif
69
70/* parse standard "fopen" modes into open() flags */
71PHPAPI int php_stream_parse_fopen_modes(const char *mode, int *open_flags)
72{
73 int flags;
74
75 switch (mode[0]) {
76 case 'r':
77 flags = 0;
78 break;
79 case 'w':
80 flags = O_TRUNC|O_CREAT;
81 break;
82 case 'a':
83 flags = O_CREAT|O_APPEND;
84 break;
85 case 'x':
86 flags = O_CREAT|O_EXCL;
87 break;
88 case 'c':
89 flags = O_CREAT;
90 break;
91 default:
92 /* unknown mode */
93 return FAILURE;
94 }
95
96 if (strchr(mode, '+')) {
97 flags |= O_RDWR;
98 } else if (flags) {
99 flags |= O_WRONLY;
100 } else {
101 flags |= O_RDONLY;
102 }
103
104#if defined(O_CLOEXEC)
105 if (strchr(mode, 'e')) {
106 flags |= O_CLOEXEC;
107 }
108#endif
109
110#if defined(O_NONBLOCK)
111 if (strchr(mode, 'n')) {
112 flags |= O_NONBLOCK;
113 }
114#endif
115
116#if defined(_O_TEXT) && defined(O_BINARY)
117 if (strchr(mode, 't')) {
118 flags |= _O_TEXT;
119 } else {
120 flags |= O_BINARY;
121 }
122#endif
123
124 *open_flags = flags;
125 return SUCCESS;
126}
127
128
129/* {{{ ------- STDIO stream implementation -------*/
130
131typedef struct {
132 FILE *file;
133 int fd; /* underlying file descriptor */
134 unsigned is_process_pipe:1; /* use pclose instead of fclose */
135 unsigned is_pipe:1; /* stream is an actual pipe, currently Windows only*/
136 unsigned cached_fstat:1; /* sb is valid */
137 unsigned is_pipe_blocking:1; /* allow blocking read() on pipes, currently Windows only */
138 unsigned no_forced_fstat:1; /* Use fstat cache even if forced */
139 unsigned is_seekable:1; /* don't try and seek, if not set */
140 unsigned _reserved:26;
141
142 int lock_flag; /* stores the lock state */
143 zend_string *temp_name; /* if non-null, this is the path to a temporary file that
144 * is to be deleted when the stream is closed */
145#ifdef HAVE_FLUSHIO
146 char last_op;
147#endif
148
149#ifdef HAVE_MMAP
150 char *last_mapped_addr;
151 size_t last_mapped_len;
152#endif
153#ifdef PHP_WIN32
154 char *last_mapped_addr;
155 HANDLE file_mapping;
156#endif
157
160#define PHP_STDIOP_GET_FD(anfd, data) anfd = (data)->file ? fileno((data)->file) : (data)->fd
161
162static int do_fstat(php_stdio_stream_data *d, int force)
163{
164 if (!d->cached_fstat || (force && !d->no_forced_fstat)) {
165 int fd;
166 int r;
167
169 r = zend_fstat(fd, &d->sb);
170 d->cached_fstat = r == 0;
171
172 return r;
173 }
174 return 0;
175}
176
177static php_stream *_php_stream_fopen_from_fd_int(int fd, const char *mode, const char *persistent_id STREAMS_DC)
178{
180
181 self = pemalloc_rel_orig(sizeof(*self), persistent_id);
182 memset(self, 0, sizeof(*self));
183 self->file = NULL;
184 self->is_seekable = 1;
185 self->is_pipe = 0;
186 self->lock_flag = LOCK_UN;
187 self->is_process_pipe = 0;
188 self->temp_name = NULL;
189 self->fd = fd;
190#ifdef PHP_WIN32
191 self->is_pipe_blocking = 0;
192#endif
193
194 return php_stream_alloc_rel(&php_stream_stdio_ops, self, persistent_id, mode);
195}
196
197static php_stream *_php_stream_fopen_from_file_int(FILE *file, const char *mode STREAMS_DC)
198{
200
201 self = emalloc_rel_orig(sizeof(*self));
202 memset(self, 0, sizeof(*self));
203 self->file = file;
204 self->is_seekable = 1;
205 self->is_pipe = 0;
206 self->lock_flag = LOCK_UN;
207 self->is_process_pipe = 0;
208 self->temp_name = NULL;
209 self->fd = fileno(file);
210#ifdef PHP_WIN32
211 self->is_pipe_blocking = 0;
212#endif
213
215}
216
217PHPAPI php_stream *_php_stream_fopen_temporary_file(const char *dir, const char *pfx, zend_string **opened_path_ptr STREAMS_DC)
218{
219 zend_string *opened_path = NULL;
220 int fd;
221
222 fd = php_open_temporary_fd(dir, pfx, &opened_path);
223 if (fd != -1) {
224 php_stream *stream;
225
226 if (opened_path_ptr) {
227 *opened_path_ptr = opened_path;
228 }
229
230 stream = php_stream_fopen_from_fd_int_rel(fd, "r+b", NULL);
231 if (stream) {
234 stream->orig_path = estrndup(ZSTR_VAL(opened_path), ZSTR_LEN(opened_path));
235
236 self->temp_name = opened_path;
237 self->lock_flag = LOCK_UN;
238
239 return stream;
240 }
241 close(fd);
242
243 php_error_docref(NULL, E_WARNING, "Unable to allocate stream");
244
245 return NULL;
246 }
247 return NULL;
248}
249
254
255static void detect_is_seekable(php_stdio_stream_data *self) {
256#if defined(S_ISFIFO) && defined(S_ISCHR)
257 if (self->fd >= 0 && do_fstat(self, 0) == 0) {
258 self->is_seekable = !(S_ISFIFO(self->sb.st_mode) || S_ISCHR(self->sb.st_mode));
259 self->is_pipe = S_ISFIFO(self->sb.st_mode);
260 }
261#elif defined(PHP_WIN32)
262 uintptr_t handle = _get_osfhandle(self->fd);
263
264 if (handle != (uintptr_t)INVALID_HANDLE_VALUE) {
265 DWORD file_type = GetFileType((HANDLE)handle);
266
267 self->is_seekable = !(file_type == FILE_TYPE_PIPE || file_type == FILE_TYPE_CHAR);
268 self->is_pipe = file_type == FILE_TYPE_PIPE;
269
270 /* Additional check needed to distinguish between pipes and sockets. */
271 if (self->is_pipe && !GetNamedPipeInfo((HANDLE) handle, NULL, NULL, NULL, NULL)) {
272 self->is_pipe = 0;
273 }
274 }
275#endif
276}
277
278PHPAPI php_stream *_php_stream_fopen_from_fd(int fd, const char *mode, const char *persistent_id, bool zero_position STREAMS_DC)
279{
280 php_stream *stream = php_stream_fopen_from_fd_int_rel(fd, mode, persistent_id);
281
282 if (stream) {
284
285 detect_is_seekable(self);
286 if (!self->is_seekable) {
288 stream->position = -1;
289 } else if (zero_position) {
290 ZEND_ASSERT(zend_lseek(self->fd, 0, SEEK_CUR) == 0);
291 stream->position = 0;
292 } else {
293 stream->position = zend_lseek(self->fd, 0, SEEK_CUR);
294#ifdef ESPIPE
295 /* FIXME: Is this code still needed? */
296 if (stream->position == (zend_off_t)-1 && errno == ESPIPE) {
298 self->is_seekable = 0;
299 }
300#endif
301 }
302 }
303
304 return stream;
305}
306
308{
310
311 if (stream) {
313
314 detect_is_seekable(self);
315 if (!self->is_seekable) {
317 stream->position = -1;
318 } else {
319 stream->position = zend_ftell(file);
320 }
321 }
322
323 return stream;
324}
325
327{
329 php_stream *stream;
330
331 self = emalloc_rel_orig(sizeof(*self));
332 memset(self, 0, sizeof(*self));
333 self->file = file;
334 self->is_seekable = 0;
335 self->is_pipe = 1;
336 self->lock_flag = LOCK_UN;
337 self->is_process_pipe = 1;
338 self->fd = fileno(file);
339 self->temp_name = NULL;
340#ifdef PHP_WIN32
341 self->is_pipe_blocking = 0;
342#endif
343
346 return stream;
347}
348
349static ssize_t php_stdiop_write(php_stream *stream, const char *buf, size_t count)
350{
352 ssize_t bytes_written;
353
354 assert(data != NULL);
355
356 if (data->fd >= 0) {
357#ifdef PHP_WIN32
358 bytes_written = _write(data->fd, buf, PLAIN_WRAP_BUF_SIZE(count));
359#else
360 bytes_written = write(data->fd, buf, count);
361#endif
362 if (bytes_written < 0) {
364 return 0;
365 }
366 if (errno == EINTR) {
367 /* TODO: Should this be treated as a proper error or not? */
368 return bytes_written;
369 }
370 if (!(stream->flags & PHP_STREAM_FLAG_SUPPRESS_ERRORS)) {
371 php_error_docref(NULL, E_NOTICE, "Write of %zu bytes failed with errno=%d %s", count, errno, strerror(errno));
372 }
373 }
374 } else {
375
376#ifdef HAVE_FLUSHIO
377 if (data->is_seekable && data->last_op == 'r') {
378 zend_fseek(data->file, 0, SEEK_CUR);
379 }
380 data->last_op = 'w';
381#endif
382
383 bytes_written = (ssize_t) fwrite(buf, 1, count, data->file);
384 }
385
386 if (EG(active)) {
387 /* clear stat cache as mtime and ctime got changed */
389 }
390
391 return bytes_written;
392}
393
394static ssize_t php_stdiop_read(php_stream *stream, char *buf, size_t count)
395{
397 ssize_t ret;
398
399 assert(data != NULL);
400
401 if (data->fd >= 0) {
402#ifdef PHP_WIN32
403 php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
404
405 if ((self->is_pipe || self->is_process_pipe) && !self->is_pipe_blocking) {
406 HANDLE ph = (HANDLE)_get_osfhandle(data->fd);
407 int retry = 0;
408 DWORD avail_read = 0;
409
410 do {
411 /* Look ahead to get the available data amount to read. Do the same
412 as read() does, however not blocking forever. In case it failed,
413 no data will be read (better than block). */
414 if (!PeekNamedPipe(ph, NULL, 0, NULL, &avail_read, NULL)) {
415 break;
416 }
417 /* If there's nothing to read, wait in 10us periods. */
418 if (0 == avail_read) {
419 usleep(10);
420 }
421 } while (0 == avail_read && retry++ < 3200000);
422
423 /* Reduce the required data amount to what is available, otherwise read()
424 will block.*/
425 if (avail_read < count) {
426 count = avail_read;
427 }
428 }
429#endif
430 ret = read(data->fd, buf, PLAIN_WRAP_BUF_SIZE(count));
431
432 if (ret == (size_t)-1 && errno == EINTR) {
433 /* Read was interrupted, retry once,
434 If read still fails, give up with feof==0
435 so script can retry if desired */
436 ret = read(data->fd, buf, PLAIN_WRAP_BUF_SIZE(count));
437 }
438
439 if (ret < 0) {
441 /* Not an error. */
442 ret = 0;
443 } else if (errno == EINTR) {
444 /* TODO: Should this be treated as a proper error or not? */
445 } else {
446 if (!(stream->flags & PHP_STREAM_FLAG_SUPPRESS_ERRORS)) {
447 php_error_docref(NULL, E_NOTICE, "Read of %zu bytes failed with errno=%d %s", count, errno, strerror(errno));
448 }
449
450 /* TODO: Remove this special-case? */
451 if (errno != EBADF) {
452 stream->eof = 1;
453 }
454 }
455 } else if (ret == 0) {
456 stream->eof = 1;
457 }
458
459 } else {
460#ifdef HAVE_FLUSHIO
461 if (data->is_seekable && data->last_op == 'w')
462 zend_fseek(data->file, 0, SEEK_CUR);
463 data->last_op = 'r';
464#endif
465
466 ret = fread(buf, 1, count, data->file);
467
468 stream->eof = feof(data->file);
469 }
470
471 if (EG(active)) {
472 /* clear stat cache as atime got changed */
474 }
475
476 return ret;
477}
478
479static int php_stdiop_close(php_stream *stream, int close_handle)
480{
481 int ret;
483
484 assert(data != NULL);
485
486#ifdef HAVE_MMAP
487 if (data->last_mapped_addr) {
488 munmap(data->last_mapped_addr, data->last_mapped_len);
489 data->last_mapped_addr = NULL;
490 }
491#elif defined(PHP_WIN32)
492 if (data->last_mapped_addr) {
493 UnmapViewOfFile(data->last_mapped_addr);
494 data->last_mapped_addr = NULL;
495 }
496 if (data->file_mapping) {
497 CloseHandle(data->file_mapping);
498 data->file_mapping = NULL;
499 }
500#endif
501
502 if (close_handle) {
503 if (data->file) {
504 if (data->is_process_pipe) {
505 errno = 0;
506 ret = pclose(data->file);
507
508#ifdef HAVE_SYS_WAIT_H
509 if (WIFEXITED(ret)) {
510 ret = WEXITSTATUS(ret);
511 }
512#endif
513 } else {
514 ret = fclose(data->file);
515 data->file = NULL;
516 }
517 } else if (data->fd != -1) {
518 ret = close(data->fd);
519 data->fd = -1;
520 } else {
521 return 0; /* everything should be closed already -> success */
522 }
523 if (data->temp_name) {
524#ifdef PHP_WIN32
525 php_win32_ioutil_unlink(ZSTR_VAL(data->temp_name));
526#else
527 unlink(ZSTR_VAL(data->temp_name));
528#endif
529 /* temporary streams are never persistent */
530 zend_string_release_ex(data->temp_name, 0);
531 data->temp_name = NULL;
532 }
533 } else {
534 ret = 0;
535 data->file = NULL;
536 data->fd = -1;
537 }
538
539 pefree(data, stream->is_persistent);
540
541 return ret;
542}
543
544static int php_stdiop_flush(php_stream *stream)
545{
547
548 assert(data != NULL);
549
550 /*
551 * stdio buffers data in user land. By calling fflush(3), this
552 * data is sent to the kernel using write(2). fsync'ing is
553 * something completely different.
554 */
555 if (data->file) {
556 if (EG(active)) {
557 /* clear stat cache as there might be a write so mtime and ctime might have changed */
559 }
560 return fflush(data->file);
561 }
562 return 0;
563}
564
565
566static int php_stdiop_sync(php_stream *stream, bool dataonly)
567{
569 FILE *fp;
570 int fd;
571
572 if (php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&fp, REPORT_ERRORS) == FAILURE) {
573 return -1;
574 }
575
576 if (php_stdiop_flush(stream) == 0) {
578 if (dataonly) {
579 return fdatasync(fd);
580 } else {
581 return fsync(fd);
582 }
583 }
584 return -1;
585}
586
587static int php_stdiop_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset)
588{
590 int ret;
591
592 assert(data != NULL);
593
594 if (!data->is_seekable) {
595 php_error_docref(NULL, E_WARNING, "Cannot seek on this stream");
596 return -1;
597 }
598
599 if (data->fd >= 0) {
601
602 result = zend_lseek(data->fd, offset, whence);
603 if (result == (zend_off_t)-1)
604 return -1;
605
606 *newoffset = result;
607 return 0;
608
609 } else {
610 ret = zend_fseek(data->file, offset, whence);
611 *newoffset = zend_ftell(data->file);
612 return ret;
613 }
614}
615
616static int php_stdiop_cast(php_stream *stream, int castas, void **ret)
617{
620
621 assert(data != NULL);
622
623 /* as soon as someone touches the stdio layer, buffering may ensue,
624 * so we need to stop using the fd directly in that case */
625
626 switch (castas) {
628 if (ret) {
629
630 if (data->file == NULL) {
631 /* we were opened as a plain file descriptor, so we
632 * need fdopen now */
633 char fixed_mode[5];
635 data->file = fdopen(data->fd, fixed_mode);
636 if (data->file == NULL) {
637 return FAILURE;
638 }
639 }
640
641 *(FILE**)ret = data->file;
642 data->fd = SOCK_ERR;
643 }
644 return SUCCESS;
645
648 if (SOCK_ERR == fd) {
649 return FAILURE;
650 }
651 if (ret) {
652 *(php_socket_t *)ret = fd;
653 }
654 return SUCCESS;
655
656 case PHP_STREAM_AS_FD:
658
659 if (SOCK_ERR == fd) {
660 return FAILURE;
661 }
662 if (data->file) {
663 fflush(data->file);
664 }
665 if (ret) {
666 *(php_socket_t *)ret = fd;
667 }
668 return SUCCESS;
669 default:
670 return FAILURE;
671 }
672}
673
674static int php_stdiop_stat(php_stream *stream, php_stream_statbuf *ssb)
675{
676 int ret;
678
679 assert(data != NULL);
680 if((ret = do_fstat(data, 1)) == 0) {
681 memcpy(&ssb->sb, &data->sb, sizeof(ssb->sb));
682 }
683
684 return ret;
685}
686
687static int php_stdiop_set_option(php_stream *stream, int option, int value, void *ptrparam)
688{
690 size_t size;
691 int fd;
692#ifdef O_NONBLOCK
693 /* FIXME: make this work for win32 */
694 int flags;
695 int oldval;
696#endif
697
699
700 switch(option) {
702 if (fd == -1)
703 return -1;
704#ifdef O_NONBLOCK
705 flags = fcntl(fd, F_GETFL, 0);
706 oldval = (flags & O_NONBLOCK) ? 0 : 1;
707 if (value)
709 else
710 flags |= O_NONBLOCK;
711
712 if (-1 == fcntl(fd, F_SETFL, flags))
713 return -1;
714 return oldval;
715#else
716 return -1; /* not yet implemented */
717#endif
718
720
721 if (data->file == NULL) {
722 return -1;
723 }
724
725 if (ptrparam)
726 size = *(size_t *)ptrparam;
727 else
728 size = BUFSIZ;
729
730 switch(value) {
732 return setvbuf(data->file, NULL, _IONBF, 0);
733
735 return setvbuf(data->file, NULL, _IOLBF, size);
736
738 return setvbuf(data->file, NULL, _IOFBF, size);
739
740 default:
741 return -1;
742 }
743 break;
744
746 if (fd == -1) {
747 return -1;
748 }
749
750 if ((uintptr_t) ptrparam == PHP_STREAM_LOCK_SUPPORTED) {
751 return 0;
752 }
753
754 if (!flock(fd, value)) {
755 data->lock_flag = value;
756 return 0;
757 } else {
758 return -1;
759 }
760 break;
761
763#ifdef HAVE_MMAP
764 {
766 int prot, flags;
767
768 switch (value) {
771
773 if (do_fstat(data, 1) != 0) {
775 }
776 if (range->offset > data->sb.st_size) {
777 range->offset = data->sb.st_size;
778 }
779 if (range->length == 0 ||
780 range->length > data->sb.st_size - range->offset) {
781 range->length = data->sb.st_size - range->offset;
782 }
783 switch (range->mode) {
785 prot = PROT_READ;
786 flags = MAP_PRIVATE;
787 break;
789 prot = PROT_READ | PROT_WRITE;
790 flags = MAP_PRIVATE;
791 break;
793 prot = PROT_READ;
794 flags = MAP_SHARED;
795 break;
797 prot = PROT_READ | PROT_WRITE;
798 flags = MAP_SHARED;
799 break;
800 default:
802 }
803 range->mapped = (char*)mmap(NULL, range->length, prot, flags, fd, range->offset);
804 if (range->mapped == (char*)MAP_FAILED) {
805 range->mapped = NULL;
807 }
808 /* remember the mapping */
809 data->last_mapped_addr = range->mapped;
810 data->last_mapped_len = range->length;
812
814 if (data->last_mapped_addr) {
815 munmap(data->last_mapped_addr, data->last_mapped_len);
816 data->last_mapped_addr = NULL;
817
819 }
821 }
822 }
823#elif defined(PHP_WIN32)
824 {
826 HANDLE hfile = (HANDLE)_get_osfhandle(fd);
827 DWORD prot, acc, loffs = 0, hoffs = 0, delta = 0;
828 LARGE_INTEGER file_size;
829
830 switch (value) {
832 return hfile == INVALID_HANDLE_VALUE ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK;
833
835 switch (range->mode) {
837 prot = PAGE_READONLY;
838 acc = FILE_MAP_READ;
839 break;
841 prot = PAGE_READWRITE;
842 acc = FILE_MAP_READ | FILE_MAP_WRITE;
843 break;
845 prot = PAGE_READONLY;
846 acc = FILE_MAP_READ;
847 /* TODO: we should assign a name for the mapping */
848 break;
850 prot = PAGE_READWRITE;
851 acc = FILE_MAP_READ | FILE_MAP_WRITE;
852 /* TODO: we should assign a name for the mapping */
853 break;
854 default:
856 }
857
858 /* create a mapping capable of viewing the whole file (this costs no real resources) */
859 data->file_mapping = CreateFileMapping(hfile, NULL, prot, 0, 0, NULL);
860
861 if (data->file_mapping == NULL) {
863 }
864
865 if (!GetFileSizeEx(hfile, &file_size)) {
866 CloseHandle(data->file_mapping);
867 data->file_mapping = NULL;
869 }
870# if defined(_WIN64)
871 size = file_size.QuadPart;
872# else
873 if (file_size.HighPart) {
874 CloseHandle(data->file_mapping);
875 data->file_mapping = NULL;
877 } else {
878 size = file_size.LowPart;
879 }
880# endif
881 if (range->offset > size) {
882 range->offset = size;
883 }
884 if (range->length == 0 || range->length > size - range->offset) {
885 range->length = size - range->offset;
886 }
887
888 /* figure out how big a chunk to map to be able to view the part that we need */
889 if (range->offset != 0) {
890 SYSTEM_INFO info;
891 DWORD gran;
892
893 GetSystemInfo(&info);
894 gran = info.dwAllocationGranularity;
895 ZEND_ASSERT(gran != 0 && (gran & (gran - 1)) == 0);
896 size_t rounded_offset = (range->offset / gran) * gran;
897 delta = range->offset - rounded_offset;
898 loffs = (DWORD)rounded_offset;
899#ifdef _WIN64
900 hoffs = (DWORD)(rounded_offset >> 32);
901#else
902 hoffs = 0;
903#endif
904 }
905
906 /* MapViewOfFile()ing zero bytes would map to the end of the file; match *nix behavior instead */
907 if (range->length + delta == 0) {
909 }
910
911 data->last_mapped_addr = MapViewOfFile(data->file_mapping, acc, hoffs, loffs, range->length + delta);
912
913 if (data->last_mapped_addr) {
914 /* give them back the address of the start offset they requested */
915 range->mapped = data->last_mapped_addr + delta;
917 }
918
919 CloseHandle(data->file_mapping);
920 data->file_mapping = NULL;
921
923
925 if (data->last_mapped_addr) {
926 UnmapViewOfFile(data->last_mapped_addr);
927 data->last_mapped_addr = NULL;
928 CloseHandle(data->file_mapping);
929 data->file_mapping = NULL;
931 }
933
934 default:
936 }
937 }
938
939#endif
941
943 switch (value) {
947 return php_stdiop_sync(stream, 0) == 0 ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR;
949 return php_stdiop_sync(stream, 1) == 0 ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR;
950 }
951 /* Invalid option passed */
953
955 switch (value) {
958
960 ptrdiff_t new_size = *(ptrdiff_t*)ptrparam;
961 if (new_size < 0) {
963 }
964#ifdef PHP_WIN32
965 HANDLE h = (HANDLE) _get_osfhandle(fd);
966 if (INVALID_HANDLE_VALUE == h) {
968 }
969
970 LARGE_INTEGER sz, old_sz;
971 sz.QuadPart = 0;
972
973 if (!SetFilePointerEx(h, sz, &old_sz, FILE_CURRENT)) {
975 }
976
977#ifdef _WIN64
978 sz.QuadPart = new_size;
979#else
980 sz.HighPart = 0;
981 sz.LowPart = new_size;
982#endif
983 if (!SetFilePointerEx(h, sz, NULL, FILE_BEGIN)) {
985 }
986 if (0 == SetEndOfFile(h)) {
988 }
989 if (!SetFilePointerEx(h, old_sz, NULL, FILE_BEGIN)) {
991 }
993#else
995#endif
996 }
997 }
999
1000#ifdef PHP_WIN32
1002 data->is_pipe_blocking = value;
1004#endif
1006 if (fd == -1)
1007 return -1;
1008#ifdef O_NONBLOCK
1009 flags = fcntl(fd, F_GETFL, 0);
1010
1011 add_assoc_bool((zval*)ptrparam, "timed_out", 0);
1012 add_assoc_bool((zval*)ptrparam, "blocked", (flags & O_NONBLOCK)? 0 : 1);
1013 add_assoc_bool((zval*)ptrparam, "eof", stream->eof);
1014
1016#endif
1017 return -1;
1018 default:
1020 }
1021}
1022
1023/* This should be "const", but phpdbg overwrite it */
1025 php_stdiop_write, php_stdiop_read,
1026 php_stdiop_close, php_stdiop_flush,
1027 "STDIO",
1028 php_stdiop_seek,
1029 php_stdiop_cast,
1030 php_stdiop_stat,
1031 php_stdiop_set_option
1032};
1033/* }}} */
1034
1035/* {{{ plain files opendir/readdir implementation */
1036static ssize_t php_plain_files_dirstream_read(php_stream *stream, char *buf, size_t count)
1037{
1038 DIR *dir = (DIR*)stream->abstract;
1039 struct dirent *result;
1041
1042 /* avoid problems if someone mis-uses the stream */
1043 if (count != sizeof(php_stream_dirent))
1044 return -1;
1045
1046 result = readdir(dir);
1047 if (result) {
1048 PHP_STRLCPY(ent->d_name, result->d_name, sizeof(ent->d_name), strlen(result->d_name));
1049#ifdef _DIRENT_HAVE_D_TYPE
1050 ent->d_type = result->d_type;
1051#else
1052 ent->d_type = DT_UNKNOWN;
1053#endif
1054 return sizeof(php_stream_dirent);
1055 }
1056 return 0;
1057}
1058
1059static int php_plain_files_dirstream_close(php_stream *stream, int close_handle)
1060{
1061 return closedir((DIR *)stream->abstract);
1062}
1063
1064static int php_plain_files_dirstream_rewind(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffs)
1065{
1066 rewinddir((DIR *)stream->abstract);
1067 return 0;
1068}
1069
1070static const php_stream_ops php_plain_files_dirstream_ops = {
1071 NULL, php_plain_files_dirstream_read,
1072 php_plain_files_dirstream_close, NULL,
1073 "dir",
1074 php_plain_files_dirstream_rewind,
1075 NULL, /* cast */
1076 NULL, /* stat */
1077 NULL /* set_option */
1078};
1079
1080static php_stream *php_plain_files_dir_opener(php_stream_wrapper *wrapper, const char *path, const char *mode,
1082{
1083 DIR *dir = NULL;
1084 php_stream *stream = NULL;
1085
1086#ifdef HAVE_GLOB
1089 }
1090#endif
1091
1093 return NULL;
1094 }
1095
1096 dir = VCWD_OPENDIR(path);
1097
1098#ifdef PHP_WIN32
1099 if (!dir) {
1100 php_win32_docref1_from_error(GetLastError(), path);
1101 }
1102
1103 if (dir && dir->finished) {
1104 closedir(dir);
1105 dir = NULL;
1106 }
1107#endif
1108 if (dir) {
1109 stream = php_stream_alloc(&php_plain_files_dirstream_ops, dir, 0, mode);
1110 if (stream == NULL)
1111 closedir(dir);
1112 }
1113
1114 return stream;
1115}
1116/* }}} */
1117
1118/* {{{ php_stream_fopen */
1119PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, zend_string **opened_path, int options STREAMS_DC)
1120{
1121 char realpath[MAXPATHLEN];
1122 int open_flags;
1123 int fd;
1124 php_stream *ret;
1126 char *persistent_id = NULL;
1127
1128 if (FAILURE == php_stream_parse_fopen_modes(mode, &open_flags)) {
1129 php_stream_wrapper_log_error(&php_plain_files_wrapper, options, "`%s' is not a valid mode for fopen", mode);
1130 return NULL;
1131 }
1132
1134 strlcpy(realpath, filename, sizeof(realpath));
1135 } else {
1136 if (expand_filepath(filename, realpath) == NULL) {
1137 return NULL;
1138 }
1139 }
1140
1141 if (persistent) {
1142 spprintf(&persistent_id, 0, "streams_stdio_%d_%s", open_flags, realpath);
1143 switch (php_stream_from_persistent_id(persistent_id, &ret)) {
1145 if (opened_path) {
1146 //TODO: avoid reallocation???
1147 *opened_path = zend_string_init(realpath, strlen(realpath), 0);
1148 }
1150
1152 efree(persistent_id);
1153 return ret;
1154 }
1155 }
1156#ifdef PHP_WIN32
1157 fd = php_win32_ioutil_open(realpath, open_flags, 0666);
1158#else
1159 fd = open(realpath, open_flags, 0666);
1160#endif
1161 if (fd != -1) {
1162
1164 ret = php_stream_fopen_from_fd_int_rel(fd, mode, persistent_id);
1165 } else {
1166 /* skip the lseek(SEEK_CUR) system call to
1167 * determine the current offset because we
1168 * know newly opened files are at offset zero
1169 * (unless the file has been opened in
1170 * O_APPEND mode) */
1171 ret = php_stream_fopen_from_fd_rel(fd, mode, persistent_id, (open_flags & O_APPEND) == 0);
1172 }
1173
1174 if (EG(active)) {
1175 /* clear stat cache as mtime and ctime might got changed - phar can use stream before
1176 * cache is initialized so we need to check if the execution is active. */
1178 }
1179
1180 if (ret) {
1181 if (opened_path) {
1182 *opened_path = zend_string_init(realpath, strlen(realpath), 0);
1183 }
1184 if (persistent_id) {
1185 efree(persistent_id);
1186 }
1187
1188 /* WIN32 always set ISREG flag */
1189#ifndef PHP_WIN32
1190 /* sanity checks for include/require.
1191 * We check these after opening the stream, so that we save
1192 * on fstat() syscalls */
1195 int r;
1196
1197 r = do_fstat(self, 0);
1198 if ((r == 0 && !S_ISREG(self->sb.st_mode))) {
1199 if (opened_path) {
1200 zend_string_release_ex(*opened_path, 0);
1201 *opened_path = NULL;
1202 }
1204 return NULL;
1205 }
1206
1207 /* Make sure the fstat result is reused when we later try to get the
1208 * file size. */
1209 self->no_forced_fstat = 1;
1210 }
1211
1214 self->is_pipe_blocking = 1;
1215 }
1216#endif
1217
1218 return ret;
1219 }
1220 close(fd);
1221 }
1222 if (persistent_id) {
1223 efree(persistent_id);
1224 }
1225 return NULL;
1226}
1227/* }}} */
1228
1229
1230static php_stream *php_plain_files_stream_opener(php_stream_wrapper *wrapper, const char *path, const char *mode,
1232{
1234 return NULL;
1235 }
1236
1237 return php_stream_fopen_rel(path, mode, opened_path, options);
1238}
1239
1240static int php_plain_files_url_stater(php_stream_wrapper *wrapper, const char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context)
1241{
1243 if (strncasecmp(url, "file://", sizeof("file://") - 1) == 0) {
1244 url += sizeof("file://") - 1;
1245 }
1246
1248 return -1;
1249 }
1250 }
1251
1252#ifdef PHP_WIN32
1254 return VCWD_LSTAT(url, &ssb->sb);
1255 }
1256#else
1257# ifdef HAVE_SYMLINK
1259 return VCWD_LSTAT(url, &ssb->sb);
1260 } else
1261# endif
1262#endif
1263 return VCWD_STAT(url, &ssb->sb);
1264}
1265
1266static int php_plain_files_unlink(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context)
1267{
1268 int ret;
1269
1270 if (strncasecmp(url, "file://", sizeof("file://") - 1) == 0) {
1271 url += sizeof("file://") - 1;
1272 }
1273
1274 if (php_check_open_basedir(url)) {
1275 return 0;
1276 }
1277
1278 ret = VCWD_UNLINK(url);
1279 if (ret == -1) {
1280 if (options & REPORT_ERRORS) {
1281 php_error_docref1(NULL, url, E_WARNING, "%s", strerror(errno));
1282 }
1283 return 0;
1284 }
1285
1286 /* Clear stat cache (and realpath cache) */
1288
1289 return 1;
1290}
1291
1292static int php_plain_files_rename(php_stream_wrapper *wrapper, const char *url_from, const char *url_to, int options, php_stream_context *context)
1293{
1294 int ret;
1295
1296 if (!url_from || !url_to) {
1297 return 0;
1298 }
1299
1300#ifdef PHP_WIN32
1301 if (!php_win32_check_trailing_space(url_from, strlen(url_from))) {
1302 php_win32_docref2_from_error(ERROR_INVALID_NAME, url_from, url_to);
1303 return 0;
1304 }
1305 if (!php_win32_check_trailing_space(url_to, strlen(url_to))) {
1306 php_win32_docref2_from_error(ERROR_INVALID_NAME, url_from, url_to);
1307 return 0;
1308 }
1309#endif
1310
1311 if (strncasecmp(url_from, "file://", sizeof("file://") - 1) == 0) {
1312 url_from += sizeof("file://") - 1;
1313 }
1314
1315 if (strncasecmp(url_to, "file://", sizeof("file://") - 1) == 0) {
1316 url_to += sizeof("file://") - 1;
1317 }
1318
1319 if (php_check_open_basedir(url_from) || php_check_open_basedir(url_to)) {
1320 return 0;
1321 }
1322
1323 ret = VCWD_RENAME(url_from, url_to);
1324
1325 if (ret == -1) {
1326#ifndef PHP_WIN32
1327# ifdef EXDEV
1328 if (errno == EXDEV) {
1329 zend_stat_t sb;
1330# if !defined(ZTS) && !defined(TSRM_WIN32)
1331 /* not sure what to do in ZTS case, umask is not thread-safe */
1332 int oldmask = umask(077);
1333# endif
1334 int success = 0;
1335 if (php_copy_file(url_from, url_to) == SUCCESS) {
1336 if (VCWD_STAT(url_from, &sb) == 0) {
1337 success = 1;
1338# ifndef TSRM_WIN32
1339 /*
1340 * Try to set user and permission info on the target.
1341 * If we're not root, then some of these may fail.
1342 * We try chown first, to set proper group info, relying
1343 * on the system environment to have proper umask to not allow
1344 * access to the file in the meantime.
1345 */
1346 if (VCWD_CHOWN(url_to, sb.st_uid, sb.st_gid)) {
1347 php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", strerror(errno));
1348 if (errno != EPERM) {
1349 success = 0;
1350 }
1351 }
1352
1353 if (success) {
1354 if (VCWD_CHMOD(url_to, sb.st_mode)) {
1355 php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", strerror(errno));
1356 if (errno != EPERM) {
1357 success = 0;
1358 }
1359 }
1360 }
1361# endif
1362 if (success) {
1363 VCWD_UNLINK(url_from);
1364 }
1365 } else {
1366 php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", strerror(errno));
1367 }
1368 } else {
1369 php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", strerror(errno));
1370 }
1371# if !defined(ZTS) && !defined(TSRM_WIN32)
1372 umask(oldmask);
1373# endif
1374 return success;
1375 }
1376# endif
1377#endif
1378
1379#ifdef PHP_WIN32
1380 php_win32_docref2_from_error(GetLastError(), url_from, url_to);
1381#else
1382 php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", strerror(errno));
1383#endif
1384 return 0;
1385 }
1386
1387 /* Clear stat cache (and realpath cache) */
1389
1390 return 1;
1391}
1392
1393static int php_plain_files_mkdir(php_stream_wrapper *wrapper, const char *dir, int mode, int options, php_stream_context *context)
1394{
1395 if (strncasecmp(dir, "file://", sizeof("file://") - 1) == 0) {
1396 dir += sizeof("file://") - 1;
1397 }
1398
1401 return 0;
1402 }
1403
1404 int ret = VCWD_MKDIR(dir, (mode_t)mode);
1405 if (ret < 0 && (options & REPORT_ERRORS)) {
1406 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
1407 return 0;
1408 }
1409
1410 return 1;
1411 }
1412
1413 char buf[MAXPATHLEN];
1415 php_error_docref(NULL, E_WARNING, "Invalid path");
1416 return 0;
1417 }
1418
1420 return 0;
1421 }
1422
1423 /* we look for directory separator from the end of string, thus hopefully reducing our work load */
1424 char *p;
1425 zend_stat_t sb;
1426 size_t dir_len = strlen(dir), offset = 0;
1427 char *e = buf + strlen(buf);
1428
1429 if ((p = memchr(buf, DEFAULT_SLASH, dir_len))) {
1430 offset = p - buf + 1;
1431 }
1432
1433 if (p && dir_len == 1) {
1434 /* buf == "DEFAULT_SLASH" */
1435 }
1436 else {
1437 /* find a top level directory we need to create */
1438 while ( (p = strrchr(buf + offset, DEFAULT_SLASH)) || (offset != 1 && (p = strrchr(buf, DEFAULT_SLASH))) ) {
1439 int n = 0;
1440
1441 *p = '\0';
1442 while (p > buf && *(p-1) == DEFAULT_SLASH) {
1443 ++n;
1444 --p;
1445 *p = '\0';
1446 }
1447 if (VCWD_STAT(buf, &sb) == 0) {
1448 while (1) {
1449 *p = DEFAULT_SLASH;
1450 if (!n) break;
1451 --n;
1452 ++p;
1453 }
1454 break;
1455 }
1456 }
1457 }
1458
1459 if (!p) {
1460 p = buf;
1461 }
1462 while (true) {
1463 int ret = VCWD_MKDIR(buf, (mode_t) mode);
1464 if (ret < 0 && errno != EEXIST) {
1465 if (options & REPORT_ERRORS) {
1466 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
1467 }
1468 return 0;
1469 }
1470
1471 bool replaced_slash = false;
1472 while (++p != e) {
1473 if (*p == '\0') {
1474 replaced_slash = true;
1475 *p = DEFAULT_SLASH;
1476 if (*(p+1) != '\0') {
1477 break;
1478 }
1479 }
1480 }
1481 if (p == e || !replaced_slash) {
1482 /* No more directories to create */
1483 /* issue a warning to client when the last directory was created failed */
1484 if (ret < 0) {
1485 if (options & REPORT_ERRORS) {
1486 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
1487 }
1488 return 0;
1489 }
1490 return 1;
1491 }
1492 }
1493}
1494
1495static int php_plain_files_rmdir(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context)
1496{
1497 if (strncasecmp(url, "file://", sizeof("file://") - 1) == 0) {
1498 url += sizeof("file://") - 1;
1499 }
1500
1501 if (php_check_open_basedir(url)) {
1502 return 0;
1503 }
1504
1505#ifdef PHP_WIN32
1506 if (!php_win32_check_trailing_space(url, strlen(url))) {
1507 php_error_docref1(NULL, url, E_WARNING, "%s", strerror(ENOENT));
1508 return 0;
1509 }
1510#endif
1511
1512 if (VCWD_RMDIR(url) < 0) {
1513 php_error_docref1(NULL, url, E_WARNING, "%s", strerror(errno));
1514 return 0;
1515 }
1516
1517 /* Clear stat cache (and realpath cache) */
1519
1520 return 1;
1521}
1522
1523static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url, int option, void *value, php_stream_context *context)
1524{
1525 struct utimbuf *newtime;
1526#ifndef PHP_WIN32
1527 uid_t uid;
1528 gid_t gid;
1529#endif
1530 mode_t mode;
1531 int ret = 0;
1532
1533#ifdef PHP_WIN32
1534 if (!php_win32_check_trailing_space(url, strlen(url))) {
1535 php_error_docref1(NULL, url, E_WARNING, "%s", strerror(ENOENT));
1536 return 0;
1537 }
1538#endif
1539
1540 if (strncasecmp(url, "file://", sizeof("file://") - 1) == 0) {
1541 url += sizeof("file://") - 1;
1542 }
1543
1544 if (php_check_open_basedir(url)) {
1545 return 0;
1546 }
1547
1548 switch(option) {
1550 newtime = (struct utimbuf *)value;
1551 if (VCWD_ACCESS(url, F_OK) != 0) {
1552 FILE *file = VCWD_FOPEN(url, "w");
1553 if (file == NULL) {
1554 php_error_docref1(NULL, url, E_WARNING, "Unable to create file %s because %s", url, strerror(errno));
1555 return 0;
1556 }
1557 fclose(file);
1558 }
1559
1560 ret = VCWD_UTIME(url, newtime);
1561 break;
1562#ifndef PHP_WIN32
1565 if(option == PHP_STREAM_META_OWNER_NAME) {
1566 if(php_get_uid_by_name((char *)value, &uid) != SUCCESS) {
1567 php_error_docref1(NULL, url, E_WARNING, "Unable to find uid for %s", (char *)value);
1568 return 0;
1569 }
1570 } else {
1571 uid = (uid_t)*(long *)value;
1572 }
1573 ret = VCWD_CHOWN(url, uid, -1);
1574 break;
1577 if(option == PHP_STREAM_META_GROUP_NAME) {
1578 if(php_get_gid_by_name((char *)value, &gid) != SUCCESS) {
1579 php_error_docref1(NULL, url, E_WARNING, "Unable to find gid for %s", (char *)value);
1580 return 0;
1581 }
1582 } else {
1583 gid = (gid_t)*(long *)value;
1584 }
1585 ret = VCWD_CHOWN(url, -1, gid);
1586 break;
1587#endif
1589 mode = (mode_t)*(zend_long *)value;
1590 ret = VCWD_CHMOD(url, mode);
1591 break;
1592 default:
1593 zend_value_error("Unknown option %d for stream_metadata", option);
1594 return 0;
1595 }
1596 if (ret == -1) {
1597 php_error_docref1(NULL, url, E_WARNING, "Operation failed: %s", strerror(errno));
1598 return 0;
1599 }
1601 return 1;
1602}
1603
1604
1605static const php_stream_wrapper_ops php_plain_files_wrapper_ops = {
1606 php_plain_files_stream_opener,
1607 NULL,
1608 NULL,
1609 php_plain_files_url_stater,
1610 php_plain_files_dir_opener,
1611 "plainfile",
1612 php_plain_files_unlink,
1613 php_plain_files_rename,
1614 php_plain_files_mkdir,
1615 php_plain_files_rmdir,
1616 php_plain_files_metadata
1617};
1618
1619/* TODO: We have to make php_plain_files_wrapper writable to support SWOOLE */
1621 &php_plain_files_wrapper_ops,
1622 NULL,
1623 0
1624};
1625
1626/* {{{ php_stream_fopen_with_path */
1627PHPAPI php_stream *_php_stream_fopen_with_path(const char *filename, const char *mode, const char *path, zend_string **opened_path, int options STREAMS_DC)
1628{
1629 /* code ripped off from fopen_wrappers.c */
1630 char *pathbuf, *end;
1631 const char *ptr;
1632 char trypath[MAXPATHLEN];
1633 php_stream *stream;
1634 size_t filename_length;
1635 zend_string *exec_filename;
1636
1637 if (opened_path) {
1638 *opened_path = NULL;
1639 }
1640
1641 if(!filename) {
1642 return NULL;
1643 }
1644
1645 filename_length = strlen(filename);
1646#ifndef PHP_WIN32
1647 (void) filename_length;
1648#endif
1649
1650 /* Relative path open */
1651 if (*filename == '.' && (IS_SLASH(filename[1]) || filename[1] == '.')) {
1652 /* further checks, we could have ....... filenames */
1653 ptr = filename + 1;
1654 if (*ptr == '.') {
1655 while (*(++ptr) == '.');
1656 if (!IS_SLASH(*ptr)) { /* not a relative path after all */
1657 goto not_relative_path;
1658 }
1659 }
1660
1661
1662 if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(filename)) {
1663 return NULL;
1664 }
1665
1666 return php_stream_fopen_rel(filename, mode, opened_path, options);
1667 }
1668
1669not_relative_path:
1670
1671 /* Absolute path open */
1672 if (IS_ABSOLUTE_PATH(filename, filename_length)) {
1673
1674 if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(filename)) {
1675 return NULL;
1676 }
1677
1678 return php_stream_fopen_rel(filename, mode, opened_path, options);
1679 }
1680
1681#ifdef PHP_WIN32
1682 if (IS_SLASH(filename[0])) {
1683 size_t cwd_len;
1684 char *cwd;
1686 /* getcwd() will return always return [DRIVE_LETTER]:/) on windows. */
1687 *(cwd+3) = '\0';
1688
1689 if (snprintf(trypath, MAXPATHLEN, "%s%s", cwd, filename) >= MAXPATHLEN) {
1690 php_error_docref(NULL, E_NOTICE, "%s/%s path was truncated to %d", cwd, filename, MAXPATHLEN);
1691 }
1692
1693 efree(cwd);
1694
1695 if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(trypath)) {
1696 return NULL;
1697 }
1698
1699 return php_stream_fopen_rel(trypath, mode, opened_path, options);
1700 }
1701#endif
1702
1703 if (!path || !*path) {
1704 return php_stream_fopen_rel(filename, mode, opened_path, options);
1705 }
1706
1707 /* check in provided path */
1708 /* append the calling scripts' current working directory
1709 * as a fallback case
1710 */
1711 if (zend_is_executing() &&
1712 (exec_filename = zend_get_executed_filename_ex()) != NULL) {
1713 const char *exec_fname = ZSTR_VAL(exec_filename);
1714 size_t exec_fname_length = ZSTR_LEN(exec_filename);
1715
1716 while ((--exec_fname_length < SIZE_MAX) && !IS_SLASH(exec_fname[exec_fname_length]));
1717 if (exec_fname_length<=0) {
1718 /* no path */
1719 pathbuf = estrdup(path);
1720 } else {
1721 size_t path_length = strlen(path);
1722
1723 pathbuf = (char *) emalloc(exec_fname_length + path_length +1 +1);
1724 memcpy(pathbuf, path, path_length);
1725 pathbuf[path_length] = DEFAULT_DIR_SEPARATOR;
1726 memcpy(pathbuf+path_length+1, exec_fname, exec_fname_length);
1727 pathbuf[path_length + exec_fname_length +1] = '\0';
1728 }
1729 } else {
1730 pathbuf = estrdup(path);
1731 }
1732
1733 ptr = pathbuf;
1734
1735 while (ptr && *ptr) {
1737 if (end != NULL) {
1738 *end = '\0';
1739 end++;
1740 }
1741 if (*ptr == '\0') {
1742 goto stream_skip;
1743 }
1744 if (snprintf(trypath, MAXPATHLEN, "%s/%s", ptr, filename) >= MAXPATHLEN) {
1745 php_error_docref(NULL, E_NOTICE, "%s/%s path was truncated to %d", ptr, filename, MAXPATHLEN);
1746 }
1747
1748 if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir_ex(trypath, 0)) {
1749 goto stream_skip;
1750 }
1751
1752 stream = php_stream_fopen_rel(trypath, mode, opened_path, options);
1753 if (stream) {
1754 efree(pathbuf);
1755 return stream;
1756 }
1757stream_skip:
1758 ptr = end;
1759 } /* end provided path */
1760
1761 efree(pathbuf);
1762 return NULL;
1763
1764}
1765/* }}} */
umask(?int $mask=null)
unlink(string $filename, $context=null)
usleep(int $microseconds)
fsync($stream)
readdir($dir_handle=null)
ftruncate($stream, int $size)
file(string $filename, int $flags=0, $context=null)
feof($stream)
closedir($dir_handle=null)
strrchr(string $haystack, string $needle, bool $before_needle=false)
pclose($handle)
fwrite($stream, string $data, ?int $length=null)
dir(string $directory, $context=null)
fclose($stream)
count(Countable|array $value, int $mode=COUNT_NORMAL)
fread($stream, int $length)
fflush($stream)
flock($stream, int $operation, &$would_block=null)
assert(mixed $assertion, Throwable|string|null $description=null)
rewinddir($dir_handle=null)
strchr(string $haystack, string $needle, bool $before_needle=false)
realpath(string $path)
void php_stream_mode_sanitize_fdopen_fopencookie(php_stream *stream, char *result)
Definition cast.c:151
zend_long ptrdiff_t
#define DWORD
Definition exif.c:1762
DL_HANDLE handle
Definition ffi.c:3028
zend_long n
Definition ffi.c:4979
new_type size
Definition ffi.c:4365
void * ptr
Definition ffi.c:3814
memcpy(ptr1, ptr2, size)
memset(ptr, 0, type->size)
ffi persistent
Definition ffi.c:3633
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
PHPAPI zend_result php_copy_file(const char *src, const char *dest)
Definition file.c:1483
const SEEK_CUR
Definition file.stub.php:16
#define O_BINARY
Definition file.h:643
#define O_CLOEXEC
Definition file.h:144
PHPAPI void php_clear_stat_cache(bool clear_realpath_cache, const char *filename, size_t filename_len)
Definition filestat.c:697
PHPAPI char * expand_filepath_with_mode(const char *filepath, char *real_path, const char *relative_to, size_t relative_to_len, int realpath_mode)
PHPAPI int php_check_open_basedir(const char *path)
PHPAPI char * expand_filepath(const char *filepath, char *real_path)
PHPAPI int php_check_open_basedir_ex(const char *path, int warn)
zend_long offset
char * mode
#define SIZE_MAX
Definition funcs.c:51
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
unsigned short mode_t
Definition ioutil.h:72
#define F_OK
Definition ioutil.h:86
PHPAPI ZEND_COLD void php_error_docref2(const char *docref, const char *param1, const char *param2, int type, const char *format,...)
Definition main.c:1198
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
Definition main.c:1173
PHPAPI ZEND_COLD void php_error_docref1(const char *docref, const char *param1, int type, const char *format,...)
Definition main.c:1186
#define O_NONBLOCK
Definition network.c:282
#define SOCK_ERR
Definition network.c:85
char * cwd
uint32_t cwd_len
#define strlcpy
Definition php.h:159
#define PHP_STRLCPY(dst, src, size, src_size)
Definition php.h:142
#define PHPAPI
Definition php.h:71
unsigned const char * end
Definition php_ffi.h:51
PHP_JSON_API size_t int options
Definition php_json.h:102
#define PHP_IS_TRANSIENT_ERROR(err)
Definition php_network.h:54
int php_socket_t
PHPAPI int php_open_temporary_fd(const char *dir, const char *pfx, zend_string **opened_path_p)
php_output_handler * active
Definition php_output.h:140
PHPAPI const php_stream_wrapper php_glob_stream_wrapper
@ PHP_STREAM_MAP_MODE_READWRITE
@ PHP_STREAM_MAP_MODE_READONLY
@ PHP_STREAM_MAP_MODE_SHARED_READONLY
@ PHP_STREAM_MAP_MODE_SHARED_READWRITE
#define php_stream_mmap_range(stream, offset, length, mode, mapped_len)
@ PHP_STREAM_MMAP_UNMAP
@ PHP_STREAM_MMAP_SUPPORTED
@ PHP_STREAM_MMAP_MAP_RANGE
PHPAPI php_stream_wrapper php_plain_files_wrapper
#define php_stream_fopen_temporary_file(dir, pfx, opened_path)
PHPAPI php_stream_ops php_stream_stdio_ops
#define php_stream_cast(stream, as, ret, show_err)
struct _php_stream_wrapper_ops php_stream_wrapper_ops
struct _php_stream php_stream
Definition php_streams.h:96
struct _php_stream_context php_stream_context
Definition php_streams.h:98
#define REPORT_ERRORS
#define php_stream_fopen_from_fd_rel(fd, mode, persistent_id, zero_position)
Definition php_streams.h:68
#define PHP_STREAM_META_GROUP
#define PHP_STREAM_OPTION_BLOCKING
struct _php_stream_dirent php_stream_dirent
#define PHP_STREAM_AS_FD_FOR_SELECT
#define STREAM_USE_GLOB_DIR_OPEN
#define PHP_STREAM_TRUNCATE_SET_SIZE
#define PHP_STREAM_URL_STAT_IGNORE_OPEN_BASEDIR
PHPAPI int php_stream_from_persistent_id(const char *persistent_id, php_stream **stream)
Definition streams.c:111
#define PHP_STREAM_META_OWNER_NAME
#define STREAMS_DC
Definition php_streams.h:53
#define php_stream_alloc_rel(ops, thisptr, persistent, mode)
Definition php_streams.h:60
#define PHP_STREAM_FLAG_NO_SEEK
#define PHP_STREAM_LOCK_SUPPORTED
#define STREAM_OPEN_FOR_INCLUDE
#define PHP_STREAM_BUFFER_NONE
#define PHP_STREAM_MKDIR_RECURSIVE
#define PHP_STREAM_OPTION_WRITE_BUFFER
#define PHP_STREAM_META_GROUP_NAME
#define STREAM_ASSUME_REALPATH
#define php_stream_close(stream)
#define PHP_STREAM_OPTION_RETURN_NOTIMPL
#define PHP_STREAM_FLAG_SUPPRESS_ERRORS
#define PHP_STREAM_META_OWNER
#define PHP_STREAM_PERSISTENT_FAILURE
#define STREAM_DISABLE_OPEN_BASEDIR
#define STREAM_OPEN_PERSISTENT
struct _php_stream_ops php_stream_ops
#define PHP_STREAM_URL_STAT_LINK
#define PHP_STREAM_OPTION_LOCKING
#define PHP_STREAM_META_TOUCH
#define PHP_STREAM_BUFFER_FULL
#define PHP_STREAM_PERSISTENT_SUCCESS
#define PHP_STREAM_OPTION_META_DATA_API
#define PHP_STREAM_OPTION_SYNC_API
#define PHP_STREAM_OPTION_RETURN_ERR
#define PHP_STREAM_SYNC_FSYNC
#define PHP_STREAM_OPTION_TRUNCATE_API
#define PHP_STREAM_BUFFER_LINE
#define STREAMS_REL_CC
Definition php_streams.h:55
struct _php_stream_wrapper php_stream_wrapper
Definition php_streams.h:97
#define PHP_STREAM_SYNC_SUPPORTED
#define PHP_STREAM_SYNC_FDSYNC
#define PHP_STREAM_TRUNCATE_SUPPORTED
#define php_stream_fopen_rel(filename, mode, opened, options)
Definition php_streams.h:64
#define php_stream_alloc(ops, thisptr, persistent_id, mode)
#define PHP_STREAM_OPTION_RETURN_OK
#define PHP_STREAM_URL_STAT_QUIET
#define PHP_STREAM_AS_FD
#define PHP_STREAM_OPTION_PIPE_BLOCKING
#define STREAM_USE_BLOCKING_PIPE
#define PHP_STREAM_AS_STDIO
struct _php_stream_statbuf php_stream_statbuf
PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, int options, const char *fmt,...) PHP_ATTRIBUTE_FORMAT(printf
#define PHP_STREAM_OPTION_MMAP_API
#define PHP_STREAM_META_ACCESS
#define pemalloc_rel_orig(size, persistent)
#define emalloc_rel_orig(size)
ssize_t(* php_stdiop_write)(php_stream *, const char *, size_t)
Definition phpdbg.h:284
int fd
Definition phpdbg.h:282
zend_constant * data
#define PROT_READ
Definition phpdbg_win.h:26
#define PROT_WRITE
Definition phpdbg_win.h:27
#define php_stream_fopen_from_file_int_rel(file, mode)
PHPAPI php_stream * _php_stream_fopen(const char *filename, const char *mode, zend_string **opened_path, int options STREAMS_DC)
PHPAPI php_stream * _php_stream_fopen_from_pipe(FILE *file, const char *mode STREAMS_DC)
PHPAPI php_stream * _php_stream_fopen_with_path(const char *filename, const char *mode, const char *path, zend_string **opened_path, int options STREAMS_DC)
PHPAPI php_stream * _php_stream_fopen_from_file(FILE *file, const char *mode STREAMS_DC)
#define php_stream_fopen_from_fd_int_rel(fd, mode, persistent_id)
PHPAPI php_stream * _php_stream_fopen_tmpfile(int dummy STREAMS_DC)
#define fdatasync
int php_get_uid_by_name(const char *name, uid_t *uid)
Definition filestat.c:416
PHPAPI php_stream * _php_stream_fopen_temporary_file(const char *dir, const char *pfx, zend_string **opened_path_ptr STREAMS_DC)
int php_get_gid_by_name(const char *name, gid_t *gid)
Definition filestat.c:275
PHPAPI int php_stream_parse_fopen_modes(const char *mode, int *open_flags)
PHPAPI php_stream * _php_stream_fopen_from_fd(int fd, const char *mode, const char *persistent_id, bool zero_position STREAMS_DC)
#define PLAIN_WRAP_BUF_SIZE(st)
#define PHP_STDIOP_GET_FD(anfd, data)
#define DT_UNKNOWN
Definition readdir.h:19
struct DIR_W32 DIR
Definition readdir.h:41
p
Definition session.c:1105
#define spprintf
Definition spprintf.h:29
unsigned char d_type
char d_name[MAXPATHLEN]
uint32_t flags
void * abstract
zend_off_t position
php_stream_wrapper * wrapper
char * orig_path
Definition dce.c:49
zend_string * temp_name
#define close(a)
#define errno
int php_win32_check_trailing_space(const char *path, const size_t path_len)
Definition winutil.c:57
ZEND_API ZEND_COLD void zend_value_error(const char *format,...)
Definition zend.c:1849
#define MAP_FAILED
Definition zend_alloc.c:98
#define estrndup(s, length)
Definition zend_alloc.h:165
#define efree(ptr)
Definition zend_alloc.h:155
#define estrdup(s)
Definition zend_alloc.h:164
#define pefree(ptr, persistent)
Definition zend_alloc.h:191
#define emalloc(size)
Definition zend_alloc.h:151
struct _zval_struct zval
strlen(string $string)
zend_string_release_ex(func->internal_function.function_name, 0)
#define strncasecmp(s1, s2, n)
#define snprintf
#define E_NOTICE
Definition zend_errors.h:26
#define E_WARNING
Definition zend_errors.h:24
ZEND_API void(ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data)
ZEND_API zend_string * zend_get_executed_filename_ex(void)
ZEND_API bool zend_is_executing(void)
#define LOCK_UN
#define EG(v)
int32_t zend_long
Definition zend_long.h:42
int32_t zend_off_t
Definition zend_long.h:44
struct _zend_string zend_string
#define ZEND_FALLTHROUGH
#define ZEND_ASSERT(c)
#define zend_lseek
Definition zend_stream.h:97
#define zend_fseek
Definition zend_stream.h:95
#define zend_fstat
Definition zend_stream.h:98
struct stat zend_stat_t
Definition zend_stream.h:94
#define zend_ftell
Definition zend_stream.h:96
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
@ FAILURE
Definition zend_types.h:61
CWD_API char * virtual_getcwd_ex(size_t *length)
#define IS_SLASH(c)
#define VCWD_MKDIR(pathname, mode)
#define DEFAULT_SLASH
#define VCWD_RENAME(oldname, newname)
#define VCWD_FOPEN(path, mode)
#define VCWD_CHOWN(path, owner, group)
#define IS_ABSOLUTE_PATH(path, len)
#define VCWD_LSTAT(path, buff)
#define VCWD_OPENDIR(pathname)
#define CWD_EXPAND
#define VCWD_UNLINK(path)
#define S_ISREG(mode)
#define DEFAULT_DIR_SEPARATOR
#define VCWD_RMDIR(pathname)
#define VCWD_CHMOD(path, mode)
#define MAXPATHLEN
#define VCWD_ACCESS(pathname, mode)
#define VCWD_STAT(path, buff)
zend_string * name
bool result
zval * ret
value