1
0
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:
Daniel Stenberg 2001-08-23 06:10:01 +00:00
parent e3d7cc895b
commit 83a8786fe1

239
lib/ftp.c
View File

@ -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) {