]> granicus.if.org Git - php/commitdiff
Fix for php_stream_gets when the implementation does not support it
authorWez Furlong <wez@php.net>
Sun, 17 Mar 2002 14:21:01 +0000 (14:21 +0000)
committerWez Furlong <wez@php.net>
Sun, 17 Mar 2002 14:21:01 +0000 (14:21 +0000)
natively (Thanks Marcus).

Implement php_stream_make_seekable() and add STREAM_MUST_SEEK as an
option to php_stream_open_wrapper().
See README.STREAMS for usage.

README.STREAMS
main/fopen_wrappers.h
main/php_streams.h
main/streams.c

index 897d40db4e8837f03ebf6f798eb3d8d8f57e5d4b..6100c8b272eac6b73985ad7a83a9c873c2c2c903 100644 (file)
@@ -51,7 +51,16 @@ Where:
         IGNORE_URL      - do not use plugin wrappers
         REPORT_ERRORS   - show errors in a standard format if something
                           goes wrong.
-    opened_path is used to return the path of the actual file opened.
+        STREAM_MUST_SEEK - If you really need to be able to seek the stream
+                           and don't need to be able to write to the original
+                           file/URL, use this option to arrange for the stream
+                           to be copied (if needed) into a stream that can
+                           be seek()ed.
+                           
+    opened_path is used to return the path of the actual file opened,
+    but if you used STREAM_MUST_SEEK, may not be valid.  You are
+    responsible for efree()ing opened_path.  opened_path may be (and usually
+    is) NULL.
 
 If you need to open a specific stream, or convert standard resources into
 streams there are a range of functions to do this defined in php_streams.h.
@@ -109,6 +118,39 @@ The buffer is allocated using pemalloc(); you need to call pefree() to
 release the memory when you are done.
 As with copy_to_stream, this function will try use mmap where it can.
 
+If you have an existing stream and need to be able to seek() it, you
+can use this function to copy the contents into a new stream that can
+be seek()ed:
+
+PHPAPI int php_stream_make_seekable(php_stream *origstream, php_stream **newstream);
+
+It returns one of the following values:
+#define PHP_STREAM_UNCHANGED   0 /* orig stream was seekable anyway */
+#define PHP_STREAM_RELEASED            1 /* newstream should be used; origstream is no longer valid */
+#define PHP_STREAM_FAILED              2 /* an error occurred while attempting conversion */
+#define PHP_STREAM_CRITICAL            3 /* an error occurred; origstream is in an unknown state; you should close origstream */
+
+make_seekable will always set newstream to be the stream that is valid
+if the function succeeds.
+When you have finished, remember to close the stream.
+
+NOTE: If you only need to seek forwards, there is no need to call this
+function, as the php_stream_seek can emulate forward seeking when the
+whence parameter is SEEK_CUR.
+
+NOTE: Writing to the stream may not affect the original source, so it
+only makes sense to use this for read-only use.
+
+NOTE: If the origstream is network based, this function will block
+until the whole contents have been downloaded.
+
+NOTE: Never call this function with an origstream that is referenced
+as a resource! It will close the origstream on success, and this
+can lead to a crash when the resource is later used/released.
+
+NOTE: If you are opening a stream and need it to be seekable, use the
+STREAM_MUST_SEEK option to php_stream_open_wrapper();
+
 Casting Streams
 ===============
 What if your extension needs to access the FILE* of a user level file pointer?
index f64efd40c8f3b04607ca40500094a31bb956b485..1a9ca6cc3a894a02f9674934b0be9a48918f7344 100644 (file)
 
 #include "php_globals.h"
 
-#define IGNORE_PATH            0
-#define USE_PATH               1
-#define IGNORE_URL             2
-/* There's no USE_URL. */
-#define ENFORCE_SAFE_MODE 4
-#define REPORT_ERRORS  8
-
-#ifdef PHP_WIN32
-# define IGNORE_URL_WIN IGNORE_URL
-#else
-# define IGNORE_URL_WIN 0
-#endif
-
 PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle TSRMLS_DC);
 PHPAPI char *expand_filepath(const char *filepath, char *real_path TSRMLS_DC);
 
