Permalink
Browse files

First fixes for a 64bit compatible ftp extension

  • Loading branch information...
m0ppers authored and smalyshev committed Oct 12, 2012
1 parent 8d86597 commit a93a462dcefd62e07963dd2da506fbb3409c88b5
Showing with 107 additions and 57 deletions.
  1. +18 −36 ext/ftp/ftp.c
  2. +6 −6 ext/ftp/ftp.h
  3. +7 −9 ext/ftp/php_ftp.c
  4. +23 −0 ext/ftp/tests/filesize_large.phpt
  5. +36 −0 ext/ftp/tests/ftp_nb_get_large.phpt
  6. +17 −6 ext/ftp/tests/server.inc
View
@@ -612,16 +612,16 @@ 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];
if (ftp == NULL || size <= 0) {
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 @@ 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];
@@ -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 @@ 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) {
@@ -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 @@ 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];
@@ -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 @@ 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];
@@ -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 @@ 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;
View
@@ -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
*/
View
@@ -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);

This comment has been minimized.

Show comment Hide comment
@pilif

pilif Oct 2, 2013

Contributor

I think this is the cause for bug 65667. IMHO the stream should not be closed if there's more data to be transferred

@pilif

pilif Oct 2, 2013

Contributor

I think this is the cause for bug 65667. IMHO the stream should not be closed if there's more data to be transferred

This comment has been minimized.

Show comment Hide comment
@WanderingZombie

WanderingZombie Nov 1, 2013

+1 from me. I've just spent a couple of hours tracing through code to the point of a failure with segmentation fault at a call to ftp_nb_continue($conn)

@WanderingZombie

WanderingZombie Nov 1, 2013

+1 from me. I've just spent a couple of hours tracing through code to the point of a failure with segmentation fault at a call to ftp_nb_continue($conn)

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) {
@@ -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)
@@ -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)
View
@@ -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);
-?>
+?>

0 comments on commit a93a462

Please sign in to comment.