]> granicus.if.org Git - php/commitdiff
Avoid using FILE* unless we have to.
authorWez Furlong <wez@php.net>
Tue, 18 Mar 2003 16:39:06 +0000 (16:39 +0000)
committerWez Furlong <wez@php.net>
Tue, 18 Mar 2003 16:39:06 +0000 (16:39 +0000)
main/php_open_temporary_file.c
main/php_open_temporary_file.h
main/php_streams.h
main/streams.c

index eff0393eb14c39629477bfbb93587d6855b549be..84c8fc0c8d28e25c6329b51014f9b15712bd50f9 100644 (file)
  * SUCH DAMAGE.
  */
 
-static FILE *php_do_open_temporary_file(const char *path, const char *pfx, char **opened_path_p TSRMLS_DC)
+static int php_do_open_temporary_file(const char *path, const char *pfx, char **opened_path_p TSRMLS_DC)
 {
        char *trailing_slash;
-       FILE *fp;
        char *opened_path;
-#ifndef PHP_WIN32
-       int fd;
+       int fd = -1;
+       int open_flags = O_CREAT | O_TRUNC | O_RDWR
+#ifdef PHP_WIN32
+               | _O_BINARY
 #endif
+               ;
 #ifdef NETWARE
     char *file_path = NULL;
 #endif
 
        if (!path) {
-               return NULL;
+               return -1;
        }
 
        if (!(opened_path = emalloc(MAXPATHLEN))) {
-               return NULL;
+               return -1;
        }
 
        if (IS_SLASH(path[strlen(path)-1])) {
@@ -132,38 +134,27 @@ static FILE *php_do_open_temporary_file(const char *path, const char *pfx, char
 
 #ifdef PHP_WIN32
        if (GetTempFileName(path, pfx, 0, opened_path)) {
-               fp = VCWD_FOPEN(opened_path, "r+b");
-       } else {
-               fp = NULL;
+               fd = VCWD_OPEN(opened_path, open_flags);
        }
 #elif defined(NETWARE)
        /* Using standard mktemp() implementation for NetWare */
        file_path = mktemp(opened_path);
        if (file_path) {
-               fp = VCWD_FOPEN(file_path, "r+b");
-       } else {
-               fp = NULL;
+               fd = VCWD_OPEN(file_path, open_flags);
        }
 #elif defined(HAVE_MKSTEMP)
        fd = mkstemp(opened_path);
-       if (fd==-1) {
-               fp = NULL;
-       } else {
-               fp = fdopen(fd, "r+b");
-       }
 #else
        if (mktemp(opened_path)) {
-               fp = VCWD_FOPEN(opened_path, "r+b");
-       } else {
-               fp = NULL;
+               fd = VCWD_OPEN(opened_path, open_flags);
        }
 #endif
-       if (!fp || !opened_path_p) {
+       if (fd == -1 || !opened_path_p) {
                efree(opened_path);
        } else {
                *opened_path_p = opened_path;
        }
-       return fp;
+       return fd;
 }
 /* }}} */
 
@@ -222,9 +213,9 @@ const char* get_temporary_directory()
  * This function should do its best to return a file pointer to a newly created
  * unique file, on every platform.
  */
-PHPAPI FILE *php_open_temporary_file(const char *dir, const char *pfx, char **opened_path_p TSRMLS_DC)
+PHPAPI int php_open_temporary_fd(const char *dir, const char *pfx, char **opened_path_p TSRMLS_DC)
 {
-       FILE* fp = 0;
+       int fd;
 
        if (!pfx) {
                pfx = "tmp.";
@@ -234,18 +225,29 @@ PHPAPI FILE *php_open_temporary_file(const char *dir, const char *pfx, char **op
        }
 
        /* Try the directory given as parameter. */
-       fp = php_do_open_temporary_file(dir, pfx, opened_path_p TSRMLS_CC);
-       if (fp) {
-               return fp;
+       fd = php_do_open_temporary_file(dir, pfx, opened_path_p TSRMLS_CC);
+       if (fd == -1) {
+               /* Use default temporary directory. */
+               fd = php_do_open_temporary_file(get_temporary_directory(), pfx, opened_path_p TSRMLS_CC);
        }
+       return fd;
+}
 
-       /* Use default temporary directory. */
-       fp = php_do_open_temporary_file(get_temporary_directory(), pfx, opened_path_p TSRMLS_CC);
-       if (fp) {
-               return fp;
-       }
+PHPAPI FILE *php_open_temporary_file(const char *dir, const char *pfx, char **opened_path_p TSRMLS_DC)
+{
+       FILE *fp;
+       int fd = php_open_temporary_fd(dir, pfx, opened_path_p TSRMLS_CC);
 
-       return 0;
+       if (fd == -1) {
+               return NULL;
+       }
+       
+       fp = fdopen(fd, "r+b");
+       if (fp == NULL) {
+               close(fd);
+       }
+       
+       return fp;
 }
 /* }}} */
 
index 84e19f4c8d2ec23994f8efaf8824ad09d08c24f4..dc46d22bdd6bfb0b456c6481a2fdef0c6a0a8426 100644 (file)
@@ -20,5 +20,6 @@
 #define PHP_OPEN_TEMPORARY_FILE_H
 
 PHPAPI FILE *php_open_temporary_file(const char *dir, const char *pfx, char **opened_path_p TSRMLS_DC);
+PHPAPI int php_open_temporary_fd(const char *dir, const char *pfx, char **opened_path_p TSRMLS_DC);
 
 #endif /* PHP_OPEN_TEMPORARY_FILE_H */
index 3147a21c7543bb6d4609157d9eeefb5c1f93ca3e..1c9ff46156f99ebb95e4884c4c8e4e5f50e77237 100755 (executable)
@@ -65,6 +65,7 @@ PHPAPI int php_file_le_pstream(void);
 #define php_stream_fopen_with_path_rel(filename, mode, path, opened, options) _php_stream_fopen_with_path((filename), (mode), (path), (opened), (options) STREAMS_REL_CC TSRMLS_CC)
 
 #define php_stream_fopen_from_file_rel(file, mode)      _php_stream_fopen_from_file((file), (mode) STREAMS_REL_CC TSRMLS_CC)
+#define php_stream_fopen_from_fd_rel(fd, mode)         _php_stream_fopen_from_fd((fd), (mode) STREAMS_REL_CC TSRMLS_CC)
        
 #define php_stream_fopen_from_pipe_rel(file, mode)      _php_stream_fopen_from_pipe((file), (mode) STREAMS_REL_CC TSRMLS_CC)
        
@@ -439,6 +440,9 @@ PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, cha
 PHPAPI php_stream *_php_stream_fopen_with_path(char *filename, char *mode, char *path, char **opened_path, int options STREAMS_DC TSRMLS_DC);
 #define php_stream_fopen_with_path(filename, mode, path, opened)       _php_stream_fopen_with_path((filename), (mode), (path), (opened) STREAMS_CC TSRMLS_CC)
 
+PHPAPI php_stream *_php_stream_fopen_from_fd(int fd, const char *mode STREAMS_DC TSRMLS_DC);
+#define php_stream_fopen_from_fd(fd, mode)  _php_stream_fopen_from_fd((fd), (mode) STREAMS_CC TSRMLS_CC)
+
 PHPAPI php_stream *_php_stream_fopen_from_file(FILE *file, const char *mode STREAMS_DC TSRMLS_DC);
 #define php_stream_fopen_from_file(file, mode) _php_stream_fopen_from_file((file), (mode) STREAMS_CC TSRMLS_CC)
 
index e051b62acf796887259b271b4e86d63390c83ff4..58cd55bf1d094678bf22e81d1c1fb17cf0b3b977 100755 (executable)
@@ -53,6 +53,8 @@
 #define STREAM_DEBUG 0
 #define STREAM_WRAPPER_PLAIN_FILES     ((php_stream_wrapper*)-1)
 
+#define PHP_STDIOP_GET_FD(anfd, data)   anfd = (data)->file ? fileno((data)->file) : (data)->fd
+
 /* {{{ some macros to help track leaks */
 #if ZEND_DEBUG
 #define emalloc_rel_orig(size) \
@@ -1290,14 +1292,14 @@ typedef struct {
 
 PHPAPI php_stream *_php_stream_fopen_temporary_file(const char *dir, const char *pfx, char **opened_path STREAMS_DC TSRMLS_DC)
 {
-       FILE *fp = php_open_temporary_file(dir, pfx, opened_path TSRMLS_CC);
+       int fd = php_open_temporary_fd(dir, pfx, opened_path TSRMLS_CC);
 
-       if (fp) {
-               php_stream *stream = php_stream_fopen_from_file_rel(fp, "r+b");
+       if (fd != -1)   {
+               php_stream *stream = php_stream_fopen_from_fd_rel(fd, "r+b");
                if (stream) {
                        return stream;
                }
-               fclose(fp);
+               close(fd);
 
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to allocate stream");
 
@@ -1309,17 +1311,17 @@ PHPAPI php_stream *_php_stream_fopen_temporary_file(const char *dir, const char
 PHPAPI php_stream *_php_stream_fopen_tmpfile(int dummy STREAMS_DC TSRMLS_DC)
 {
        char *opened_path = NULL;
-       FILE *fp = php_open_temporary_file(NULL, "php", &opened_path TSRMLS_CC);
+       int fd = php_open_temporary_fd(NULL, "php", &opened_path TSRMLS_CC);
 
-       if (fp) {
-               php_stream *stream = php_stream_fopen_from_file_rel(fp, "r+b");
+       if (fd != -1)   {
+               php_stream *stream = php_stream_fopen_from_fd_rel(fd, "r+b");
                if (stream) {
                        php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
 
                        self->temp_file_name = opened_path;
                        return stream;
                }
-               fclose(fp);
+               close(fd);
 
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to allocate stream");
 
@@ -1412,7 +1414,7 @@ static size_t php_stdiop_write(php_stream *stream, const char *buf, size_t count
 static size_t php_stdiop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
 {
        php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
-       size_t ret;
+       int ret;
 
        assert(data != NULL);
 
@@ -1434,7 +1436,7 @@ static size_t php_stdiop_read(php_stream *stream, char *buf, size_t count TSRMLS
                if (feof(data->file))
                        stream->eof = 1;
        }
-       return ret;
+       return ret < 0 ? 0 : ret;
 }
 
 static int php_stdiop_close(php_stream *stream, int close_handle TSRMLS_DC)
@@ -1535,16 +1537,17 @@ static int php_stdiop_cast(php_stream *stream, int castas, void **ret TSRMLS_DC)
        switch (castas) {
                case PHP_STREAM_AS_STDIO:
                        if (ret) {
+                               if (data->file == NULL) {
+                                       data->file = fdopen(data->fd, stream->mode);
+                               }
                                *(FILE**)ret = data->file;
                                data->fd = -1;
                        }
                        return SUCCESS;
 
                case PHP_STREAM_AS_FD:
-                       /* fetch the fileno rather than using data->fd, since we may
-                        * have zeroed that member if someone requested the FILE*
-                        * first (see above case) */
-                       fd = fileno(data->file);
+                       PHP_STDIOP_GET_FD(fd, data);
+
                        if (fd < 0) {
                                return FAILURE;
                        }
@@ -1565,7 +1568,7 @@ static int php_stdiop_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC
 
        assert(data != NULL);
 
-       fd = fileno(data->file);
+       PHP_STDIOP_GET_FD(fd, data);
 
        return fstat(fd, &ssb->sb);
 }
@@ -1581,10 +1584,10 @@ static int php_stdiop_set_option(php_stream *stream, int option, int value, void
        int oldval;
 #endif
        
+       PHP_STDIOP_GET_FD(fd, data);
+       
        switch(option) {
                case PHP_STREAM_OPTION_BLOCKING:
-                       fd = fileno(data->file);
-
                        if (fd == -1)
                                return -1;
 #ifdef O_NONBLOCK
@@ -1658,7 +1661,7 @@ PHPAPI php_stream *_php_stream_fopen_with_path(char *filename, char *mode, char
                *opened_path = NULL;
        }
 
-       if(!filename) {
+       if (!filename) {
                return NULL;
        }
 
@@ -1690,7 +1693,7 @@ PHPAPI php_stream *_php_stream_fopen_with_path(char *filename, char *mode, char
         * safe mode GID/UID checks
         */
 
-       not_relative_path:
+not_relative_path:
 
        /* Absolute path open */
        if (IS_ABSOLUTE_PATH(filename, filename_length)) {
@@ -1806,7 +1809,7 @@ PHPAPI php_stream *_php_stream_fopen_with_path(char *filename, char *mode, char
                }
                stream = php_stream_fopen_rel(trypath, mode, opened_path, options);
                if (stream) {
-                       stream_done:
+stream_done:
                        efree(pathbuf);
                        return stream;
                }
@@ -1823,21 +1826,71 @@ PHPAPI php_stream *_php_stream_fopen_with_path(char *filename, char *mode, char
 #define S_ISREG(mode)  (((mode)&S_IFMT) == S_IFREG)
 #endif
 
+/* parse standard "fopen" modes into open() flags */
+PHPAPI int php_stream_parse_fopen_modes(const char *mode, int *open_flags)
+{
+       int flags;
+
+       switch (mode[0]) {
+               case 'r':
+                       flags = 0;
+                       break;
+               case 'w':
+                       flags = O_TRUNC|O_CREAT;
+                       break;
+               case 'a':
+                       flags = O_CREAT|O_APPEND;
+                       break;
+               case 'x':
+                       flags = O_CREAT|O_EXCL;
+                       break;
+               default:
+                       /* unknown mode */
+                       return FAILURE;
+       }
+
+       if (strchr(mode, '+')) {
+               flags |= O_RDWR;
+       } else if (flags) {
+               flags |= O_WRONLY;
+       } else {
+               flags |= O_RDONLY;
+       }
+
+#ifdef O_BINARY
+       if (strchr(mode, 'b')) {
+               flags |= O_BINARY;
+       }
+#endif
+
+       *open_flags = flags;
+       return SUCCESS;
+}
+
+
 /* {{{ php_stream_fopen */
 PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, char **opened_path, int options STREAMS_DC TSRMLS_DC)
 {
-       FILE *fp;
        char *realpath = NULL;
        struct stat st;
+       int open_flags;
+       int fd;
        php_stream *ret;
 
+       if (FAILURE == php_stream_parse_fopen_modes(mode, &open_flags)) {
+               if (options & REPORT_ERRORS) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "`%s' is not a valid mode for fopen", mode);
+               }
+               return NULL;
+       }
+
        realpath = expand_filepath(filename, NULL TSRMLS_CC);
 
-       fp = fopen(realpath, mode);
+       fd = open(realpath, open_flags, 0666);
 
-       if (fp) {
+       if (fd != -1)   {
                /* sanity checks for include/require */
-               if (options & STREAM_OPEN_FOR_INCLUDE && (fstat(fileno(fp), &st) == -1 || !S_ISREG(st.st_mode))) {
+               if (options & STREAM_OPEN_FOR_INCLUDE && (fstat(fd, &st) == -1 || !S_ISREG(st.st_mode))) {
 #ifdef PHP_WIN32
                        /* skip the sanity check; fstat doesn't appear to work on
                         * UNC paths */
@@ -1846,7 +1899,7 @@ PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, cha
                                goto err;
                } 
        
-               ret = php_stream_fopen_from_file_rel(fp, mode);
+               ret = php_stream_fopen_from_fd_rel(fd, mode);
 
                if (ret)        {
                        if (opened_path)        {
@@ -1859,13 +1912,57 @@ PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, cha
                        return ret;
                }
 err:
-               fclose(fp);
+               close(fd);
        }
        efree(realpath);
        return NULL;
 }
 /* }}} */
 
+PHPAPI php_stream *_php_stream_fopen_from_fd(int fd, const char *mode STREAMS_DC TSRMLS_DC)
+{
+       php_stdio_stream_data *self;
+       php_stream *stream;
+
+       self = emalloc_rel_orig(sizeof(*self));
+       memset(self, 0, sizeof(*self));
+       self->file = NULL;
+       self->is_pipe = 0;
+       self->is_process_pipe = 0;
+       self->temp_file_name = NULL;
+       self->fd = fd;
+
+#ifdef S_ISFIFO
+       /* detect if this is a pipe */
+       if (self->fd >= 0) {
+               struct stat sb;
+               self->is_pipe = (fstat(self->fd, &sb) == 0 && S_ISFIFO(sb.st_mode)) ? 1 : 0;
+       }
+#elif defined(PHP_WIN32)
+       {
+               long handle = _get_osfhandle(self->fd);
+               DWORD in_buf_size, out_buf_size;
+
+               if (handle != 0xFFFFFFFF) {
+                       self->is_pipe = GetNamedPipeInfo((HANDLE)handle, NULL, &out_buf_size, &in_buf_size, NULL);
+               }
+       }
+#endif
+
+       stream = php_stream_alloc_rel(&php_stream_stdio_ops, self, 0, mode);
+
+       if (stream) {
+               if (self->is_pipe) {
+                       stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
+               } else {
+                       stream->position = lseek(self->fd, 0, SEEK_CUR);
+               }
+       }
+
+       return stream;
+}
+
+
 /* {{{ STDIO with fopencookie */
 #if HAVE_FUNOPEN
 /* use our fopencookie emulation */