From b1aa8bf36b0effea1ad7884f8585ff84b34405a6 Mon Sep 17 00:00:00 2001 From: Andreas Streichardt Date: Fri, 12 Oct 2012 11:02:33 +0200 Subject: [PATCH 1/5] First fixes for a 64bit compatible ftp extension --- ext/ftp/ftp.c | 42 ++++++++++++++---------------------------- ext/ftp/ftp.h | 12 ++++++------ ext/ftp/php_ftp.c | 12 ++++++------ 3 files changed, 26 insertions(+), 40 deletions(-) diff --git a/ext/ftp/ftp.c b/ext/ftp/ftp.c index 4156a0458131..4a98233ca23b 100644 --- a/ext/ftp/ftp.c +++ b/ext/ftp/ftp.c @@ -610,7 +610,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]; @@ -618,8 +618,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; } @@ -785,7 +785,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; @@ -806,10 +806,6 @@ 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); if (!ftp_putcmd(ftp, "REST", arg)) { goto bail; @@ -883,10 +879,10 @@ ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, /* {{{ 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]; @@ -903,10 +899,6 @@ 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); if (!ftp_putcmd(ftp, "REST", arg)) { goto bail; @@ -964,7 +956,7 @@ ftp_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, i /* {{{ ftp_size */ -int +long ftp_size(ftpbuf_t *ftp, const char *path) { if (ftp == NULL) { @@ -979,7 +971,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); } /* }}} */ @@ -1141,7 +1133,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 */ @@ -1234,7 +1226,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) { @@ -1704,7 +1697,7 @@ ftp_genlist(ftpbuf_t *ftp, const char *cmd, const char *path TSRMLS_DC) /* {{{ 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]; @@ -1722,13 +1715,6 @@ 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); if (!ftp_putcmd(ftp, "REST", arg)) { goto bail; @@ -1828,7 +1814,7 @@ ftp_nb_continue_read(ftpbuf_t *ftp TSRMLS_DC) /* {{{ 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]; @@ -1884,7 +1870,7 @@ ftp_nb_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type int ftp_nb_continue_write(ftpbuf_t *ftp TSRMLS_DC) { - int size; + long size; char *ptr; int ch; diff --git a/ext/ftp/ftp.h b/ext/ftp/ftp.h index 7023723a403a..a4d773d4710f 100644 --- a/ext/ftp/ftp.h +++ b/ext/ftp/ftp.h @@ -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 */ diff --git a/ext/ftp/php_ftp.c b/ext/ftp/php_ftp.c index 6e232a5df2d3..57f3beba178b 100644 --- a/ext/ftp/php_ftp.c +++ b/ext/ftp/php_ftp.c @@ -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; @@ -982,7 +982,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 +1120,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 +1173,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) { From 8886a36e4f4688b41dd2d4da3fbe9d86c3c0fb55 Mon Sep 17 00:00:00 2001 From: Andreas Streichardt Date: Sat, 13 Oct 2012 11:18:04 +0200 Subject: [PATCH 2/5] Add testcase to verify ftp_size can handle large files --- ext/ftp/tests/filesize_large.phpt | 20 ++++++++++++++++++++ ext/ftp/tests/server.inc | 8 ++++---- 2 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 ext/ftp/tests/filesize_large.phpt diff --git a/ext/ftp/tests/filesize_large.phpt b/ext/ftp/tests/filesize_large.phpt new file mode 100644 index 000000000000..6c3b20245f95 --- /dev/null +++ b/ext/ftp/tests/filesize_large.phpt @@ -0,0 +1,20 @@ +--TEST-- +Verify php can handle filesizes >32bit +--SKIPIF-- + +--FILE-- + +--EXPECT-- +int(5368709120) diff --git a/ext/ftp/tests/server.inc b/ext/ftp/tests/server.inc index 86178806233f..f5e4166feec3 100644 --- a/ext/ftp/tests/server.inc +++ b/ext/ftp/tests/server.inc @@ -395,9 +395,9 @@ if ($pid) { }elseif (preg_match('/^REST \d+/', $buf, $matches)) { 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 +407,4 @@ if ($pid) { } fclose($socket); -?> \ No newline at end of file +?> From 857ba251fb26296f00df019f453b381a5e291eeb Mon Sep 17 00:00:00 2001 From: Andreas Streichardt Date: Sat, 13 Oct 2012 12:13:28 +0200 Subject: [PATCH 3/5] More ints, nb_get large testcase --- ext/ftp/ftp.c | 12 ++++------- ext/ftp/tests/ftp_nb_get_large.phpt | 31 +++++++++++++++++++++++++++++ ext/ftp/tests/server.inc | 15 ++++++++++++-- 3 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 ext/ftp/tests/ftp_nb_get_large.phpt diff --git a/ext/ftp/ftp.c b/ext/ftp/ftp.c index 4a98233ca23b..330b689ce401 100644 --- a/ext/ftp/ftp.c +++ b/ext/ftp/ftp.c @@ -806,7 +806,7 @@ ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, ftp->data = data; if (resumepos > 0) { - snprintf(arg, sizeof(arg), "%u", resumepos); + snprintf(arg, sizeof(arg), "%ld", resumepos); if (!ftp_putcmd(ftp, "REST", arg)) { goto bail; } @@ -899,7 +899,7 @@ ftp_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, l ftp->data = data; if (startpos > 0) { - snprintf(arg, sizeof(arg), "%u", startpos); + snprintf(arg, sizeof(arg), "%ld", startpos); if (!ftp_putcmd(ftp, "REST", arg)) { goto bail; } @@ -1715,7 +1715,7 @@ ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t typ } if (resumepos>0) { - snprintf(arg, sizeof(arg), "%u", resumepos); + snprintf(arg, sizeof(arg), "%ld", resumepos); if (!ftp_putcmd(ftp, "REST", arg)) { goto bail; } @@ -1829,11 +1829,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; } diff --git a/ext/ftp/tests/ftp_nb_get_large.phpt b/ext/ftp/tests/ftp_nb_get_large.phpt new file mode 100644 index 000000000000..3b2636f89c88 --- /dev/null +++ b/ext/ftp/tests/ftp_nb_get_large.phpt @@ -0,0 +1,31 @@ +--TEST-- +Testing ftp_nb_fget can handle large files incl. resume +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECT-- +string(1) "X" +int(5368709120) diff --git a/ext/ftp/tests/server.inc b/ext/ftp/tests/server.inc index f5e4166feec3..7dc8fa08d99f 100644 --- a/ext/ftp/tests/server.inc +++ b/ext/ftp/tests/server.inc @@ -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,7 +403,8 @@ 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"); }elseif (preg_match('/^SIZE largefile/', $buf)) { fputs($s, "213 5368709120\r\n"); From 3bb47f33d0812613d6e391647309a6639f60e9c1 Mon Sep 17 00:00:00 2001 From: Andreas Streichardt Date: Sun, 4 Aug 2013 16:02:16 +0200 Subject: [PATCH 4/5] Skip check on 32 bit platforms --- ext/ftp/tests/ftp_nb_get_large.phpt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ext/ftp/tests/ftp_nb_get_large.phpt b/ext/ftp/tests/ftp_nb_get_large.phpt index 3b2636f89c88..ce051fc3f133 100644 --- a/ext/ftp/tests/ftp_nb_get_large.phpt +++ b/ext/ftp/tests/ftp_nb_get_large.phpt @@ -3,7 +3,12 @@ Testing ftp_nb_fget can handle large files incl. resume --SKIPIF-- --FILE-- Date: Sun, 4 Aug 2013 16:18:26 +0200 Subject: [PATCH 5/5] Always close outstream and not only when it is finished --- ext/ftp/php_ftp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ext/ftp/php_ftp.c b/ext/ftp/php_ftp.c index 57f3beba178b..75a30c332393 100644 --- a/ext/ftp/php_ftp.c +++ b/ext/ftp/php_ftp.c @@ -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); }