* 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])) {
#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;
}
/* }}} */
* 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.";
}
/* 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;
}
/* }}} */
#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)
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)
#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) \
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");
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");
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);
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)
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;
}
assert(data != NULL);
- fd = fileno(data->file);
+ PHP_STDIOP_GET_FD(fd, data);
return fstat(fd, &ssb->sb);
}
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
*opened_path = NULL;
}
- if(!filename) {
+ if (!filename) {
return NULL;
}
* safe mode GID/UID checks
*/
- not_relative_path:
+not_relative_path:
/* Absolute path open */
if (IS_ABSOLUTE_PATH(filename, filename_length)) {
}
stream = php_stream_fopen_rel(trypath, mode, opened_path, options);
if (stream) {
- stream_done:
+stream_done:
efree(pathbuf);
return stream;
}
#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 */
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) {
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 */