index 65a83c803614a177ae8046ee34bdb782db3d50e0..402156c33508eb913f224ae47e09f65f145574cf 100755 (executable)
@@ -146,13 +146,36 @@ PHPAPI int php_stream_cast(php_stream *stream, int castas, void **ret, int show_
 #define php_stream_is_persistent(stream)       (stream)->is_persistent
 
 /* Wrappers support */
+
+#define IGNORE_PATH                    0
+#define USE_PATH                       1
+#define IGNORE_URL                     2
+/* There's no USE_URL. */
+#define ENFORCE_SAFE_MODE      4
+#define REPORT_ERRORS          8
+/* If you don't need to write to the stream, but really need to
+ * be able to seek, use this flag in your options. */
+#define STREAM_MUST_SEEK       16
+
+#ifdef PHP_WIN32
+# define IGNORE_URL_WIN IGNORE_URL
+#else
+# define IGNORE_URL_WIN 0
+#endif
+
 int php_init_stream_wrappers(TSRMLS_D);
 int php_shutdown_stream_wrappers(TSRMLS_D);
 PHPAPI int php_register_url_stream_wrapper(char *protocol, php_stream_wrapper *wrapper TSRMLS_DC);
 PHPAPI int php_unregister_url_stream_wrapper(char *protocol TSRMLS_DC);
-
 PHPAPI php_stream *php_stream_open_wrapper(char *path, char *mode, int options, char **opened_path TSRMLS_DC);
 
+#define PHP_STREAM_UNCHANGED   0 /* orig stream was seekable anyway */
+#define PHP_STREAM_RELEASED            1 /* newstream should be used; origstream is no longer valid */
+#define PHP_STREAM_FAILED              2 /* an error occurred while attempting conversion */
+#define PHP_STREAM_CRITICAL            3 /* an error occurred; origstream is in an unknown state; you should close origstream */
+/* DO NOT call this on streams that are referenced by resources! */
+PHPAPI int php_stream_make_seekable(php_stream *origstream, php_stream **newstream);
+
 #endif
 
 /*
index e84f6804b305c71141e8908d53c1a5ac9dac2f49..b67bc837fe171c0503d07c1df22e0d0c32e7dedc 100755 (executable)
@@ -166,7 +166,7 @@ PHPAPI char *php_stream_gets(php_stream *stream, char *buf, size_t maxlen)
                return stream->ops->gets(stream, buf, maxlen);
        } else {
                /* unbuffered fgets - poor performance ! */
-               size_t n = 0;
+               size_t n = 1;
                char *c = buf;
 
                /* TODO: look at error returns? */
@@ -944,7 +944,7 @@ PHPAPI php_stream *php_stream_open_wrapper(char *path, char *mode, int options,
                goto out;
        }
 
-       if ((options & USE_PATH) && PG(include_path) != NULL)   {
+       if ((options & USE_PATH) && PG(include_path) != NULL) {
                stream = php_stream_fopen_with_path(path, mode, PG(include_path), opened_path TSRMLS_CC);
                goto out;
        }
@@ -954,7 +954,29 @@ PHPAPI php_stream *php_stream_open_wrapper(char *path, char *mode, int options,
 
        stream = php_stream_fopen(path, mode, opened_path TSRMLS_CC);
 out:
-       if (stream == NULL && (options & REPORT_ERRORS))        {
+       if (stream != NULL && (options & STREAM_MUST_SEEK)) {
+               php_stream *newstream;
+
+               switch(php_stream_make_seekable(stream, &newstream)) {
+                       case PHP_STREAM_UNCHANGED:
+                               return stream;
+                       case PHP_STREAM_RELEASED:
+                               return newstream;
+                       default:
+                               php_stream_close(stream);
+                               stream = NULL;
+                               if (options & REPORT_ERRORS) {
+                                       char *tmp = estrdup(path);
+                                       php_strip_url_passwd(tmp);
+                                       zend_error(E_WARNING, "%s(\"%s\") - could not make seekable - %s",
+                                                       get_active_function_name(TSRMLS_C), tmp, strerror(errno));
+                                       efree(tmp);
+
+                                       options ^= REPORT_ERRORS;
+                               }
+               }
+       }
+       if (stream == NULL && (options & REPORT_ERRORS)) {
                char *tmp = estrdup(path);
                php_strip_url_passwd(tmp);
                zend_error(E_WARNING, "%s(\"%s\") - %s", get_active_function_name(TSRMLS_C), tmp, strerror(errno));
@@ -963,6 +985,34 @@ out:
        return stream;
 }
 
+PHPAPI int php_stream_make_seekable(php_stream *origstream, php_stream **newstream)
+{
+       assert(newstream != NULL);
+
+       *newstream = NULL;
+       
+       if (origstream->ops->seek != NULL) {
+               *newstream = origstream;
+               return PHP_STREAM_UNCHANGED;
+       }
+       
+       /* Use a tmpfile and copy the old streams contents into it */
+
+       *newstream = php_stream_fopen_tmpfile();
+
+       if (*newstream == NULL)
+               return PHP_STREAM_FAILED;
+
+       if (php_stream_copy_to_stream(origstream, *newstream, PHP_STREAM_COPY_ALL) == 0) {
+               php_stream_close(*newstream);
+               *newstream = NULL;
+               return PHP_STREAM_CRITICAL;
+       }
+
+       php_stream_close(origstream);
+
+       return PHP_STREAM_RELEASED;
+}
 
 /*
  * Local variables: