On Fri, Aug 30, 2013 at 4:52 PM, Johannes Schlüter
<johan...@schlueters.de> wrote:
>
> On Fri, 2013-08-30 at 16:43 +0200, X Ryl wrote:
> > Hi,
> >
> >
> >   Please find attached a patch for adding large file size support to
> > PHP 5.5.1.
>
> The patch didn't make it. Please send as text/plain (i.e. using .txt
> extension)


Done.

>
>
> > It does so by, from the PHP's side, getting double instead of int for
> > the file size/ offset functions, when the size is larger than 2^31.
>
> This has some problems - for further handling onemight need the exact
> file size (i.e. content length headers, checking structures, reading
> specific positions)
>
> > This means that files with size:
> > - up to 2^32 bytes works as previously (integer returned / used)
> > - up to 2^52 bytes can be handled correctly (double's mantissa is 52
> > bits, no loss in precision here)
>
> This might work for the initial operation, but as soon as the user does
> a calculation ("give me the last ten bytes") this will cause issues.

No it won't. double mantissa are integers, works like integer.
So you have the complete 52 bits of precision here, not a single
rounding error can occur.
The exponent in that case will be 0, so "2^0 * integer_with_52_bits"
is still an integer with 52 bits of precision.

So the "filesize - 10" is still exact as long as the filesize is less
than 2^52 (see below when it's larger)



>
> > - from 2^52 up to 2^64 will have their size rounded, yet, reading and
> > writing will work as expected since it's done in the PHP's binary.

I'll try to improve this, since it's causing misunderstanding.
Typically, when you start storing a value that does not fit in 52
bits, it's shifted (understand: round to the closed multiple of two)
until it fits the range.
So for example, a file size that's "2^53 + 203" will be stored as
9007199254741196 instead of 9007199254741195 (the error is 1 here)

Yet, the reported value will be wrong, but if you seek close to the
end position and read it you'll still be able to read it completely
(since the <wrong> double value will be converted back to <wrong>
64-bit integer in the C code). As long as you're dealing with
positions/seek in a multiple of 2^52, you'll be fine.
So if you need 100% correct value for such a large file, you can still
do it by looping, AT WORST, 4096 times ( = 2^64 / 2^52) a seek with
SEEK_CUR.
Not a real showstopper when the current version does not even allow
you to know the actual size of the file, not even speaking of reading
it!)

If you either have to handle such large file NOW, then chance are high
you're already using a 64 bits system.
This patch if for us, poor souls, struck with 32 bits system, yet
wanting to report correct size for our movies in our web-based file
manager, wanting to stream correctly such files and so on.

> >
> >
> > The changes are:
> > - Some size_t are changed to off_t wherever required.
>
> This disqualifies from 5.5 and allows use in 5.6 only.

Ok
Cyril
diff -ur php-5.5.1/ext/phar/phar_internal.h 
php-5.5.1.new/ext/phar/phar_internal.h
--- php-5.5.1/ext/phar/phar_internal.h  2013-07-18 16:37:33.000000000 +0200
+++ php-5.5.1.new/ext/phar/phar_internal.h      2013-08-15 10:42:39.332887601 
+0200
@@ -534,8 +534,15 @@
        return FAILURE;
 }
 #else
-# define phar_stream_copy_to_stream(src, dest, maxlen, len)    
_php_stream_copy_to_stream_ex((src), (dest), (maxlen), (len) STREAMS_CC 
TSRMLS_CC)
-
+static inline size_t phar_stream_copy_to_stream(php_stream *src, php_stream 
*dest, size_t maxlen, size_t *len)
+{
+       off_t _maxlen = maxlen == (size_t)PHP_STREAM_COPY_ALL ? 
PHP_STREAM_COPY_ALL : maxlen, _len = 0;
+       size_t ret = php_stream_copy_to_stream_ex(src, dest, _maxlen, &_len);
+       if (ret == SUCCESS) {
+               if (len) *len = (size_t)_len;
+       } else if (len) *len = 0;
+       return ret;
+}
 #endif
 
 #if PHP_VERSION_ID >= 60000
