]> granicus.if.org Git - php/commitdiff
First fixes for a 64bit compatible ftp extension
authorAndreas Streichardt <andreas.streichardt@gmail.com>
Fri, 12 Oct 2012 09:02:33 +0000 (11:02 +0200)
committerStanislav Malyshev <stas@php.net>
Mon, 5 Aug 2013 02:31:30 +0000 (19:31 -0700)
ext/ftp/ftp.c
ext/ftp/ftp.h
ext/ftp/php_ftp.c
ext/ftp/tests/filesize_large.phpt [new file with mode: 0644]
ext/ftp/tests/ftp_nb_get_large.phpt [new file with mode: 0644]
ext/ftp/tests/server.inc

index dd41f02704255fbbb3ac8629804a27ef27c7d04d..0d6704f9d21a05c56567e29f6e479aedbba82e7d 100644 (file)
@@ -612,7 +612,7 @@ ftp_chmod(ftpbuf_t *ftp, const int mode, const char *filename, const int filenam
 /* {{{ ftp_alloc
  */
 int
-ftp_alloc(ftpbuf_t *ftp, const int size, char **response)
+ftp_alloc(ftpbuf_t *ftp, const long size, char **response)
 {
        char buffer[64];
 
@@ -620,8 +620,8 @@ ftp_alloc(ftpbuf_t *ftp, const int size, char **response)
                return 0;
        }
 
-       snprintf(buffer, sizeof(buffer) - 1, "%d", size);
-
+       snprintf(buffer, sizeof(buffer) - 1, "%ld", size);
+    
        if (!ftp_putcmd(ftp, "ALLO", buffer)) {
                return 0;
        }
@@ -787,7 +787,7 @@ ftp_pasv(ftpbuf_t *ftp, int pasv)
 /* {{{ ftp_get
  */
 int
-ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, int resumepos TSRMLS_DC)
+ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, long resumepos TSRMLS_DC)
 {
        databuf_t               *data = NULL;
        int                     lastch;
@@ -808,11 +808,7 @@ ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type,
        ftp->data = data;
 
        if (resumepos > 0) {
-               if (resumepos > 2147483647) {
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHP cannot handle files greater than 2147483647 bytes.");
-                       goto bail;
-               }
-               snprintf(arg, sizeof(arg), "%u", resumepos);
+               snprintf(arg, sizeof(arg), "%ld", resumepos);
                if (!ftp_putcmd(ftp, "REST", arg)) {
                        goto bail;
                }
@@ -885,10 +881,10 @@ bail:
 /* {{{ ftp_put
  */
 int
-ftp_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, int startpos TSRMLS_DC)
+ftp_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, long startpos TSRMLS_DC)
 {
        databuf_t               *data = NULL;
-       int                     size;
+       long                    size;
        char                    *ptr;
        int                     ch;
        char                    arg[11];
@@ -905,11 +901,7 @@ ftp_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, i
        ftp->data = data;       
 
        if (startpos > 0) {
-               if (startpos > 2147483647) {
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHP cannot handle files with a size greater than 2147483647 bytes.");
-                       goto bail;
-               }
-               snprintf(arg, sizeof(arg), "%u", startpos);
+               snprintf(arg, sizeof(arg), "%ld", startpos);
                if (!ftp_putcmd(ftp, "REST", arg)) {
                        goto bail;
                }
@@ -966,7 +958,7 @@ bail:
 
 /* {{{ ftp_size
  */
-int
+long
 ftp_size(ftpbuf_t *ftp, const char *path)
 {
        if (ftp == NULL) {
@@ -981,7 +973,7 @@ ftp_size(ftpbuf_t *ftp, const char *path)
        if (!ftp_getresp(ftp) || ftp->resp != 213) {
                return -1;
        }
-       return atoi(ftp->inbuf);
+       return atol(ftp->inbuf);
 }
 /* }}} */
 
@@ -1143,7 +1135,7 @@ ftp_putcmd(ftpbuf_t *ftp, const char *cmd, const char *args)
 int
 ftp_readline(ftpbuf_t *ftp)
 {
-       int             size, rcvd;
+       long            size, rcvd;
        char            *data, *eol;
 
        /* shift the extra to the front */
@@ -1236,7 +1228,8 @@ ftp_getresp(ftpbuf_t *ftp)
 int
 my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
 {
-       int             n, size, sent;
+       long            size, sent;
+    int         n;
 
        size = len;
        while (size) {
@@ -1719,7 +1712,7 @@ bail:
 /* {{{ ftp_nb_get
  */
 int
-ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, int resumepos TSRMLS_DC)
+ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, long resumepos TSRMLS_DC)
 {
        databuf_t               *data = NULL;
        char                    arg[11];
@@ -1737,14 +1730,7 @@ ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t typ
        }
 
        if (resumepos>0) {
-               /* We are working on an architecture that supports 64-bit integers
-                * since php is 32 bit by design, we bail out with warning
-                */
-               if (resumepos > 2147483647) {
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHP cannot handle files greater than 2147483648 bytes.");
-                       goto bail;
-               }
-               snprintf(arg, sizeof(arg), "%u", resumepos);
+               snprintf(arg, sizeof(arg), "%ld", resumepos);
                if (!ftp_putcmd(ftp, "REST", arg)) {
                        goto bail;
                }
@@ -1843,7 +1829,7 @@ bail:
 /* {{{ ftp_nb_put
  */
 int
-ftp_nb_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, int startpos TSRMLS_DC)
+ftp_nb_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, long startpos TSRMLS_DC)
 {
        databuf_t               *data = NULL;
        char                    arg[11];
@@ -1858,11 +1844,7 @@ ftp_nb_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type
                goto bail;
        }
        if (startpos > 0) {
-               if (startpos > 2147483647) {
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHP cannot handle files with a size greater than 2147483647 bytes.");
-                       goto bail;
-               }
-               snprintf(arg, sizeof(arg), "%u", startpos);
+               snprintf(arg, sizeof(arg), "%ld", startpos);
                if (!ftp_putcmd(ftp, "REST", arg)) {
                        goto bail;
                }
@@ -1899,7 +1881,7 @@ bail:
 int
 ftp_nb_continue_write(ftpbuf_t *ftp TSRMLS_DC)
 {
-       int                     size;
+       long                    size;
        char                    *ptr;
        int                     ch;
 
index c7db45789a5d94066f23896c89c60b2f6b89c267..69de7dbb78acadfcf0ce9ae763432d74ca2b2685 100644 (file)
@@ -146,7 +146,7 @@ int         ftp_chmod(ftpbuf_t *ftp, const int mode, const char *filename, const int fi
  * however some servers will not accept STOR or APPE until ALLO is confirmed. 
  * If response is passed, it is estrdup()ed from ftp->inbuf and must be freed
  * or assigned to a zval returned to the user */
-int            ftp_alloc(ftpbuf_t *ftp, const int size, char **response);
+int            ftp_alloc(ftpbuf_t *ftp, const long size, char **response);
 
 /* returns a NULL-terminated array of filenames in the given path
  * or NULL on error.  the return array must be freed (but don't
@@ -169,15 +169,15 @@ int               ftp_pasv(ftpbuf_t *ftp, int pasv);
 /* retrieves a file and saves its contents to outfp
  * returns true on success, false on error
  */
-int            ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, int resumepos TSRMLS_DC);
+int            ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, long resumepos TSRMLS_DC);
 
 /* stores the data from a file, socket, or process as a file on the remote server
  * returns true on success, false on error
  */
-int            ftp_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, int startpos TSRMLS_DC);
+int            ftp_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, long startpos TSRMLS_DC);
 
 /* returns the size of the given file, or -1 on error */
-int            ftp_size(ftpbuf_t *ftp, const char *path);
+long           ftp_size(ftpbuf_t *ftp, const char *path);
 
 /* returns the last modified time of the given file, or -1 on error */
 time_t         ftp_mdtm(ftpbuf_t *ftp, const char *path);
@@ -194,12 +194,12 @@ int               ftp_site(ftpbuf_t *ftp, const char *cmd);
 /* retrieves part of a file and saves its contents to outfp
  * returns true on success, false on error
  */
-int            ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, int resumepos TSRMLS_DC);
+int            ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, long resumepos TSRMLS_DC);
 
 /* stores the data from a file, socket, or process as a file on the remote server
  * returns true on success, false on error
  */
