LTP GCOV extension - code coverage report
Current view: directory - main/streams - plain_wrapper.c
Test: PHP Code Coverage
Date: 2007-04-10 Instrumented lines: 552
Code covered: 45.5 % Executed lines: 251
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5