diff -ur php-5.5.1/ext/standard/file.c php-5.5.1.new/ext/standard/file.c
--- php-5.5.1/ext/standard/file.c       2013-07-18 16:37:33.000000000 +0200
+++ php-5.5.1.new/ext/standard/file.c   2013-08-15 10:42:39.432888125 +0200
@@ -570,7 +570,7 @@
        char *filename;
        int filename_len;
        zval *data;
-       int numbytes = 0;
+       off_t numbytes = 0;
        long flags = 0;
        zval *zcontext = NULL;
        php_stream_context *context = NULL;
@@ -618,7 +618,7 @@
 
        switch (Z_TYPE_P(data)) {
                case IS_RESOURCE: {
-                       size_t len;
+                       off_t len;
                        if (php_stream_copy_to_stream_ex(srcstream, stream, 
PHP_STREAM_COPY_ALL, &len) != SUCCESS) {
                                numbytes = -1;
                        } else {
@@ -635,9 +635,9 @@
 
                case IS_STRING:
                        if (Z_STRLEN_P(data)) {
-                               numbytes = php_stream_write(stream, 
Z_STRVAL_P(data), Z_STRLEN_P(data));
-                               if (numbytes != Z_STRLEN_P(data)) {
-                                       php_error_docref(NULL TSRMLS_CC, 
E_WARNING, "Only %d of %d bytes written, possibly out of free disk space", 
numbytes, Z_STRLEN_P(data));
+                               numbytes = (off_t)php_stream_write(stream, 
Z_STRVAL_P(data), Z_STRLEN_P(data));
+                               if (numbytes != (off_t)Z_STRLEN_P(data)) {
+                                       php_error_docref(NULL TSRMLS_CC, 
E_WARNING, "Only %d of %d bytes written, possibly out of free disk space", 
(size_t)numbytes, Z_STRLEN_P(data));
                                        numbytes = -1;
                                }
                        }
@@ -656,13 +656,13 @@
                                                convert_to_string(*tmp);
                                        }
                                        if (Z_STRLEN_PP(tmp)) {
-                                               numbytes += Z_STRLEN_PP(tmp);
+                                               numbytes += 
(off_t)Z_STRLEN_PP(tmp);
                                                bytes_written = 
php_stream_write(stream, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
                                                if (bytes_written < 0 || 
bytes_written != Z_STRLEN_PP(tmp)) {
                                                        if (bytes_written < 0) {
                                                                
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write %d bytes to %s", 
Z_STRLEN_PP(tmp), filename);
                                                        } else {
-                                                               
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Only %d of %d bytes written, 
possibly out of free disk space", bytes_written, Z_STRLEN_PP(tmp));
+                                                               
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Only %d of %d bytes written, 
possibly out of free disk space", (size_t)bytes_written, Z_STRLEN_PP(tmp));
                                                        }
                                                        numbytes = -1;
                                                        break;
@@ -678,9 +678,9 @@
                                zval out;
 
                                if (zend_std_cast_object_tostring(data, &out, 
IS_STRING TSRMLS_CC) == SUCCESS) {
-                                       numbytes = php_stream_write(stream, 
Z_STRVAL(out), Z_STRLEN(out));
-                                       if (numbytes != Z_STRLEN(out)) {
-                                               php_error_docref(NULL 
TSRMLS_CC, E_WARNING, "Only %d of %d bytes written, possibly out of free disk 
space", numbytes, Z_STRLEN(out));
+                                       numbytes = 
(off_t)php_stream_write(stream, Z_STRVAL(out), Z_STRLEN(out));
+                                       if (numbytes != (off_t)Z_STRLEN(out)) {
+                                               php_error_docref(NULL 
TSRMLS_CC, E_WARNING, "Only %d of %d bytes written, possibly out of free disk 
space", (size_t)numbytes, Z_STRLEN(out));
                                                numbytes = -1;
                                        }
                                        zval_dtor(&out);
@@ -697,7 +697,11 @@
                RETURN_FALSE;
        }
 
-       RETURN_LONG(numbytes);
+        if (numbytes > LONG_MAX) {
+               RETURN_DOUBLE((double)numbytes);
+       } else {
+               RETURN_LONG(numbytes);
+       }
 }
 /* }}} */
 
@@ -1245,7 +1249,7 @@
 PHPAPI PHP_FUNCTION(ftell)
 {
        zval *arg1;
-       long ret;
+       off_t ret;
        php_stream *stream;
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == 
FAILURE) {
@@ -1258,7 +1262,11 @@
        if (ret == -1)  {
                RETURN_FALSE;
        }
-       RETURN_LONG(ret);
+        if (ret > LONG_MAX) {
+               RETURN_DOUBLE((double)ret);
+       } else {
+               RETURN_LONG(ret);
+       }
 }
 /* }}} */
 
@@ -1351,7 +1359,7 @@
 {
        char *filename;
        int filename_len;
-       int size = 0;
+       off_t size = 0;
        zend_bool use_include_path = 0;
        zval *zcontext = NULL;
        php_stream *stream;
@@ -1367,7 +1375,11 @@
        if (stream) {
                size = php_stream_passthru(stream);
                php_stream_close(stream);
-               RETURN_LONG(size);
+               if (size > LONG_MAX) {
+                       RETURN_DOUBLE((double)size);
+               } else {
+                       RETURN_LONG(size);
+               }
        }
 
        RETURN_FALSE;
@@ -1406,7 +1418,7 @@
 PHPAPI PHP_FUNCTION(fpassthru)
 {
        zval *arg1;
-       int size;
+       off_t size;
        php_stream *stream;
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == 
FAILURE) {
@@ -1416,7 +1428,11 @@
        PHP_STREAM_TO_ZVAL(stream, &arg1);
 
        size = php_stream_passthru(stream);
-       RETURN_LONG(size);
+       if (size > LONG_MAX) {
+               RETURN_DOUBLE((double)size);
+       } else {
+               RETURN_LONG(size);
+       }
 }
 /* }}} */
 
@@ -1548,7 +1564,11 @@
 #else
        MAKE_LONG_ZVAL_INCREF(stat_rdev, -1);
 #endif
-       MAKE_LONG_ZVAL_INCREF(stat_size, stat_ssb.sb.st_size);
+        if (stat_ssb.sb.st_size > LONG_MAX) {
+               MAKE_DOUBLE_ZVAL_INCREF(stat_size, (double)stat_ssb.sb.st_size);
+        } else {
+               MAKE_LONG_ZVAL_INCREF(stat_size, (long)stat_ssb.sb.st_size);
+        }
        MAKE_LONG_ZVAL_INCREF(stat_atime, stat_ssb.sb.st_atime);
        MAKE_LONG_ZVAL_INCREF(stat_mtime, stat_ssb.sb.st_mtime);
        MAKE_LONG_ZVAL_INCREF(stat_ctime, stat_ssb.sb.st_ctime);
diff -ur php-5.5.1/ext/standard/filestat.c php-5.5.1.new/ext/standard/filestat.c
--- php-5.5.1/ext/standard/filestat.c   2013-07-18 16:37:33.000000000 +0200
+++ php-5.5.1.new/ext/standard/filestat.c       2013-08-15 10:42:39.442888060 
+0200
@@ -966,7 +966,11 @@
        case FS_INODE:
                RETURN_LONG((long)ssb.sb.st_ino);
        case FS_SIZE:
-               RETURN_LONG((long)ssb.sb.st_size);
+               if (ssb.sb.st_size > LONG_MAX) {
+                       RETURN_DOUBLE((double)ssb.sb.st_size);
+               } else {
+                       RETURN_LONG((long)ssb.sb.st_size);
+               }
        case FS_OWNER:
                RETURN_LONG((long)ssb.sb.st_uid);
        case FS_GROUP:
@@ -1023,7 +1027,11 @@
 #else
                MAKE_LONG_ZVAL_INCREF(stat_rdev, -1);
 #endif
-               MAKE_LONG_ZVAL_INCREF(stat_size, stat_sb->st_size);
+               if (stat_sb->st_size > LONG_MAX) {
+                       MAKE_DOUBLE_ZVAL_INCREF(stat_size, 
(double)stat_sb->st_size);
+               } else {
+                       MAKE_LONG_ZVAL_INCREF(stat_size, 
(long)stat_sb->st_size);
+               }
                MAKE_LONG_ZVAL_INCREF(stat_atime, stat_sb->st_atime);
                MAKE_LONG_ZVAL_INCREF(stat_mtime, stat_sb->st_mtime);
                MAKE_LONG_ZVAL_INCREF(stat_ctime, stat_sb->st_ctime);
diff -ur php-5.5.1/ext/standard/php_filestat.h 
php-5.5.1.new/ext/standard/php_filestat.h
--- php-5.5.1/ext/standard/php_filestat.h       2013-07-18 16:37:33.000000000 
+0200
+++ php-5.5.1.new/ext/standard/php_filestat.h   2013-08-15 10:42:39.442888060 
+0200
@@ -66,6 +66,12 @@
        ZVAL_LONG(name, val); \
        Z_ADDREF_P(name); 
 
+#define MAKE_DOUBLE_ZVAL_INCREF(name, val)\
+       MAKE_STD_ZVAL(name); \
+       ZVAL_DOUBLE(name, val); \
+       Z_ADDREF_P(name); 
+
+
 #ifdef PHP_WIN32
 #define S_IRUSR S_IREAD
 #define S_IWUSR S_IWRITE
diff -ur php-5.5.1/ext/standard/streamsfuncs.c 
php-5.5.1.new/ext/standard/streamsfuncs.c
--- php-5.5.1/ext/standard/streamsfuncs.c       2013-07-18 16:37:33.000000000 
+0200
+++ php-5.5.1.new/ext/standard/streamsfuncs.c   2013-08-15 10:42:39.442888060 
+0200
@@ -452,8 +452,9 @@
 {
        php_stream *src, *dest;
        zval *zsrc, *zdest;
-       long maxlen = PHP_STREAM_COPY_ALL, pos = 0;
-       size_t len;
+       long maxlen = (long)PHP_STREAM_COPY_ALL, pos = 0;
+       off_t len;
+        off_t reallength = PHP_STREAM_COPY_ALL;
        int ret;
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr|ll", &zsrc, 
&zdest, &maxlen, &pos) == FAILURE) {
@@ -468,12 +469,17 @@
                RETURN_FALSE;
        }
 
-       ret = php_stream_copy_to_stream_ex(src, dest, maxlen, &len);
+       reallength = maxlen == (long)PHP_STREAM_COPY_ALL ? PHP_STREAM_COPY_ALL 
: maxlen;
+       ret = php_stream_copy_to_stream_ex(src, dest, reallength, &len);
 
        if (ret != SUCCESS) {
                RETURN_FALSE;
        }
-       RETURN_LONG(len);
+        if (len > LONG_MAX) {
+               RETURN_DOUBLE((double)len);
+       } else {
+               RETURN_LONG(len);
+       }
 }
 /* }}} */
 
diff -ur php-5.5.1/main/php_streams.h php-5.5.1.new/main/php_streams.h
--- php-5.5.1/main/php_streams.h        2013-07-18 16:37:33.000000000 +0200
+++ php-5.5.1.new/main/php_streams.h    2013-08-15 10:44:45.432887821 +0200
@@ -411,7 +411,7 @@
 #define php_stream_truncate_supported(stream)  
(_php_stream_set_option((stream), PHP_STREAM_OPTION_TRUNCATE_API, 
PHP_STREAM_TRUNCATE_SUPPORTED, NULL TSRMLS_CC) == PHP_STREAM_OPTION_RETURN_OK ? 
1 : 0)
 
 BEGIN_EXTERN_C()
-PHPAPI int _php_stream_truncate_set_size(php_stream *stream, size_t newsize 
TSRMLS_DC);
+PHPAPI int _php_stream_truncate_set_size(php_stream *stream, off_t newsize 
TSRMLS_DC);
 #define php_stream_truncate_set_size(stream, size)     
_php_stream_truncate_set_size((stream), (size) TSRMLS_CC)
 END_EXTERN_C()
 
@@ -428,13 +428,13 @@
 
 /* copy up to maxlen bytes from src to dest.  If maxlen is PHP_STREAM_COPY_ALL,
  * copy until eof(src). */
-#define PHP_STREAM_COPY_ALL            ((size_t)-1)
+#define PHP_STREAM_COPY_ALL            ((off_t)-1)
 
 BEGIN_EXTERN_C()
 ZEND_ATTRIBUTE_DEPRECATED
 PHPAPI size_t _php_stream_copy_to_stream(php_stream *src, php_stream *dest, 
size_t maxlen STREAMS_DC TSRMLS_DC);
 #define php_stream_copy_to_stream(src, dest, maxlen)   
_php_stream_copy_to_stream((src), (dest), (maxlen) STREAMS_CC TSRMLS_CC)
-PHPAPI int _php_stream_copy_to_stream_ex(php_stream *src, php_stream *dest, 
size_t maxlen, size_t *len STREAMS_DC TSRMLS_DC);
+PHPAPI int _php_stream_copy_to_stream_ex(php_stream *src, php_stream *dest, 
off_t maxlen, off_t *len STREAMS_DC TSRMLS_DC);
 #define php_stream_copy_to_stream_ex(src, dest, maxlen, len)   
_php_stream_copy_to_stream_ex((src), (dest), (maxlen), (len) STREAMS_CC 
TSRMLS_CC)
 
 
@@ -445,7 +445,7 @@
 #define php_stream_copy_to_mem(src, buf, maxlen, persistent) 
_php_stream_copy_to_mem((src), (buf), (maxlen), (persistent) STREAMS_CC 
TSRMLS_CC)
 
 /* output all data from a stream */
-PHPAPI size_t _php_stream_passthru(php_stream * src STREAMS_DC TSRMLS_DC);
+PHPAPI off_t _php_stream_passthru(php_stream * src STREAMS_DC TSRMLS_DC);
 #define php_stream_passthru(stream)    _php_stream_passthru((stream) 
STREAMS_CC TSRMLS_CC)
 END_EXTERN_C()
 
diff -ur php-5.5.1/main/streams/memory.c php-5.5.1.new/main/streams/memory.c
--- php-5.5.1/main/streams/memory.c     2013-07-18 16:37:33.000000000 +0200
+++ php-5.5.1.new/main/streams/memory.c 2013-08-29 21:22:26.892904548 +0200
@@ -255,7 +255,7 @@
                                        if (ms->mode & TEMP_STREAM_READONLY) {
                                                return 
PHP_STREAM_OPTION_RETURN_ERR;
                                        }
-                                       newsize = *(size_t*)ptrparam;
+                                       newsize = *(off_t*)ptrparam;
                                        if (newsize <= ms->fsize) {
                                                if (newsize < ms->fpos) {
                                                        ms->fpos = newsize;
diff -ur php-5.5.1/main/streams/mmap.c php-5.5.1.new/main/streams/mmap.c
--- php-5.5.1/main/streams/mmap.c       2013-07-18 16:37:33.000000000 +0200
+++ php-5.5.1.new/main/streams/mmap.c   2013-08-28 16:55:56.992883015 +0200
@@ -22,7 +22,7 @@
 #include "php.h"
 #include "php_streams_int.h"
 
-PHPAPI char *_php_stream_mmap_range(php_stream *stream, size_t offset, size_t 
length, php_stream_mmap_operation_t mode, size_t *mapped_len TSRMLS_DC)
+PHPAPI char *_php_stream_mmap_range(php_stream *stream, off_t offset, size_t 
length, php_stream_mmap_operation_t mode, size_t *mapped_len TSRMLS_DC)
 {
        php_stream_mmap_range range;
        
diff -ur php-5.5.1/main/streams/php_stream_mmap.h 
php-5.5.1.new/main/streams/php_stream_mmap.h
--- php-5.5.1/main/streams/php_stream_mmap.h    2013-07-18 16:37:33.000000000 
+0200
+++ php-5.5.1.new/main/streams/php_stream_mmap.h        2013-08-28 
16:55:03.722897870 +0200
@@ -48,7 +48,7 @@
 typedef struct {
        /* requested offset and length.
         * If length is 0, the whole file is mapped */
-       size_t offset;
+       off_t offset;
        size_t length;
        
        php_stream_mmap_access_t mode;
@@ -67,7 +67,7 @@
 #define php_stream_mmap_possible(stream)                       
(!php_stream_is_filtered((stream)) && php_stream_mmap_supported((stream)))
 
 BEGIN_EXTERN_C()
-PHPAPI char *_php_stream_mmap_range(php_stream *stream, size_t offset, size_t 
length, php_stream_mmap_operation_t mode, size_t *mapped_len TSRMLS_DC);
+PHPAPI char *_php_stream_mmap_range(php_stream *stream, off_t offset, size_t 
length, php_stream_mmap_operation_t mode, size_t *mapped_len TSRMLS_DC);
 #define php_stream_mmap_range(stream, offset, length, mode, mapped_len)        
_php_stream_mmap_range((stream), (offset), (length), (mode), (mapped_len) 
TSRMLS_CC)
 
 /* un-maps the last mapped range */
diff -ur php-5.5.1/main/streams/plain_wrapper.c 
php-5.5.1.new/main/streams/plain_wrapper.c
--- php-5.5.1/main/streams/plain_wrapper.c      2013-07-18 16:37:33.000000000 
+0200
+++ php-5.5.1.new/main/streams/plain_wrapper.c  2013-08-30 14:36:33.012883582 
+0200
@@ -35,7 +35,14 @@
 #endif
 #ifdef HAVE_SYS_MMAN_H
 #include <sys/mman.h>
+# ifndef PAGE_SIZE
+#  define PAGE_SIZE 4096
+# endif
 #endif
+#ifdef PHP_WIN32
+# define PAGE_SIZE 4096
+#endif
+
 #include "SAPI.h"
 
 #include "php_streams_int.h"
@@ -628,10 +635,12 @@
                        {
                                php_stream_mmap_range *range = 
(php_stream_mmap_range*)ptrparam;
                                int prot, flags;
+                               off_t map_start = 0;
+                                size_t map_offset = 0;
                                
                                switch (value) {
                                        case PHP_STREAM_MMAP_SUPPORTED:
-                                               return fd == -1 ? 
PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK;
+                                               return fd == -1 || 
data->is_pipe ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK;
 
                                        case PHP_STREAM_MMAP_MAP_RANGE:
                                                do_fstat(data, 1);
@@ -665,7 +674,9 @@
                                                        default:
                                                                return 
PHP_STREAM_OPTION_RETURN_ERR;
                                                }
-                                               range->mapped = 
(char*)mmap(NULL, range->length, prot, flags, fd, range->offset);
+                                                map_start = range->offset & 
~(PAGE_SIZE - 1);
+                                                map_offset = 
(size_t)(range->offset - map_start);
+                                               range->mapped = 
(char*)mmap(NULL, range->length + map_offset, prot, flags, fd, map_start);
                                                if (range->mapped == 
(char*)MAP_FAILED) {
                                                        range->mapped = NULL;
                                                        return 
PHP_STREAM_OPTION_RETURN_ERR;
@@ -673,6 +684,7 @@
                                                /* remember the mapping */
                                                data->last_mapped_addr = 
range->mapped;
                                                data->last_mapped_len = 
range->length;
+                                                range->mapped = ((unsigned 
char*)range->mapped + map_offset); 
                                                return 
PHP_STREAM_OPTION_RETURN_OK;
 
                                        case PHP_STREAM_MMAP_UNMAP:
@@ -786,7 +798,8 @@
                                        return fd == -1 ? 
PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK;
 
                                case PHP_STREAM_TRUNCATE_SET_SIZE: {
-                                       ptrdiff_t new_size = 
*(ptrdiff_t*)ptrparam;
+                                       off_t new_size = *(off_t*)ptrparam;
+                                       /* Check for negative size, to keep 
backward compatibility with the previous behaviour */
                                        if (new_size < 0) {
                                                return 
PHP_STREAM_OPTION_RETURN_ERR;
                                        }
diff -ur php-5.5.1/main/streams/streams.c php-5.5.1.new/main/streams/streams.c
--- php-5.5.1/main/streams/streams.c    2013-07-18 16:37:33.000000000 +0200
+++ php-5.5.1.new/main/streams/streams.c        2013-08-30 14:54:44.622887454 
+0200
@@ -1378,30 +1378,39 @@
        return ret;
 }
 
-PHPAPI int _php_stream_truncate_set_size(php_stream *stream, size_t newsize 
TSRMLS_DC)
+PHPAPI int _php_stream_truncate_set_size(php_stream *stream, off_t newsize 
TSRMLS_DC)
 {
        return php_stream_set_option(stream, PHP_STREAM_OPTION_TRUNCATE_API, 
PHP_STREAM_TRUNCATE_SET_SIZE, &newsize);
 }
 
-PHPAPI size_t _php_stream_passthru(php_stream * stream STREAMS_DC TSRMLS_DC)
+PHPAPI off_t _php_stream_passthru(php_stream * stream STREAMS_DC TSRMLS_DC)
 {
-       size_t bcount = 0;
+       off_t bcount = 0;
        char buf[8192];
        int b;
 
        if (php_stream_mmap_possible(stream)) {
-               char *p;
-               size_t mapped;
+               char *p = NULL;
+               size_t mapped = 0;
+                off_t final = 0;
+               off_t start = php_stream_tell(stream);
 
-               p = php_stream_mmap_range(stream, php_stream_tell(stream), 
PHP_STREAM_MMAP_ALL, PHP_STREAM_MAP_MODE_SHARED_READONLY, &mapped);
+               p = php_stream_mmap_range(stream, start, PHP_STREAM_MMAP_ALL, 
PHP_STREAM_MAP_MODE_SHARED_READONLY, &mapped);
 
-               if (p) {
+               while (p && mapped)
+                {
                        PHPWRITE(p, mapped);
 
                        php_stream_mmap_unmap_ex(stream, mapped);
+                        final += mapped;
+                       p = php_stream_mmap_range(stream, start + final, 
PHP_STREAM_MMAP_ALL, PHP_STREAM_MAP_MODE_SHARED_READONLY, &mapped);
 
-                       return mapped;
                }
+                if (p) {
+                       php_stream_mmap_unmap_ex(stream, mapped);
+               }
+
+               return final;
        }
 
        while ((b = php_stream_read(stream, buf, sizeof(buf))) > 0) {
@@ -1426,7 +1435,7 @@
                return 0;
        }
 
-       if (maxlen == PHP_STREAM_COPY_ALL) {
+       if (maxlen == (size_t)PHP_STREAM_COPY_ALL) {
                maxlen = 0;
        }
 
@@ -1484,13 +1493,13 @@
 }
 
 /* Returns SUCCESS/FAILURE and sets *len to the number of bytes moved */
-PHPAPI int _php_stream_copy_to_stream_ex(php_stream *src, php_stream *dest, 
size_t maxlen, size_t *len STREAMS_DC TSRMLS_DC)
+PHPAPI int _php_stream_copy_to_stream_ex(php_stream *src, php_stream *dest, 
off_t maxlen, off_t *len STREAMS_DC TSRMLS_DC)
 {
        char buf[CHUNK_SIZE];
        size_t readchunk;
-       size_t haveread = 0;
+       off_t haveread = 0;
        size_t didread, didwrite, towrite;
-       size_t dummy;
+       off_t dummy;
        php_stream_statbuf ssbuf;
 
        if (!len) {
@@ -1521,24 +1530,34 @@
                char *p;
                size_t mapped;
 
-               p = php_stream_mmap_range(src, php_stream_tell(src), maxlen, 
PHP_STREAM_MAP_MODE_SHARED_READONLY, &mapped);
+                off_t final = 0, start = php_stream_tell(src), mapsum = 0;
+                size_t mappedlen = maxlen < SIZE_MAX ? (size_t)maxlen : 
(size_t)-1;
 
-               if (p) {
+                p = php_stream_mmap_range(src, start, maxlen, 
PHP_STREAM_MAP_MODE_SHARED_READONLY, &mapped);
+
+               while (p && mapped > 0) {
+                       mapsum += (off_t)mapped;
                        didwrite = php_stream_write(dest, p, mapped);
 
+                        final += didwrite;
+                        if ((maxlen && final >= maxlen) || mapped < mappedlen) 
break;
+                       /* Ok, map another section to fit the address space for 
a larger file */
+                       php_stream_mmap_unmap_ex(src, mapped);
+                        mappedlen = (maxlen - final ) < SIZE_MAX ? 
(size_t)(maxlen - final) : (size_t)-1;
+                        p = php_stream_mmap_range(src, start + final, 
mappedlen, PHP_STREAM_MAP_MODE_SHARED_READONLY, &mapped);
+                }
+                *len = final;
+               if (p) {
                        php_stream_mmap_unmap_ex(src, mapped);
-
-                       *len = didwrite;
-
-                       /* we've got at least 1 byte to read
-                        * less than 1 is an error
-                        * AND read bytes match written */
-                       if (mapped > 0 && mapped == didwrite) {
-                               return SUCCESS;
-                       }
-                       return FAILURE;
                }
-       }
+
+                /* we've got at least 1 byte to read.
+                * less than 1 is an error */
+                if (final > 0 && mapsum == final) {
+                       return SUCCESS;
+                }
+                return FAILURE;
+        }
 
        while(1) {
                readchunk = sizeof(buf);
@@ -1593,12 +1612,12 @@
 ZEND_ATTRIBUTE_DEPRECATED
 PHPAPI size_t _php_stream_copy_to_stream(php_stream *src, php_stream *dest, 
size_t maxlen STREAMS_DC TSRMLS_DC)
 {
-       size_t len;
-       int ret = _php_stream_copy_to_stream_ex(src, dest, maxlen, &len 
STREAMS_REL_CC TSRMLS_CC);
-       if (ret == SUCCESS && len == 0 && maxlen != 0) {
+        off_t _len = 0, _maxlen = maxlen;
+       int ret = _php_stream_copy_to_stream_ex(src, dest, _maxlen, &_len 
STREAMS_REL_CC TSRMLS_CC);
+       if (ret == SUCCESS && _len == 0 && _maxlen != 0) {
                return 1;
        }
-       return len;
+       return (size_t)_len;
 }
 /* }}} */
 
diff -ur php-5.5.1/main/streams/userspace.c 
php-5.5.1.new/main/streams/userspace.c
--- php-5.5.1/main/streams/userspace.c  2013-07-18 16:37:33.000000000 +0200
+++ php-5.5.1.new/main/streams/userspace.c      2013-08-30 14:40:13.352891754 
+0200
@@ -1036,8 +1036,8 @@
                        break;
 
                case PHP_STREAM_TRUNCATE_SET_SIZE: {
-                       ptrdiff_t new_size = *(ptrdiff_t*) ptrparam;
-                       if (new_size >= 0 && new_size <= (ptrdiff_t)LONG_MAX) {
+                       off_t new_size = *(off_t*) ptrparam;
+                       if (new_size >= 0 && new_size <= (off_t)LONG_MAX) {
                                MAKE_STD_ZVAL(zvalue);
                                ZVAL_LONG(zvalue, (long)new_size);
                                args[0] = &zvalue;
-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to