root/main/streams/plain_wrapper.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_stream_parse_fopen_modes
  2. do_fstat
  3. _php_stream_fopen_from_fd_int
  4. _php_stream_fopen_from_file_int
  5. _php_stream_fopen_temporary_file
  6. _php_stream_fopen_tmpfile
  7. _php_stream_fopen_from_fd
  8. _php_stream_fopen_from_file
  9. _php_stream_fopen_from_pipe
  10. php_stdiop_write
  11. php_stdiop_read
  12. php_stdiop_close
  13. php_stdiop_flush
  14. php_stdiop_seek
  15. php_stdiop_cast
  16. php_stdiop_stat
  17. php_stdiop_set_option
  18. php_plain_files_dirstream_read
  19. php_plain_files_dirstream_close
  20. php_plain_files_dirstream_rewind
  21. php_plain_files_dir_opener
  22. _php_stream_fopen
  23. php_plain_files_stream_opener
  24. php_plain_files_url_stater
  25. php_plain_files_unlink
  26. php_plain_files_rename
  27. php_plain_files_mkdir
  28. php_plain_files_rmdir
  29. php_plain_files_metadata
  30. _php_stream_fopen_with_path

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

/* [<][>][^][v][top][bottom][index][help] */