Annotation of embedaddon/php/main/streams/plain_wrapper.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>