mirror of
https://github.com/moparisthebest/curl
synced 2024-11-12 04:25:08 -05:00
I want Sterling to be my friend, so I wasted some time on splitting up the
huge monster function _ftp() into more little functions. There are still more that can be done, but this is at least improving readability and maintainability... :-)
This commit is contained in:
parent
e3d7cc895b
commit
83a8786fe1
239
lib/ftp.c
239
lib/ftp.c
@ -151,9 +151,11 @@ static CURLcode AllowServerConnect(struct UrlData *data,
|
|||||||
|
|
||||||
/* --- parse FTP server responses --- */
|
/* --- parse FTP server responses --- */
|
||||||
|
|
||||||
#define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
|
/*
|
||||||
isdigit((int)line[2]) && (' ' == line[3]))
|
* Curl_GetFTPResponse() is supposed to be invoked after each command sent to
|
||||||
|
* a remote FTP server. This function will wait and read all lines of the
|
||||||
|
* response and extract the relevant return code for the invoking function.
|
||||||
|
*/
|
||||||
|
|
||||||
int Curl_GetFTPResponse(int sockfd,
|
int Curl_GetFTPResponse(int sockfd,
|
||||||
char *buf,
|
char *buf,
|
||||||
@ -165,8 +167,7 @@ int Curl_GetFTPResponse(int sockfd,
|
|||||||
* as it seems that the OpenSSL read() stuff doesn't grok that properly.
|
* as it seems that the OpenSSL read() stuff doesn't grok that properly.
|
||||||
*
|
*
|
||||||
* Alas, read as much as possible, split up into lines, use the ending
|
* Alas, read as much as possible, split up into lines, use the ending
|
||||||
* line in a response or continue reading.
|
* line in a response or continue reading. */
|
||||||
*/
|
|
||||||
|
|
||||||
int nread; /* total size read */
|
int nread; /* total size read */
|
||||||
int perline; /* count bytes per line */
|
int perline; /* count bytes per line */
|
||||||
@ -260,6 +261,9 @@ int Curl_GetFTPResponse(int sockfd,
|
|||||||
/* no need to output LF here, it is part of the data */
|
/* no need to output LF here, it is part of the data */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
|
||||||
|
isdigit((int)line[2]) && (' ' == line[3]))
|
||||||
|
|
||||||
if(perline>3 && lastline(line_start)) {
|
if(perline>3 && lastline(line_start)) {
|
||||||
/* This is the end of the last line, copy the last
|
/* This is the end of the last line, copy the last
|
||||||
* line to the start of the buffer and zero terminate,
|
* line to the start of the buffer and zero terminate,
|
||||||
@ -635,6 +639,90 @@ CURLcode _ftp_cwd(struct connectdata *conn, char *path)
|
|||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
CURLcode _ftp_getfiletime(struct connectdata *conn, char *file)
|
||||||
|
{
|
||||||
|
CURLcode result=CURLE_OK;
|
||||||
|
int ftpcode; /* for ftp status */
|
||||||
|
ssize_t nread;
|
||||||
|
char *buf = conn->data->buffer;
|
||||||
|
|
||||||
|
/* we have requested to get the modified-time of the file, this is yet
|
||||||
|
again a grey area as the MDTM is not kosher RFC959 */
|
||||||
|
ftpsendf(conn->firstsocket, conn, "MDTM %s", file);
|
||||||
|
|
||||||
|
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
|
if(ftpcode == 213) {
|
||||||
|
/* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
|
||||||
|
last .sss part is optional and means fractions of a second */
|
||||||
|
int year, month, day, hour, minute, second;
|
||||||
|
if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
|
||||||
|
&year, &month, &day, &hour, &minute, &second)) {
|
||||||
|
/* we have a time, reformat it */
|
||||||
|
time_t secs=time(NULL);
|
||||||
|
sprintf(buf, "%04d%02d%02d %02d:%02d:%02d",
|
||||||
|
year, month, day, hour, minute, second);
|
||||||
|
/* now, convert this into a time() value: */
|
||||||
|
conn->data->progress.filetime = curl_getdate(buf, &secs);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
infof(conn->data, "unsupported MDTM reply format\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURLcode _ftp_transfertype(struct connectdata *conn,
|
||||||
|
bool ascii)
|
||||||
|
{
|
||||||
|
struct UrlData *data = conn->data;
|
||||||
|
int ftpcode;
|
||||||
|
ssize_t nread;
|
||||||
|
char *buf=data->buffer;
|
||||||
|
|
||||||
|
ftpsendf(conn->firstsocket, conn, "TYPE %s", ascii?"A":"I");
|
||||||
|
|
||||||
|
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
|
if(ftpcode != 200) {
|
||||||
|
failf(data, "Couldn't set %s mode",
|
||||||
|
ascii?"ASCII":"binary");
|
||||||
|
return ascii? CURLE_FTP_COULDNT_SET_ASCII:CURLE_FTP_COULDNT_SET_BINARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
CURLcode _ftp_getsize(struct connectdata *conn, char *file,
|
||||||
|
ssize_t *size)
|
||||||
|
{
|
||||||
|
struct UrlData *data = conn->data;
|
||||||
|
int ftpcode;
|
||||||
|
ssize_t nread;
|
||||||
|
char *buf=data->buffer;
|
||||||
|
|
||||||
|
ftpsendf(conn->firstsocket, conn, "SIZE %s", file);
|
||||||
|
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
|
if(ftpcode == 213) {
|
||||||
|
/* get the size from the ascii string: */
|
||||||
|
*size = atoi(buf+4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return CURLE_FTP_COULDNT_GET_SIZE;
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
CURLcode _ftp(struct connectdata *conn)
|
CURLcode _ftp(struct connectdata *conn)
|
||||||
{
|
{
|
||||||
@ -675,40 +763,17 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* change directory first! */
|
/* change directory first! */
|
||||||
if(ftp->dir && ftp->dir[0]) {
|
if(ftp->dir && ftp->dir[0]) {
|
||||||
if ((result = _ftp_cwd(conn, ftp->dir)) != CURLE_OK)
|
if ((result = _ftp_cwd(conn, ftp->dir)) != CURLE_OK)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Requested time of file? */
|
||||||
if(data->bits.get_filetime && ftp->file) {
|
if(data->bits.get_filetime && ftp->file) {
|
||||||
/* we have requested to get the modified-time of the file, this is yet
|
result = _ftp_getfiletime(conn, ftp->file);
|
||||||
again a grey area as the MDTM is not kosher RFC959 */
|
if(result)
|
||||||
ftpsendf(conn->firstsocket, conn, "MDTM %s", ftp->file);
|
return result;
|
||||||
|
|
||||||
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
|
|
||||||
if(nread < 0)
|
|
||||||
return CURLE_OPERATION_TIMEOUTED;
|
|
||||||
|
|
||||||
if(ftpcode == 213) {
|
|
||||||
/* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
|
|
||||||
last .sss part is optional and means fractions of a second */
|
|
||||||
int year, month, day, hour, minute, second;
|
|
||||||
if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
|
|
||||||
&year, &month, &day, &hour, &minute, &second)) {
|
|
||||||
/* we have a time, reformat it */
|
|
||||||
time_t secs=time(NULL);
|
|
||||||
sprintf(buf, "%04d%02d%02d %02d:%02d:%02d",
|
|
||||||
year, month, day, hour, minute, second);
|
|
||||||
/* now, convert this into a time() value: */
|
|
||||||
data->progress.filetime = curl_getdate(buf, &secs);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
infof(data, "unsupported MDTM reply format\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we have selected NOBODY, it means that we only want file information.
|
/* If we have selected NOBODY, it means that we only want file information.
|
||||||
@ -717,39 +782,26 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
/* The SIZE command is _not_ RFC 959 specified, and therefor many servers
|
/* The SIZE command is _not_ RFC 959 specified, and therefor many servers
|
||||||
may not support it! It is however the only way we have to get a file's
|
may not support it! It is however the only way we have to get a file's
|
||||||
size! */
|
size! */
|
||||||
int filesize;
|
ssize_t filesize;
|
||||||
|
|
||||||
/* Some servers return different sizes for different modes, and thus we
|
/* Some servers return different sizes for different modes, and thus we
|
||||||
must set the proper type before we check the size */
|
must set the proper type before we check the size */
|
||||||
ftpsendf(conn->firstsocket, conn, "TYPE %s",
|
result = _ftp_transfertype(conn, data->bits.ftp_ascii);
|
||||||
(data->bits.ftp_ascii)?"A":"I");
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
|
/* failing to get size is not a serious error */
|
||||||
if(nread < 0)
|
result = _ftp_getsize(conn, ftp->file, &filesize);
|
||||||
return CURLE_OPERATION_TIMEOUTED;
|
|
||||||
|
|
||||||
if(ftpcode != 200) {
|
|
||||||
failf(data, "Couldn't set %s mode",
|
|
||||||
(data->bits.ftp_ascii)?"ASCII":"binary");
|
|
||||||
return (data->bits.ftp_ascii)? CURLE_FTP_COULDNT_SET_ASCII:
|
|
||||||
CURLE_FTP_COULDNT_SET_BINARY;
|
|
||||||
}
|
|
||||||
|
|
||||||
ftpsendf(conn->firstsocket, conn, "SIZE %s", ftp->file);
|
|
||||||
|
|
||||||
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
|
|
||||||
if(nread < 0)
|
|
||||||
return CURLE_OPERATION_TIMEOUTED;
|
|
||||||
|
|
||||||
if(ftpcode == 213) {
|
|
||||||
|
|
||||||
/* get the size from the ascii string: */
|
|
||||||
filesize = atoi(buf+4);
|
|
||||||
|
|
||||||
|
if(CURLE_OK == result) {
|
||||||
sprintf(buf, "Content-Length: %d\r\n", filesize);
|
sprintf(buf, "Content-Length: %d\r\n", filesize);
|
||||||
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
|
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we asked for a time of the file and we actually got one as
|
||||||
|
well, we "emulate" a HTTP-style header in our output. */
|
||||||
|
|
||||||
#ifdef HAVE_STRFTIME
|
#ifdef HAVE_STRFTIME
|
||||||
if(data->bits.get_filetime && data->progress.filetime) {
|
if(data->bits.get_filetime && data->progress.filetime) {
|
||||||
@ -768,7 +820,6 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
@ -1312,19 +1363,9 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
if(data->bits.upload) {
|
if(data->bits.upload) {
|
||||||
|
|
||||||
/* Set type to binary (unless specified ASCII) */
|
/* Set type to binary (unless specified ASCII) */
|
||||||
ftpsendf(conn->firstsocket, conn, "TYPE %s",
|
result = _ftp_transfertype(conn, data->bits.ftp_ascii);
|
||||||
(data->bits.ftp_ascii)?"A":"I");
|
if(result)
|
||||||
|
return result;
|
||||||
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
|
|
||||||
if(nread < 0)
|
|
||||||
return CURLE_OPERATION_TIMEOUTED;
|
|
||||||
|
|
||||||
if(ftpcode != 200) {
|
|
||||||
failf(data, "Couldn't set %s mode",
|
|
||||||
(data->bits.ftp_ascii)?"ASCII":"binary");
|
|
||||||
return (data->bits.ftp_ascii)? CURLE_FTP_COULDNT_SET_ASCII:
|
|
||||||
CURLE_FTP_COULDNT_SET_BINARY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(conn->resume_from) {
|
if(conn->resume_from) {
|
||||||
/* we're about to continue the uploading of a file */
|
/* we're about to continue the uploading of a file */
|
||||||
@ -1344,19 +1385,10 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
/* we could've got a specified offset from the command line,
|
/* we could've got a specified offset from the command line,
|
||||||
but now we know we didn't */
|
but now we know we didn't */
|
||||||
|
|
||||||
ftpsendf(conn->firstsocket, conn, "SIZE %s", ftp->file);
|
if(CURLE_OK != _ftp_getsize(conn, ftp->file, &conn->resume_from)) {
|
||||||
|
failf(data, "Couldn't get remote file size");
|
||||||
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
|
|
||||||
if(nread < 0)
|
|
||||||
return CURLE_OPERATION_TIMEOUTED;
|
|
||||||
|
|
||||||
if(ftpcode != 213) {
|
|
||||||
failf(data, "Couldn't get file size: %s", buf+4);
|
|
||||||
return CURLE_FTP_COULDNT_GET_SIZE;
|
return CURLE_FTP_COULDNT_GET_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get the size from the ascii string: */
|
|
||||||
conn->resume_from = atoi(buf+4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(conn->resume_from) {
|
if(conn->resume_from) {
|
||||||
@ -1380,8 +1412,7 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
|
|
||||||
passed += actuallyread;
|
passed += actuallyread;
|
||||||
if(actuallyread != readthisamountnow) {
|
if(actuallyread != readthisamountnow) {
|
||||||
failf(data, "Could only read %d bytes from the input\n",
|
failf(data, "Could only read %d bytes from the input\n", passed);
|
||||||
passed);
|
|
||||||
return CURLE_FTP_COULDNT_USE_REST;
|
return CURLE_FTP_COULDNT_USE_REST;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1427,6 +1458,7 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(data->bits.ftp_use_port) {
|
if(data->bits.ftp_use_port) {
|
||||||
|
/* PORT means we are now awaiting the server to connect to us. */
|
||||||
result = AllowServerConnect(data, conn, portsock);
|
result = AllowServerConnect(data, conn, portsock);
|
||||||
if( result )
|
if( result )
|
||||||
return result;
|
return result;
|
||||||
@ -1495,16 +1527,9 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
dirlist = TRUE;
|
dirlist = TRUE;
|
||||||
|
|
||||||
/* Set type to ASCII */
|
/* Set type to ASCII */
|
||||||
ftpsendf(conn->firstsocket, conn, "TYPE A");
|
result = _ftp_transfertype(conn, TRUE /* ASCII enforced */);
|
||||||
|
if(result)
|
||||||
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
|
return result;
|
||||||
if(nread < 0)
|
|
||||||
return CURLE_OPERATION_TIMEOUTED;
|
|
||||||
|
|
||||||
if(ftpcode != 200) {
|
|
||||||
failf(data, "Couldn't set ascii mode");
|
|
||||||
return CURLE_FTP_COULDNT_SET_ASCII;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if this output is to be machine-parsed, the NLST command will be
|
/* if this output is to be machine-parsed, the NLST command will be
|
||||||
better used since the LIST command output is not specified or
|
better used since the LIST command output is not specified or
|
||||||
@ -1516,19 +1541,9 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Set type to binary (unless specified ASCII) */
|
/* Set type to binary (unless specified ASCII) */
|
||||||
ftpsendf(conn->firstsocket, conn, "TYPE %s",
|
result = _ftp_transfertype(conn, data->bits.ftp_ascii);
|
||||||
(data->bits.ftp_ascii)?"A":"I");
|
if(result)
|
||||||
|
return result;
|
||||||
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
|
|
||||||
if(nread < 0)
|
|
||||||
return CURLE_OPERATION_TIMEOUTED;
|
|
||||||
|
|
||||||
if(ftpcode != 200) {
|
|
||||||
failf(data, "Couldn't set %s mode",
|
|
||||||
(data->bits.ftp_ascii)?"ASCII":"binary");
|
|
||||||
return (data->bits.ftp_ascii)? CURLE_FTP_COULDNT_SET_ASCII:
|
|
||||||
CURLE_FTP_COULDNT_SET_BINARY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(conn->resume_from) {
|
if(conn->resume_from) {
|
||||||
|
|
||||||
@ -1537,22 +1552,18 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
* We start with trying to use the SIZE command to figure out the size
|
* We start with trying to use the SIZE command to figure out the size
|
||||||
* of the file we're gonna get. If we can get the size, this is by far
|
* of the file we're gonna get. If we can get the size, this is by far
|
||||||
* the best way to know if we're trying to resume beyond the EOF. */
|
* the best way to know if we're trying to resume beyond the EOF. */
|
||||||
|
int foundsize=-1;
|
||||||
|
|
||||||
ftpsendf(conn->firstsocket, conn, "SIZE %s", ftp->file);
|
result = _ftp_getsize(conn, ftp->file, &foundsize);
|
||||||
|
|
||||||
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
|
if(CURLE_OK != result) {
|
||||||
if(nread < 0)
|
infof(data, "ftp server doesn't support SIZE");
|
||||||
return CURLE_OPERATION_TIMEOUTED;
|
|
||||||
|
|
||||||
if(ftpcode != 213) {
|
|
||||||
infof(data, "server doesn't support SIZE: %s", buf+4);
|
|
||||||
/* We couldn't get the size and therefore we can't know if there
|
/* We couldn't get the size and therefore we can't know if there
|
||||||
really is a part of the file left to get, although the server
|
really is a part of the file left to get, although the server
|
||||||
will just close the connection when we start the connection so it
|
will just close the connection when we start the connection so it
|
||||||
won't cause us any harm, just not make us exit as nicely. */
|
won't cause us any harm, just not make us exit as nicely. */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int foundsize=atoi(buf+4);
|
|
||||||
/* We got a file size report, so we check that there actually is a
|
/* We got a file size report, so we check that there actually is a
|
||||||
part of the file left to get, or else we go home. */
|
part of the file left to get, or else we go home. */
|
||||||
if(conn->resume_from< 0) {
|
if(conn->resume_from< 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user