Back to index

php5  5.3.10
plain_wrapper.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Wez Furlong <wez@thebrainroom.com>                          |
00016    +----------------------------------------------------------------------+
00017  */
00018 
00019 /* $Id: plain_wrapper.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #include "php.h"
00022 #include "php_globals.h"
00023 #include "php_network.h"
00024 #include "php_open_temporary_file.h"
00025 #include "ext/standard/file.h"
00026 #include "ext/standard/flock_compat.h"
00027 #include "ext/standard/php_filestat.h"
00028 #include <stddef.h>
00029 #include <fcntl.h>
00030 #if HAVE_SYS_WAIT_H
00031 #include <sys/wait.h>
00032 #endif
00033 #if HAVE_SYS_FILE_H
00034 #include <sys/file.h>
00035 #endif
00036 #ifdef HAVE_SYS_MMAN_H
00037 #include <sys/mman.h>
00038 #endif
00039 #include "SAPI.h"
00040 
00041 #include "php_streams_int.h"
00042 #ifdef PHP_WIN32
00043 # include "win32/winutil.h"
00044 #endif
00045 
00046 #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)
00047 #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)
00048 #define php_stream_fopen_from_file_int(file, mode)      _php_stream_fopen_from_file_int((file), (mode) STREAMS_CC TSRMLS_CC)
00049 #define php_stream_fopen_from_file_int_rel(file, mode)   _php_stream_fopen_from_file_int((file), (mode) STREAMS_REL_CC TSRMLS_CC)
00050 
00051 /* parse standard "fopen" modes into open() flags */
00052 PHPAPI int php_stream_parse_fopen_modes(const char *mode, int *open_flags)
00053 {
00054        int flags;
00055 
00056        switch (mode[0]) {
00057               case 'r':
00058                      flags = 0;
00059                      break;
00060               case 'w':
00061                      flags = O_TRUNC|O_CREAT;
00062                      break;
00063               case 'a':
00064                      flags = O_CREAT|O_APPEND;
00065                      break;
00066               case 'x':
00067                      flags = O_CREAT|O_EXCL;
00068                      break;
00069               case 'c':
00070                      flags = O_CREAT;
00071                      break;
00072               default:
00073                      /* unknown mode */
00074                      return FAILURE;
00075        }
00076 #if defined(O_NONBLOCK)
00077        if (strchr(mode, 'n')) {
00078               flags |= O_NONBLOCK;
00079        }
00080 #endif
00081        if (strchr(mode, '+')) {
00082               flags |= O_RDWR;
00083        } else if (flags) {
00084               flags |= O_WRONLY;
00085        } else {
00086               flags |= O_RDONLY;
00087        }
00088 
00089 #if defined(_O_TEXT) && defined(O_BINARY)
00090        if (strchr(mode, 't')) {
00091               flags |= _O_TEXT;
00092        } else {
00093               flags |= O_BINARY;
00094        }
00095 #endif
00096 
00097        *open_flags = flags;
00098        return SUCCESS;
00099 }
00100 
00101 
00102 /* {{{ ------- STDIO stream implementation -------*/
00103 
00104 typedef struct {
00105        FILE *file;
00106        int fd;                                   /* underlying file descriptor */
00107        unsigned is_process_pipe:1; /* use pclose instead of fclose */
00108        unsigned is_pipe:1;                /* don't try and seek */
00109        unsigned cached_fstat:1;    /* sb is valid */
00110        unsigned _reserved:29;
00111        
00112        int lock_flag;                     /* stores the lock state */
00113        char *temp_file_name;       /* if non-null, this is the path to a temporary file that
00114                                                   * is to be deleted when the stream is closed */
00115 #if HAVE_FLUSHIO
00116        char last_op;
00117 #endif
00118 
00119 #if HAVE_MMAP
00120        char *last_mapped_addr;
00121        size_t last_mapped_len;
00122 #endif
00123 #ifdef PHP_WIN32
00124        char *last_mapped_addr;
00125        HANDLE file_mapping;
00126 #endif
00127 
00128        struct stat sb;
00129 } php_stdio_stream_data;
00130 #define PHP_STDIOP_GET_FD(anfd, data)     anfd = (data)->file ? fileno((data)->file) : (data)->fd
00131 
00132 static int do_fstat(php_stdio_stream_data *d, int force)
00133 {
00134        if (!d->cached_fstat || force) {
00135               int fd;
00136               int r;
00137           
00138               PHP_STDIOP_GET_FD(fd, d);
00139               r = fstat(fd, &d->sb);
00140               d->cached_fstat = r == 0;
00141 
00142               return r;
00143        }
00144        return 0;
00145 }
00146 
00147 static php_stream *_php_stream_fopen_from_fd_int(int fd, const char *mode, const char *persistent_id STREAMS_DC TSRMLS_DC)
00148 {
00149        php_stdio_stream_data *self;
00150        
00151        self = pemalloc_rel_orig(sizeof(*self), persistent_id);
00152        memset(self, 0, sizeof(*self));
00153        self->file = NULL;
00154        self->is_pipe = 0;
00155        self->lock_flag = LOCK_UN;
00156        self->is_process_pipe = 0;
00157        self->temp_file_name = NULL;
00158        self->fd = fd;
00159        
00160        return php_stream_alloc_rel(&php_stream_stdio_ops, self, persistent_id, mode);
00161 }
00162 
00163 static php_stream *_php_stream_fopen_from_file_int(FILE *file, const char *mode STREAMS_DC TSRMLS_DC)
00164 {
00165        php_stdio_stream_data *self;
00166        
00167        self = emalloc_rel_orig(sizeof(*self));
00168        memset(self, 0, sizeof(*self));
00169        self->file = file;
00170        self->is_pipe = 0;
00171        self->lock_flag = LOCK_UN;
00172        self->is_process_pipe = 0;
00173        self->temp_file_name = NULL;
00174        self->fd = fileno(file);
00175 
00176        return php_stream_alloc_rel(&php_stream_stdio_ops, self, 0, mode);
00177 }
00178 
00179 PHPAPI php_stream *_php_stream_fopen_temporary_file(const char *dir, const char *pfx, char **opened_path STREAMS_DC TSRMLS_DC)
00180 {
00181        int fd = php_open_temporary_fd(dir, pfx, opened_path TSRMLS_CC);
00182 
00183        if (fd != -1) {
00184               php_stream *stream = php_stream_fopen_from_fd_int_rel(fd, "r+b", NULL);
00185               if (stream) {
00186                      return stream;
00187               }
00188               close(fd);
00189 
00190               php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to allocate stream");
00191 
00192               return NULL;
00193        }
00194        return NULL;
00195 }
00196 
00197 PHPAPI php_stream *_php_stream_fopen_tmpfile(int dummy STREAMS_DC TSRMLS_DC)
00198 {
00199        char *opened_path = NULL;
00200        int fd = php_open_temporary_fd(NULL, "php", &opened_path TSRMLS_CC);
00201 
00202        if (fd != -1) {
00203               php_stream *stream = php_stream_fopen_from_fd_int_rel(fd, "r+b", NULL);
00204               if (stream) {
00205                      php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
00206                      stream->wrapper = &php_plain_files_wrapper;
00207                      stream->orig_path = estrdup(opened_path);
00208 
00209                      self->temp_file_name = opened_path;
00210                      self->lock_flag = LOCK_UN;
00211                      
00212                      return stream;
00213               }
00214               close(fd);
00215 
00216               php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to allocate stream");
00217 
00218               return NULL;
00219        }
00220        return NULL;
00221 }
00222 
00223 PHPAPI php_stream *_php_stream_fopen_from_fd(int fd, const char *mode, const char *persistent_id STREAMS_DC TSRMLS_DC)
00224 {
00225        php_stream *stream = php_stream_fopen_from_fd_int_rel(fd, mode, persistent_id);
00226 
00227        if (stream) {
00228               php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
00229 
00230 #ifdef S_ISFIFO
00231               /* detect if this is a pipe */
00232               if (self->fd >= 0) {
00233                      self->is_pipe = (do_fstat(self, 0) == 0 && S_ISFIFO(self->sb.st_mode)) ? 1 : 0;
00234               }
00235 #elif defined(PHP_WIN32)
00236               {
00237                      zend_uintptr_t handle = _get_osfhandle(self->fd);
00238 
00239                      if (handle != (zend_uintptr_t)INVALID_HANDLE_VALUE) {
00240                             self->is_pipe = GetFileType((HANDLE)handle) == FILE_TYPE_PIPE;
00241                      }
00242               }
00243 #endif
00244        
00245               if (self->is_pipe) {
00246                      stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
00247               } else {
00248                      stream->position = lseek(self->fd, 0, SEEK_CUR);
00249 #ifdef ESPIPE
00250                      if (stream->position == (off_t)-1 && errno == ESPIPE) {
00251                             stream->position = 0;
00252                             stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
00253                             self->is_pipe = 1;
00254                      }
00255 #endif
00256               }
00257        }
00258 
00259        return stream;
00260 }
00261 
00262 PHPAPI php_stream *_php_stream_fopen_from_file(FILE *file, const char *mode STREAMS_DC TSRMLS_DC)
00263 {
00264        php_stream *stream = php_stream_fopen_from_file_int_rel(file, mode);
00265 
00266        if (stream) {
00267               php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
00268 
00269 #ifdef S_ISFIFO
00270               /* detect if this is a pipe */
00271               if (self->fd >= 0) {
00272                      self->is_pipe = (do_fstat(self, 0) == 0 && S_ISFIFO(self->sb.st_mode)) ? 1 : 0;
00273               }
00274 #elif defined(PHP_WIN32)
00275               {
00276                      zend_uintptr_t handle = _get_osfhandle(self->fd);
00277 
00278                      if (handle != (zend_uintptr_t)INVALID_HANDLE_VALUE) {
00279                             self->is_pipe = GetFileType((HANDLE)handle) == FILE_TYPE_PIPE;
00280                      }
00281               }
00282 #endif
00283        
00284               if (self->is_pipe) {
00285                      stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
00286               } else {
00287                      stream->position = ftell(file);
00288               }
00289        }
00290 
00291        return stream;
00292 }
00293 
00294 PHPAPI php_stream *_php_stream_fopen_from_pipe(FILE *file, const char *mode STREAMS_DC TSRMLS_DC)
00295 {
00296        php_stdio_stream_data *self;
00297        php_stream *stream;
00298 
00299        self = emalloc_rel_orig(sizeof(*self));
00300        memset(self, 0, sizeof(*self));
00301        self->file = file;
00302        self->is_pipe = 1;
00303        self->lock_flag = LOCK_UN;
00304        self->is_process_pipe = 1;
00305        self->fd = fileno(file);
00306        self->temp_file_name = NULL;
00307 
00308        stream = php_stream_alloc_rel(&php_stream_stdio_ops, self, 0, mode);
00309        stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
00310        return stream;
00311 }
00312 
00313 static size_t php_stdiop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
00314 {
00315        php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
00316 
00317        assert(data != NULL);
00318 
00319        if (data->fd >= 0) {
00320               int bytes_written = write(data->fd, buf, count);
00321               if (bytes_written < 0) return 0;
00322               return (size_t) bytes_written;
00323        } else {
00324 
00325 #if HAVE_FLUSHIO
00326               if (!data->is_pipe && data->last_op == 'r') {
00327                      fseek(data->file, 0, SEEK_CUR);
00328               }
00329               data->last_op = 'w';
00330 #endif
00331 
00332               return fwrite(buf, 1, count, data->file);
00333        }
00334 }
00335 
00336 static size_t php_stdiop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
00337 {
00338        php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
00339        size_t ret;
00340 
00341        assert(data != NULL);
00342 
00343        if (data->fd >= 0) {
00344               ret = read(data->fd, buf, count);
00345 
00346               if (ret == (size_t)-1 && errno == EINTR) {
00347                      /* Read was interrupted, retry once,
00348                         If read still fails, giveup with feof==0
00349                         so script can retry if desired */
00350                      ret = read(data->fd, buf, count);
00351               }
00352               
00353               stream->eof = (ret == 0 || (ret == (size_t)-1 && errno != EWOULDBLOCK && errno != EINTR && errno != EBADF));
00354                             
00355        } else {
00356 #if HAVE_FLUSHIO
00357               if (!data->is_pipe && data->last_op == 'w')
00358                      fseek(data->file, 0, SEEK_CUR);
00359               data->last_op = 'r';
00360 #endif
00361 
00362               ret = fread(buf, 1, count, data->file);
00363 
00364               stream->eof = feof(data->file);
00365        }
00366        return ret;
00367 }
00368 
00369 static int php_stdiop_close(php_stream *stream, int close_handle TSRMLS_DC)
00370 {
00371        int ret;
00372        php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
00373 
00374        assert(data != NULL);
00375 
00376 #if HAVE_MMAP
00377        if (data->last_mapped_addr) {
00378               munmap(data->last_mapped_addr, data->last_mapped_len);
00379               data->last_mapped_addr = NULL;
00380        }
00381 #elif defined(PHP_WIN32)
00382        if (data->last_mapped_addr) {
00383               UnmapViewOfFile(data->last_mapped_addr);
00384               data->last_mapped_addr = NULL;
00385        }
00386        if (data->file_mapping) {
00387               CloseHandle(data->file_mapping);
00388               data->file_mapping = NULL;
00389        }
00390 #endif
00391        
00392        if (close_handle) {
00393               if (data->file) {
00394                      if (data->is_process_pipe) {
00395                             errno = 0;
00396                             ret = pclose(data->file);
00397 
00398 #if HAVE_SYS_WAIT_H
00399                             if (WIFEXITED(ret)) {
00400                                    ret = WEXITSTATUS(ret);
00401                             }
00402 #endif
00403                      } else {
00404                             ret = fclose(data->file);
00405                             data->file = NULL;
00406                      }
00407               } else if (data->fd != -1) {
00408                      ret = close(data->fd);
00409                      data->fd = -1;
00410               } else {
00411                      return 0; /* everything should be closed already -> success */
00412               }
00413               if (data->temp_file_name) {
00414                      unlink(data->temp_file_name);
00415                      /* temporary streams are never persistent */
00416                      efree(data->temp_file_name);
00417                      data->temp_file_name = NULL;
00418               }
00419        } else {
00420               ret = 0;
00421               data->file = NULL;
00422               data->fd = -1;
00423        }
00424 
00425        pefree(data, stream->is_persistent);
00426 
00427        return ret;
00428 }
00429 
00430 static int php_stdiop_flush(php_stream *stream TSRMLS_DC)
00431 {
00432        php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
00433 
00434        assert(data != NULL);
00435 
00436        /*
00437         * stdio buffers data in user land. By calling fflush(3), this
00438         * data is send to the kernel using write(2). fsync'ing is
00439         * something completely different.
00440         */
00441        if (data->file) {
00442               return fflush(data->file);
00443        }
00444        return 0;
00445 }
00446 
00447 static int php_stdiop_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC)
00448 {
00449        php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
00450        int ret;
00451 
00452        assert(data != NULL);
00453 
00454        if (data->is_pipe) {
00455               php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot seek on a pipe");
00456               return -1;
00457        }
00458 
00459        if (data->fd >= 0) {
00460               off_t result;
00461               
00462               result = lseek(data->fd, offset, whence);
00463               if (result == (off_t)-1)
00464                      return -1;
00465 
00466               *newoffset = result;
00467               return 0;
00468               
00469        } else {
00470               ret = fseek(data->file, offset, whence);
00471               *newoffset = ftell(data->file);
00472               return ret;
00473        }
00474 }
00475 
00476 static int php_stdiop_cast(php_stream *stream, int castas, void **ret TSRMLS_DC)
00477 {
00478        int fd;
00479        php_stdio_stream_data *data = (php_stdio_stream_data*) stream->abstract;
00480 
00481        assert(data != NULL);
00482        
00483        /* as soon as someone touches the stdio layer, buffering may ensue,
00484         * so we need to stop using the fd directly in that case */
00485 
00486        switch (castas)      {
00487               case PHP_STREAM_AS_STDIO:
00488                      if (ret) {
00489 
00490                             if (data->file == NULL) {
00491                                    /* we were opened as a plain file descriptor, so we
00492                                     * need fdopen now */
00493                                    char fixed_mode[5];
00494                                    php_stream_mode_sanitize_fdopen_fopencookie(stream, fixed_mode);
00495                                    data->file = fdopen(data->fd, fixed_mode);
00496                                    if (data->file == NULL) {
00497                                           return FAILURE;
00498                                    }
00499                             }
00500                             
00501                             *(FILE**)ret = data->file;
00502                             data->fd = -1;
00503                      }
00504                      return SUCCESS;
00505 
00506               case PHP_STREAM_AS_FD_FOR_SELECT:
00507                      PHP_STDIOP_GET_FD(fd, data);
00508                      if (fd < 0) {
00509                             return FAILURE;
00510                      }
00511                      if (ret) {
00512                             *(int*)ret = fd;
00513                      }
00514                      return SUCCESS;
00515 
00516               case PHP_STREAM_AS_FD:
00517                      PHP_STDIOP_GET_FD(fd, data);
00518 
00519                      if (fd < 0) {
00520                             return FAILURE;
00521                      }
00522                      if (data->file) {
00523                             fflush(data->file);
00524                      }
00525                      if (ret) {
00526                             *(int*)ret = fd;
00527                      }
00528                      return SUCCESS;
00529               default:
00530                      return FAILURE;
00531        }
00532 }
00533 
00534 static int php_stdiop_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
00535 {
00536        int ret;
00537        php_stdio_stream_data *data = (php_stdio_stream_data*) stream->abstract;
00538 
00539        assert(data != NULL);
00540 
00541        ret = do_fstat(data, 1);
00542        memcpy(&ssb->sb, &data->sb, sizeof(ssb->sb));
00543        return ret;
00544 }
00545 
00546 static int php_stdiop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
00547 {
00548        php_stdio_stream_data *data = (php_stdio_stream_data*) stream->abstract;
00549        size_t size;
00550        int fd;
00551 #ifdef O_NONBLOCK
00552        /* FIXME: make this work for win32 */
00553        int flags;
00554        int oldval;
00555 #endif
00556        
00557        PHP_STDIOP_GET_FD(fd, data);
00558        
00559        switch(option) {
00560               case PHP_STREAM_OPTION_BLOCKING:
00561                      if (fd == -1)
00562                             return -1;
00563 #ifdef O_NONBLOCK
00564                      flags = fcntl(fd, F_GETFL, 0);
00565                      oldval = (flags & O_NONBLOCK) ? 0 : 1;
00566                      if (value)
00567                             flags &= ~O_NONBLOCK;
00568                      else
00569                             flags |= O_NONBLOCK;
00570                      
00571                      if (-1 == fcntl(fd, F_SETFL, flags))
00572                             return -1;
00573                      return oldval;
00574 #else
00575                      return -1; /* not yet implemented */
00576 #endif
00577                      
00578               case PHP_STREAM_OPTION_WRITE_BUFFER:
00579 
00580                      if (data->file == NULL) {
00581                             return -1;
00582                      }
00583                      
00584                      if (ptrparam)
00585                             size = *(size_t *)ptrparam;
00586                      else
00587                             size = BUFSIZ;
00588 
00589                      switch(value) {
00590                             case PHP_STREAM_BUFFER_NONE:
00591                                    stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
00592                                    return setvbuf(data->file, NULL, _IONBF, 0);
00593                                    
00594                             case PHP_STREAM_BUFFER_LINE:
00595                                    stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER;
00596                                    return setvbuf(data->file, NULL, _IOLBF, size);
00597                                    
00598                             case PHP_STREAM_BUFFER_FULL:
00599                                    stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER;
00600                                    return setvbuf(data->file, NULL, _IOFBF, size);
00601 
00602                             default:
00603                                    return -1;
00604                      }
00605                      break;
00606               
00607               case PHP_STREAM_OPTION_LOCKING:
00608                      if (fd == -1) {
00609                             return -1;
00610                      }
00611 
00612                      if ((zend_uintptr_t) ptrparam == PHP_STREAM_LOCK_SUPPORTED) {
00613                             return 0;
00614                      }
00615 
00616                      if (!flock(fd, value)) {
00617                             data->lock_flag = value;
00618                             return 0;
00619                      } else {
00620                             return -1;
00621                      }
00622                      break;
00623 
00624               case PHP_STREAM_OPTION_MMAP_API:
00625 #if HAVE_MMAP
00626                      {
00627                             php_stream_mmap_range *range = (php_stream_mmap_range*)ptrparam;
00628                             int prot, flags;
00629                             
00630                             switch (value) {
00631                                    case PHP_STREAM_MMAP_SUPPORTED:
00632                                           return fd == -1 ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK;
00633 
00634                                    case PHP_STREAM_MMAP_MAP_RANGE:
00635                                           do_fstat(data, 1);
00636                                           if (range->length == 0 && range->offset > 0 && range->offset < data->sb.st_size) {
00637                                                  range->length = data->sb.st_size - range->offset;
00638                                           }
00639                                           if (range->length == 0 || range->length > data->sb.st_size) {
00640                                                  range->length = data->sb.st_size;
00641                                           }
00642                                           if (range->offset >= data->sb.st_size) {
00643                                                  range->offset = data->sb.st_size;
00644                                                  range->length = 0;
00645                                           }
00646                                           switch (range->mode) {
00647                                                  case PHP_STREAM_MAP_MODE_READONLY:
00648                                                         prot = PROT_READ;
00649                                                         flags = MAP_PRIVATE;
00650                                                         break;
00651                                                  case PHP_STREAM_MAP_MODE_READWRITE:
00652                                                         prot = PROT_READ | PROT_WRITE;
00653                                                         flags = MAP_PRIVATE;
00654                                                         break;
00655                                                  case PHP_STREAM_MAP_MODE_SHARED_READONLY:
00656                                                         prot = PROT_READ;
00657                                                         flags = MAP_SHARED;
00658                                                         break;
00659                                                  case PHP_STREAM_MAP_MODE_SHARED_READWRITE:
00660                                                         prot = PROT_READ | PROT_WRITE;
00661                                                         flags = MAP_SHARED;
00662                                                         break;
00663                                                  default:
00664                                                         return PHP_STREAM_OPTION_RETURN_ERR;
00665                                           }
00666                                           range->mapped = (char*)mmap(NULL, range->length, prot, flags, fd, range->offset);
00667                                           if (range->mapped == (char*)MAP_FAILED) {
00668                                                  range->mapped = NULL;
00669                                                  return PHP_STREAM_OPTION_RETURN_ERR;
00670                                           }
00671                                           /* remember the mapping */
00672                                           data->last_mapped_addr = range->mapped;
00673                                           data->last_mapped_len = range->length;
00674                                           return PHP_STREAM_OPTION_RETURN_OK;
00675 
00676                                    case PHP_STREAM_MMAP_UNMAP:
00677                                           if (data->last_mapped_addr) {
00678                                                  munmap(data->last_mapped_addr, data->last_mapped_len);
00679                                                  data->last_mapped_addr = NULL;
00680 
00681                                                  return PHP_STREAM_OPTION_RETURN_OK;
00682                                           }
00683                                           return PHP_STREAM_OPTION_RETURN_ERR;
00684                             }
00685                      }
00686 #elif defined(PHP_WIN32)
00687                      {
00688                             php_stream_mmap_range *range = (php_stream_mmap_range*)ptrparam;
00689                             HANDLE hfile = (HANDLE)_get_osfhandle(fd);
00690                             DWORD prot, acc, loffs = 0, delta = 0;
00691 
00692                             switch (value) {
00693                                    case PHP_STREAM_MMAP_SUPPORTED:
00694                                           return hfile == INVALID_HANDLE_VALUE ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK;
00695 
00696                                    case PHP_STREAM_MMAP_MAP_RANGE:
00697                                           switch (range->mode) {
00698                                                  case PHP_STREAM_MAP_MODE_READONLY:
00699                                                         prot = PAGE_READONLY;
00700                                                         acc = FILE_MAP_READ;
00701                                                         break;
00702                                                  case PHP_STREAM_MAP_MODE_READWRITE:
00703                                                         prot = PAGE_READWRITE;
00704                                                         acc = FILE_MAP_READ | FILE_MAP_WRITE;
00705                                                         break;
00706                                                  case PHP_STREAM_MAP_MODE_SHARED_READONLY:
00707                                                         prot = PAGE_READONLY;
00708                                                         acc = FILE_MAP_READ;
00709                                                         /* TODO: we should assign a name for the mapping */
00710                                                         break;
00711                                                  case PHP_STREAM_MAP_MODE_SHARED_READWRITE:
00712                                                         prot = PAGE_READWRITE;
00713                                                         acc = FILE_MAP_READ | FILE_MAP_WRITE;
00714                                                         /* TODO: we should assign a name for the mapping */
00715                                                         break;
00716                                                  default:
00717                                                         return PHP_STREAM_OPTION_RETURN_ERR;
00718                                           }
00719 
00720                                           /* create a mapping capable of viewing the whole file (this costs no real resources) */
00721                                           data->file_mapping = CreateFileMapping(hfile, NULL, prot, 0, 0, NULL);
00722 
00723                                           if (data->file_mapping == NULL) {
00724                                                  return PHP_STREAM_OPTION_RETURN_ERR;
00725                                           }
00726 
00727                                           size = GetFileSize(hfile, NULL);
00728                                           if (range->length == 0 && range->offset > 0 && range->offset < size) {
00729                                                  range->length = size - range->offset;
00730                                           }
00731                                           if (range->length == 0 || range->length > size) {
00732                                                  range->length = size;
00733                                           }
00734                                           if (range->offset >= size) {
00735                                                  range->offset = size;
00736                                                  range->length = 0;
00737                                           }
00738 
00739                                           /* figure out how big a chunk to map to be able to view the part that we need */
00740                                           if (range->offset != 0) {
00741                                                  SYSTEM_INFO info;
00742                                                  DWORD gran;
00743 
00744                                                  GetSystemInfo(&info);
00745                                                  gran = info.dwAllocationGranularity;
00746                                                  loffs = (range->offset / gran) * gran;
00747                                                  delta = range->offset - loffs;
00748                                           }
00749 
00750                                           data->last_mapped_addr = MapViewOfFile(data->file_mapping, acc, 0, loffs, range->length + delta);
00751 
00752                                           if (data->last_mapped_addr) {
00753                                                  /* give them back the address of the start offset they requested */
00754                                                  range->mapped = data->last_mapped_addr + delta;
00755                                                  return PHP_STREAM_OPTION_RETURN_OK;
00756                                           }
00757 
00758                                           CloseHandle(data->file_mapping);
00759                                           data->file_mapping = NULL;
00760 
00761                                           return PHP_STREAM_OPTION_RETURN_ERR;
00762 
00763                                    case PHP_STREAM_MMAP_UNMAP:
00764                                           if (data->last_mapped_addr) {
00765                                                  UnmapViewOfFile(data->last_mapped_addr);
00766                                                  data->last_mapped_addr = NULL;
00767                                                  CloseHandle(data->file_mapping);
00768                                                  data->file_mapping = NULL;
00769                                                  return PHP_STREAM_OPTION_RETURN_OK;
00770                                           }
00771                                           return PHP_STREAM_OPTION_RETURN_ERR;
00772 
00773                                    default:
00774                                           return PHP_STREAM_OPTION_RETURN_ERR;
00775                             }
00776                      }
00777 
00778 #endif
00779                      return PHP_STREAM_OPTION_RETURN_NOTIMPL;
00780 
00781               case PHP_STREAM_OPTION_TRUNCATE_API:
00782                      switch (value) {
00783                             case PHP_STREAM_TRUNCATE_SUPPORTED:
00784                                    return fd == -1 ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK;
00785 
00786                             case PHP_STREAM_TRUNCATE_SET_SIZE: {
00787                                    ptrdiff_t new_size = *(ptrdiff_t*)ptrparam;
00788                                    if (new_size < 0) {
00789                                           return PHP_STREAM_OPTION_RETURN_ERR;
00790                                    }
00791                                    return ftruncate(fd, new_size) == 0 ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR;
00792                             }
00793                      }
00794                      
00795               default:
00796                      return PHP_STREAM_OPTION_RETURN_NOTIMPL;
00797        }
00798 }
00799 
00800 PHPAPI php_stream_ops       php_stream_stdio_ops = {
00801        php_stdiop_write, php_stdiop_read,
00802        php_stdiop_close, php_stdiop_flush,
00803        "STDIO",
00804        php_stdiop_seek,
00805        php_stdiop_cast,
00806        php_stdiop_stat,
00807        php_stdiop_set_option
00808 };
00809 /* }}} */
00810 
00811 /* {{{ plain files opendir/readdir implementation */
00812 static size_t php_plain_files_dirstream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
00813 {
00814        DIR *dir = (DIR*)stream->abstract;
00815        /* avoid libc5 readdir problems */
00816        char entry[sizeof(struct dirent)+MAXPATHLEN];
00817        struct dirent *result = (struct dirent *)&entry;
00818        php_stream_dirent *ent = (php_stream_dirent*)buf;
00819 
00820        /* avoid problems if someone mis-uses the stream */
00821        if (count != sizeof(php_stream_dirent))
00822               return 0;
00823 
00824        if (php_readdir_r(dir, (struct dirent *)entry, &result) == 0 && result) {
00825               PHP_STRLCPY(ent->d_name, result->d_name, sizeof(ent->d_name), strlen(result->d_name));
00826               return sizeof(php_stream_dirent);
00827        }
00828        return 0;
00829 }
00830 
00831 static int php_plain_files_dirstream_close(php_stream *stream, int close_handle TSRMLS_DC)
00832 {
00833        return closedir((DIR *)stream->abstract);
00834 }
00835 
00836 static int php_plain_files_dirstream_rewind(php_stream *stream, off_t offset, int whence, off_t *newoffs TSRMLS_DC)
00837 {
00838        rewinddir((DIR *)stream->abstract);
00839        return 0;
00840 }
00841 
00842 static php_stream_ops       php_plain_files_dirstream_ops = {
00843        NULL, php_plain_files_dirstream_read,
00844        php_plain_files_dirstream_close, NULL,
00845        "dir",
00846        php_plain_files_dirstream_rewind,
00847        NULL, /* cast */
00848        NULL, /* stat */
00849        NULL  /* set_option */
00850 };
00851 
00852 static php_stream *php_plain_files_dir_opener(php_stream_wrapper *wrapper, char *path, char *mode,
00853               int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
00854 {
00855        DIR *dir = NULL;
00856        php_stream *stream = NULL;
00857 
00858 #ifdef HAVE_GLOB
00859        if (options & STREAM_USE_GLOB_DIR_OPEN) {
00860               return php_glob_stream_wrapper.wops->dir_opener(&php_glob_stream_wrapper, path, mode, options, opened_path, context STREAMS_REL_CC TSRMLS_CC);
00861        }
00862 #endif
00863 
00864        if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(path TSRMLS_CC)) {
00865               return NULL;
00866        }
00867        
00868        if (PG(safe_mode) &&(!php_checkuid(path, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
00869               return NULL;
00870        }
00871        
00872        dir = VCWD_OPENDIR(path);
00873 
00874 #ifdef PHP_WIN32
00875        if (!dir) {
00876               php_win32_docref2_from_error(GetLastError(), path, path TSRMLS_CC);
00877        }
00878 
00879        if (dir && dir->finished) {
00880               closedir(dir);
00881               dir = NULL;
00882        }
00883 #endif
00884        if (dir) {
00885               stream = php_stream_alloc(&php_plain_files_dirstream_ops, dir, 0, mode);
00886               if (stream == NULL)
00887                      closedir(dir);
00888        }
00889               
00890        return stream;
00891 }
00892 /* }}} */
00893 
00894 /* {{{ php_stream_fopen */
00895 PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, char **opened_path, int options STREAMS_DC TSRMLS_DC)
00896 {
00897        char *realpath = NULL;
00898        int open_flags;
00899        int fd;
00900        php_stream *ret;
00901        int persistent = options & STREAM_OPEN_PERSISTENT;
00902        char *persistent_id = NULL;
00903 
00904        if (FAILURE == php_stream_parse_fopen_modes(mode, &open_flags)) {
00905               if (options & REPORT_ERRORS) {
00906                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "`%s' is not a valid mode for fopen", mode);
00907               }
00908               return NULL;
00909        }
00910 
00911        if (options & STREAM_ASSUME_REALPATH) {
00912               realpath = estrdup(filename);
00913        } else {
00914               if ((realpath = expand_filepath(filename, NULL TSRMLS_CC)) == NULL) {
00915                      return NULL;
00916               }
00917        }
00918 
00919        if (persistent) {
00920               spprintf(&persistent_id, 0, "streams_stdio_%d_%s", open_flags, realpath);
00921               switch (php_stream_from_persistent_id(persistent_id, &ret TSRMLS_CC)) {
00922                      case PHP_STREAM_PERSISTENT_SUCCESS:
00923                             if (opened_path) {
00924                                    *opened_path = realpath;
00925                                    realpath = NULL;
00926                             }
00927                             /* fall through */
00928 
00929                      case PHP_STREAM_PERSISTENT_FAILURE:
00930                             if (realpath) {
00931                                    efree(realpath);
00932                             }
00933                             efree(persistent_id);;
00934                             return ret;
00935               }
00936        }
00937        
00938        fd = open(realpath, open_flags, 0666);
00939 
00940        if (fd != -1) {
00941 
00942               if (options & STREAM_OPEN_FOR_INCLUDE) {
00943                      ret = php_stream_fopen_from_fd_int_rel(fd, mode, persistent_id);
00944               } else {
00945                      ret = php_stream_fopen_from_fd_rel(fd, mode, persistent_id);
00946               }
00947 
00948               if (ret)      {
00949                      if (opened_path) {
00950                             *opened_path = realpath;
00951                             realpath = NULL;
00952                      }
00953                      if (realpath) {
00954                             efree(realpath);
00955                      }
00956                      if (persistent_id) {
00957                             efree(persistent_id);
00958                      }
00959 
00960                      /* WIN32 always set ISREG flag */
00961 #ifndef PHP_WIN32
00962                      /* sanity checks for include/require.
00963                       * We check these after opening the stream, so that we save
00964                       * on fstat() syscalls */
00965                      if (options & STREAM_OPEN_FOR_INCLUDE) {
00966                             php_stdio_stream_data *self = (php_stdio_stream_data*)ret->abstract;
00967                             int r;
00968 
00969                             r = do_fstat(self, 0);
00970                             if ((r == 0 && !S_ISREG(self->sb.st_mode))) {
00971                                    if (opened_path) {
00972                                           efree(*opened_path);
00973                                           *opened_path = NULL;
00974                                    }
00975                                    php_stream_close(ret);
00976                                    return NULL;
00977                             }
00978                      }
00979 #endif
00980 
00981                      return ret;
00982               }
00983               close(fd);
00984        }
00985        efree(realpath);
00986        if (persistent_id) {
00987               efree(persistent_id);
00988        }
00989        return NULL;
00990 }
00991 /* }}} */
00992 
00993 
00994 static php_stream *php_plain_files_stream_opener(php_stream_wrapper *wrapper, char *path, char *mode,
00995               int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
00996 {
00997        if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(path TSRMLS_CC)) {
00998               return NULL;
00999        }
01000 
01001        if ((php_check_safe_mode_include_dir(path TSRMLS_CC)) == 0) {
01002               return php_stream_fopen_rel(path, mode, opened_path, options);
01003        }
01004 
01005        if ((options & ENFORCE_SAFE_MODE) && PG(safe_mode) && (!php_checkuid(path, mode, CHECKUID_CHECK_MODE_PARAM)))
01006               return NULL;
01007 
01008        return php_stream_fopen_rel(path, mode, opened_path, options);
01009 }
01010 
01011 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)
01012 {
01013 
01014        if (strncmp(url, "file://", sizeof("file://") - 1) == 0) {
01015               url += sizeof("file://") - 1;
01016        }
01017 
01018        if (PG(safe_mode) &&(!php_checkuid_ex(url, NULL, CHECKUID_CHECK_FILE_AND_DIR, (flags & PHP_STREAM_URL_STAT_QUIET) ? CHECKUID_NO_ERRORS : 0))) {
01019               return -1;
01020        }
01021 
01022        if (php_check_open_basedir_ex(url, (flags & PHP_STREAM_URL_STAT_QUIET) ? 0 : 1 TSRMLS_CC)) {
01023               return -1;
01024        }
01025 
01026 #ifdef PHP_WIN32
01027        if (EG(windows_version_info).dwMajorVersion >= 5) {
01028               if (flags & PHP_STREAM_URL_STAT_LINK) {
01029                      return VCWD_LSTAT(url, &ssb->sb);
01030               }
01031        }
01032 #else
01033 # ifdef HAVE_SYMLINK
01034        if (flags & PHP_STREAM_URL_STAT_LINK) {
01035               return VCWD_LSTAT(url, &ssb->sb);
01036        } else
01037 # endif
01038 #endif
01039               return VCWD_STAT(url, &ssb->sb);
01040 }
01041 
01042 static int php_plain_files_unlink(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC)
01043 {
01044        char *p;
01045        int ret;
01046 
01047        if ((p = strstr(url, "://")) != NULL) {
01048               url = p + 3;
01049        }
01050 
01051        if (options & ENFORCE_SAFE_MODE) {
01052               if (PG(safe_mode) && !php_checkuid(url, NULL, CHECKUID_CHECK_FILE_AND_DIR)) {
01053                      return 0;
01054               }
01055 
01056               if (php_check_open_basedir(url TSRMLS_CC)) {
01057                      return 0;
01058               }
01059        }
01060 
01061        ret = VCWD_UNLINK(url);
01062        if (ret == -1) {
01063               if (options & REPORT_ERRORS) {
01064                      php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "%s", strerror(errno));
01065               }
01066               return 0;
01067        }
01068 
01069        /* Clear stat cache (and realpath cache) */
01070        php_clear_stat_cache(1, NULL, 0 TSRMLS_CC);
01071 
01072        return 1;
01073 }
01074 
01075 static int php_plain_files_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC)
01076 {
01077        char *p;
01078        int ret;
01079 
01080        if (!url_from || !url_to) {
01081               return 0;
01082        }
01083 
01084 #ifdef PHP_WIN32
01085        if (!php_win32_check_trailing_space(url_from, strlen(url_from))) {
01086               php_win32_docref2_from_error(ERROR_INVALID_NAME, url_from, url_to TSRMLS_CC);
01087               return 0;
01088        }
01089        if (!php_win32_check_trailing_space(url_to, strlen(url_to))) {
01090               php_win32_docref2_from_error(ERROR_INVALID_NAME, url_from, url_to TSRMLS_CC);
01091               return 0;
01092        }
01093 #endif
01094 
01095        if ((p = strstr(url_from, "://")) != NULL) {
01096               url_from = p + 3;
01097        }
01098 
01099        if ((p = strstr(url_to, "://")) != NULL) {
01100               url_to = p + 3;
01101        }
01102 
01103        if (PG(safe_mode) && (!php_checkuid(url_from, NULL, CHECKUID_CHECK_FILE_AND_DIR) ||
01104                             !php_checkuid(url_to, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
01105               return 0;
01106        }
01107 
01108        if (php_check_open_basedir(url_from TSRMLS_CC) || php_check_open_basedir(url_to TSRMLS_CC)) {
01109               return 0;
01110        }
01111 
01112        ret = VCWD_RENAME(url_from, url_to);
01113 
01114        if (ret == -1) {
01115 #ifndef PHP_WIN32
01116 # ifdef EXDEV
01117               if (errno == EXDEV) {
01118                      struct stat sb;
01119                      if (php_copy_file(url_from, url_to TSRMLS_CC) == SUCCESS) {
01120                             if (VCWD_STAT(url_from, &sb) == 0) {
01121 #  if !defined(TSRM_WIN32) && !defined(NETWARE)
01122                                    if (VCWD_CHMOD(url_to, sb.st_mode)) {
01123                                           if (errno == EPERM) {
01124                                                  php_error_docref2(NULL TSRMLS_CC, url_from, url_to, E_WARNING, "%s", strerror(errno));
01125                                                  VCWD_UNLINK(url_from);
01126                                                  return 1;
01127                                           }
01128                                           php_error_docref2(NULL TSRMLS_CC, url_from, url_to, E_WARNING, "%s", strerror(errno));
01129                                           return 0;
01130                                    }
01131                                    if (VCWD_CHOWN(url_to, sb.st_uid, sb.st_gid)) {
01132                                           if (errno == EPERM) {
01133                                                  php_error_docref2(NULL TSRMLS_CC, url_from, url_to, E_WARNING, "%s", strerror(errno));
01134                                                  VCWD_UNLINK(url_from);
01135                                                  return 1;
01136                                           }
01137                                           php_error_docref2(NULL TSRMLS_CC, url_from, url_to, E_WARNING, "%s", strerror(errno));
01138                                           return 0;
01139                                    }
01140 #  endif
01141                                    VCWD_UNLINK(url_from);
01142                                    return 1;
01143                             }
01144                      }
01145                      php_error_docref2(NULL TSRMLS_CC, url_from, url_to, E_WARNING, "%s", strerror(errno));
01146                      return 0;
01147               }
01148 # endif
01149 #endif
01150 
01151 #ifdef PHP_WIN32
01152               php_win32_docref2_from_error(GetLastError(), url_from, url_to TSRMLS_CC);
01153 #else
01154               php_error_docref2(NULL TSRMLS_CC, url_from, url_to, E_WARNING, "%s", strerror(errno));
01155 #endif
01156               return 0;
01157        }
01158 
01159        /* Clear stat cache (and realpath cache) */
01160        php_clear_stat_cache(1, NULL, 0 TSRMLS_CC);
01161 
01162        return 1;
01163 }
01164 
01165 static int php_plain_files_mkdir(php_stream_wrapper *wrapper, char *dir, int mode, int options, php_stream_context *context TSRMLS_DC)
01166 {
01167        int ret, recursive = options & PHP_STREAM_MKDIR_RECURSIVE;
01168        char *p;
01169 
01170        if ((p = strstr(dir, "://")) != NULL) {
01171               dir = p + 3;
01172        }
01173 
01174        if (!recursive) {
01175               ret = php_mkdir(dir, mode TSRMLS_CC);
01176        } else {
01177               /* we look for directory separator from the end of string, thus hopefuly reducing our work load */
01178               char *e, *buf;
01179               struct stat sb;
01180               int dir_len = strlen(dir);
01181               int offset = 0;
01182 
01183               buf = estrndup(dir, dir_len);
01184 
01185 #ifdef PHP_WIN32
01186               e = buf;
01187               while (*e) {
01188                      if (*e == '/') {
01189                             *e = DEFAULT_SLASH;
01190                      }
01191                      e++;
01192               }
01193 #else
01194               e = buf + dir_len;
01195 #endif
01196 
01197               if ((p = memchr(buf, DEFAULT_SLASH, dir_len))) {
01198                      offset = p - buf + 1;
01199               }
01200 
01201               if (p && dir_len == 1) {
01202                      /* buf == "DEFAULT_SLASH" */       
01203               }
01204               else {
01205                      /* find a top level directory we need to create */
01206                      while ( (p = strrchr(buf + offset, DEFAULT_SLASH)) || (offset != 1 && (p = strrchr(buf, DEFAULT_SLASH))) ) {
01207                             int n = 0;
01208 
01209                             *p = '\0';
01210                             while (p > buf && *(p-1) == DEFAULT_SLASH) {
01211                                    ++n;
01212                                    --p;
01213                                    *p = '\0';
01214                             }
01215                             if (VCWD_STAT(buf, &sb) == 0) {
01216                                    while (1) {
01217                                           *p = DEFAULT_SLASH;
01218                                           if (!n) break;
01219                                           --n;
01220                                           ++p;
01221                                    }
01222                                    break;
01223                             }
01224                      }
01225               }
01226 
01227               if (p == buf) {
01228                      ret = php_mkdir(dir, mode TSRMLS_CC);
01229               } else if (!(ret = php_mkdir(buf, mode TSRMLS_CC))) {
01230                      if (!p) {
01231                             p = buf;
01232                      }
01233                      /* create any needed directories if the creation of the 1st directory worked */
01234                      while (++p != e) {
01235                             if (*p == '\0') {
01236                                    *p = DEFAULT_SLASH;
01237                                    if ((*(p+1) != '\0') &&
01238                                           (ret = VCWD_MKDIR(buf, (mode_t)mode)) < 0) {
01239                                           if (options & REPORT_ERRORS) {
01240                                                  php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
01241                                           }
01242                                           break;
01243                                    }
01244                             }
01245                      }
01246               }
01247               efree(buf);
01248        }
01249        if (ret < 0) {
01250               /* Failure */
01251               return 0;
01252        } else {
01253               /* Success */
01254               return 1;
01255        }
01256 }
01257 
01258 static int php_plain_files_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC)
01259 {
01260 #if PHP_WIN32
01261        int url_len = strlen(url);
01262 #endif
01263        if (PG(safe_mode) &&(!php_checkuid(url, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
01264               return 0;
01265        }
01266 
01267        if (php_check_open_basedir(url TSRMLS_CC)) {
01268               return 0;
01269        }
01270 
01271 #if PHP_WIN32
01272        if (!php_win32_check_trailing_space(url, url_len)) {
01273               php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "%s", strerror(ENOENT));
01274               return 0;
01275        }
01276 #endif
01277 
01278        if (VCWD_RMDIR(url) < 0) {
01279               php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "%s", strerror(errno));
01280               return 0;
01281        }
01282 
01283        /* Clear stat cache (and realpath cache) */
01284        php_clear_stat_cache(1, NULL, 0 TSRMLS_CC);
01285 
01286        return 1;
01287 }
01288 
01289 static php_stream_wrapper_ops php_plain_files_wrapper_ops = {
01290        php_plain_files_stream_opener,
01291        NULL,
01292        NULL,
01293        php_plain_files_url_stater,
01294        php_plain_files_dir_opener,
01295        "plainfile",
01296        php_plain_files_unlink,
01297        php_plain_files_rename,
01298        php_plain_files_mkdir,
01299        php_plain_files_rmdir
01300 };
01301 
01302 php_stream_wrapper php_plain_files_wrapper = {
01303        &php_plain_files_wrapper_ops,
01304        NULL,
01305        0
01306 };
01307 
01308 /* {{{ php_stream_fopen_with_path */
01309 PHPAPI php_stream *_php_stream_fopen_with_path(char *filename, char *mode, char *path, char **opened_path, int options STREAMS_DC TSRMLS_DC)
01310 {
01311        /* code ripped off from fopen_wrappers.c */
01312        char *pathbuf, *ptr, *end;
01313        char *exec_fname;
01314        char trypath[MAXPATHLEN];
01315        php_stream *stream;
01316        int path_length;
01317        int filename_length;
01318        int exec_fname_length;
01319 
01320        if (opened_path) {
01321               *opened_path = NULL;
01322        }
01323 
01324        if(!filename) {
01325               return NULL;
01326        }
01327 
01328        filename_length = strlen(filename);
01329 
01330        /* Relative path open */
01331        if (*filename == '.' && (IS_SLASH(filename[1]) || filename[1] == '.')) {
01332               /* further checks, we could have ....... filenames */
01333               ptr = filename + 1;
01334               if (*ptr == '.') {
01335                      while (*(++ptr) == '.');
01336                      if (!IS_SLASH(*ptr)) { /* not a relative path after all */
01337                             goto not_relative_path;
01338                      }
01339               }
01340 
01341 
01342               if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(filename TSRMLS_CC)) {
01343                      return NULL;
01344               }
01345 
01346               if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) {
01347                      return NULL;
01348               }
01349               return php_stream_fopen_rel(filename, mode, opened_path, options);
01350        }
01351 
01352        /*
01353         * files in safe_mode_include_dir (or subdir) are excluded from
01354         * safe mode GID/UID checks
01355         */
01356 
01357 not_relative_path:
01358 
01359        /* Absolute path open */
01360        if (IS_ABSOLUTE_PATH(filename, filename_length)) {
01361 
01362               if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(filename TSRMLS_CC)) {
01363                      return NULL;
01364               }
01365 
01366               if ((php_check_safe_mode_include_dir(filename TSRMLS_CC)) == 0)
01367                      /* filename is in safe_mode_include_dir (or subdir) */
01368                      return php_stream_fopen_rel(filename, mode, opened_path, options);
01369 
01370               if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM)))
01371                      return NULL;
01372 
01373               return php_stream_fopen_rel(filename, mode, opened_path, options);
01374        }
01375        
01376 #ifdef PHP_WIN32
01377        if (IS_SLASH(filename[0])) {
01378               size_t cwd_len;
01379               char *cwd;
01380               cwd = virtual_getcwd_ex(&cwd_len TSRMLS_CC);
01381               /* getcwd() will return always return [DRIVE_LETTER]:/) on windows. */
01382               *(cwd+3) = '\0';
01383        
01384               if (snprintf(trypath, MAXPATHLEN, "%s%s", cwd, filename) >= MAXPATHLEN) {
01385                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s/%s path was truncated to %d", cwd, filename, MAXPATHLEN);
01386               }
01387               
01388               free(cwd);
01389               
01390               if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(trypath TSRMLS_CC)) {
01391                      return NULL;
01392               }
01393               if ((php_check_safe_mode_include_dir(trypath TSRMLS_CC)) == 0) {
01394                      return php_stream_fopen_rel(trypath, mode, opened_path, options);
01395               }      
01396               if (PG(safe_mode) && (!php_checkuid(trypath, mode, CHECKUID_CHECK_MODE_PARAM))) {
01397                      return NULL;
01398               }
01399               
01400               return php_stream_fopen_rel(trypath, mode, opened_path, options);
01401        }
01402 #endif
01403 
01404        if (!path || (path && !*path)) {
01405               if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) {
01406                      return NULL;
01407               }
01408               return php_stream_fopen_rel(filename, mode, opened_path, options);
01409        }
01410 
01411        /* check in provided path */
01412        /* append the calling scripts' current working directory
01413         * as a fall back case
01414         */
01415        if (zend_is_executing(TSRMLS_C)) {
01416               exec_fname = zend_get_executed_filename(TSRMLS_C);
01417               exec_fname_length = strlen(exec_fname);
01418               path_length = strlen(path);
01419 
01420               while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
01421               if ((exec_fname && exec_fname[0] == '[')
01422                             || exec_fname_length<=0) {
01423                      /* [no active file] or no path */
01424                      pathbuf = estrdup(path);
01425               } else {
01426                      pathbuf = (char *) emalloc(exec_fname_length + path_length +1 +1);
01427                      memcpy(pathbuf, path, path_length);
01428                      pathbuf[path_length] = DEFAULT_DIR_SEPARATOR;
01429                      memcpy(pathbuf+path_length+1, exec_fname, exec_fname_length);
01430                      pathbuf[path_length + exec_fname_length +1] = '\0';
01431               }
01432        } else {
01433               pathbuf = estrdup(path);
01434        }
01435 
01436        ptr = pathbuf;
01437 
01438        while (ptr && *ptr) {
01439               end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
01440               if (end != NULL) {
01441                      *end = '\0';
01442                      end++;
01443               }
01444               if (*ptr == '\0') {
01445                      goto stream_skip;
01446               }
01447               if (snprintf(trypath, MAXPATHLEN, "%s/%s", ptr, filename) >= MAXPATHLEN) {
01448                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s/%s path was truncated to %d", ptr, filename, MAXPATHLEN);
01449               }
01450 
01451               if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir_ex(trypath, 0 TSRMLS_CC)) {
01452                      goto stream_skip;
01453               }
01454               
01455               if (PG(safe_mode)) {
01456                      struct stat sb;
01457 
01458                      if (VCWD_STAT(trypath, &sb) == 0) {
01459                             /* file exists ... check permission */
01460                             if ((php_check_safe_mode_include_dir(trypath TSRMLS_CC) == 0) ||
01461                                           php_checkuid_ex(trypath, mode, CHECKUID_CHECK_MODE_PARAM, CHECKUID_NO_ERRORS)) {
01462                                    /* UID ok, or trypath is in safe_mode_include_dir */
01463                                    stream = php_stream_fopen_rel(trypath, mode, opened_path, options);
01464                                    goto stream_done;
01465                             }
01466                      }
01467                      goto stream_skip;
01468               }
01469               stream = php_stream_fopen_rel(trypath, mode, opened_path, options);
01470               if (stream) {
01471 stream_done:
01472                      efree(pathbuf);
01473                      return stream;
01474               }
01475 stream_skip:
01476               ptr = end;
01477        } /* end provided path */
01478 
01479        efree(pathbuf);
01480        return NULL;
01481 
01482 }
01483 /* }}} */
01484 
01485 /*
01486  * Local variables:
01487  * tab-width: 4
01488  * c-basic-offset: 4
01489  * End:
01490  * vim600: noet sw=4 ts=4 fdm=marker
01491  * vim<600: noet sw=4 ts=4
01492  */