-int            ftp_nb_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, int startpos TSRMLS_DC);
+int            ftp_nb_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, long startpos TSRMLS_DC);
 
 /* continues a previous nb_(f)get command
  */
index 73071936e0fbc475c0491a2471a2b644814f8061..da22e0b63eb3a96c07021b889faf1e80b00554ef 100644 (file)
@@ -784,8 +784,8 @@ PHP_FUNCTION(ftp_nb_fget)
        ftptype_t       xtype;
        php_stream      *stream;
        char            *file;
-       int             file_len, ret;
-       long            mode, resumepos=0;
+       int             file_len;
+       long            mode, resumepos=0, ret;
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrsl|l", &z_ftp, &z_file, &file, &file_len, &mode, &resumepos) == FAILURE) {
                return;
@@ -968,9 +968,7 @@ PHP_FUNCTION(ftp_nb_get)
                RETURN_LONG(PHP_FTP_FAILED);
        }
 
-       if (ret == PHP_FTP_FINISHED) {
-               php_stream_close(outstream);
-       }
+        php_stream_close(outstream);
 
        RETURN_LONG(ret);
 }
@@ -982,7 +980,7 @@ PHP_FUNCTION(ftp_nb_continue)
 {
        zval            *z_ftp;
        ftpbuf_t        *ftp;
-       int             ret;
+       long            ret;
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_ftp) == FAILURE) {
                return;
@@ -1120,7 +1118,7 @@ PHP_FUNCTION(ftp_put)
        ftpbuf_t        *ftp;
        ftptype_t       xtype;
        char            *remote, *local;
-       int             remote_len, local_len;
+       long            remote_len, local_len;
        long            mode, startpos=0;
        php_stream      *instream;
 
@@ -1173,8 +1171,8 @@ PHP_FUNCTION(ftp_nb_put)
        ftpbuf_t        *ftp;
        ftptype_t       xtype;
        char            *remote, *local;
-       int             remote_len, local_len, ret;
-       long            mode, startpos=0;
+       int             remote_len, local_len;
+       long            mode, startpos=0, ret;
        php_stream      *instream;
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rppl|l", &z_ftp, &remote, &remote_len, &local, &local_len, &mode, &startpos) == FAILURE) {
diff --git a/ext/ftp/tests/filesize_large.phpt b/ext/ftp/tests/filesize_large.phpt
new file mode 100644 (file)
index 0000000..05f12a3
--- /dev/null
@@ -0,0 +1,23 @@
+--TEST--
+Verify php can handle filesizes >32bit
+--SKIPIF--
+<?php
+require 'skipif.inc';
+if (2147483647 == PHP_INT_MAX) {
+    die('skip 64-bit only');
+}
+?>
+--FILE--
+<?php
+require 'server.inc';
+
+$ftp = ftp_connect('127.0.0.1', $port);
+if (!$ftp) die("Couldn't connect to the server");
+
+ftp_login($ftp, 'user', 'pass');
+var_dump(ftp_size($ftp, 'largefile'));
+
+ftp_close($ftp);
+?>
+--EXPECT--
+int(5368709120)
diff --git a/ext/ftp/tests/ftp_nb_get_large.phpt b/ext/ftp/tests/ftp_nb_get_large.phpt
new file mode 100644 (file)
index 0000000..3fbf2a4
--- /dev/null
@@ -0,0 +1,36 @@
+--TEST--
+Testing ftp_nb_fget can handle large files incl. resume
+--SKIPIF--
+<?php
+require 'skipif.inc';
+if (2147483647 == PHP_INT_MAX) {
+    die('skip ot supported on this system');
+}
+if (disk_free_space(__DIR__) < 10*1024*1024*1024) {
+    die('not enough disk space');
+}
+?>
+--FILE--
+<?php
+require 'server.inc';
+
+$ftp = ftp_connect('127.0.0.1', $port);
+ftp_login($ftp, 'user', 'pass');
+if (!$ftp) die("Couldn't connect to the server");
+
+$local_file = dirname(__FILE__) . DIRECTORY_SEPARATOR . "localfile.txt";
+touch($local_file);
+ftp_nb_get($ftp, $local_file, 'fget_large.txt', FTP_BINARY, 5368709119);
+$fp = fopen($local_file, 'r');
+fseek($fp, 5368709119);
+var_dump(fread($fp, 1));
+var_dump(filesize($local_file));
+fclose($fp);
+?>
+--CLEAN--
+<?php
+@unlink(dirname(__FILE__) . DIRECTORY_SEPARATOR . "localfile.txt");
+?>
+--EXPECT--
+string(1) "X"
+int(5368709120)
index 86178806233f7f71714c9039cb17dd6d9fb71c4e..7dc8fa08d99ff7b995f027a8b096484c31ece5e2 100644 (file)
@@ -357,7 +357,17 @@ if ($pid) {
                                        $transfer_type = $ascii? 'ASCII' : 'BINARY' ;
                                        fputs($fs, "Bar\r\n");
                                        fputs($s, "226 Closing data Connection.\r\n");
-                                       break;
+                                        break;
+                                case "fget_large":
+                                       fputs($s, "150 File status okay; about to open data connection.\r\n");
+                                        $transfer_type = $ascii? 'ASCII' : 'BINARY' ;
+                                        if ($GLOBALS['rest_pos'] == '5368709119') {
+                                           fputs($fs, "X");
+                                        } else {
+                                           fputs($fs, "Y");
+                                        }
+                                       fputs($s, "226 Closing data Connection.\r\n");
+                                        break;
                                default:
                                        fputs($s, "550 {$matches[1]}: No such file or directory \r\n");
                                        break;
@@ -393,11 +403,12 @@ if ($pid) {
                }elseif (preg_match('/^LIST no_exists\//', $buf, $matches)) {
                        fputs($s, "425 Error establishing connection\r\n");
 
-               }elseif (preg_match('/^REST \d+/', $buf, $matches)) {
+                }elseif (preg_match('/^REST (\d+)/', $buf, $matches)) {
+                        $GLOBALS['rest_pos'] = $matches[1];
                        fputs($s, "350 OK\r\n");
-               }
-
-               else {
+                }elseif (preg_match('/^SIZE largefile/', $buf)) {
+                        fputs($s, "213 5368709120\r\n");
+                }else {
                        fputs($s, "500 Syntax error, command unrecognized.\r\n");
                        dump_and_exit($buf);
                }
@@ -407,4 +418,4 @@ if ($pid) {
 }
 
 fclose($socket);
-?>
\ No newline at end of file
+?>