summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/lib/ftp.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/lib/ftp.c')
-rw-r--r--Utilities/cmcurl/lib/ftp.c121
1 files changed, 70 insertions, 51 deletions
diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c
index f8f970c..425b0af 100644
--- a/Utilities/cmcurl/lib/ftp.c
+++ b/Utilities/cmcurl/lib/ftp.c
@@ -175,6 +175,7 @@ const struct Curl_handler Curl_handler_ftp = {
ftp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_FTP, /* defport */
CURLPROTO_FTP, /* protocol */
CURLPROTO_FTP, /* family */
@@ -205,6 +206,7 @@ const struct Curl_handler Curl_handler_ftps = {
ftp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_FTPS, /* defport */
CURLPROTO_FTPS, /* protocol */
CURLPROTO_FTP, /* family */
@@ -1090,7 +1092,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
else
res = NULL; /* failure! */
- if(res == NULL) {
+ if(!res) {
failf(data, "failed to resolve the address provided to PORT: %s", host);
free(addr);
return CURLE_FTP_PORT_FAILED;
@@ -1357,7 +1359,7 @@ static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data)
struct FTP *ftp = data->req.p.ftp;
struct connectdata *conn = data->conn;
- if(ftp->transfer != FTPTRANSFER_BODY) {
+ if(ftp->transfer != PPTRANSFER_BODY) {
/* doesn't transfer any data */
/* still possibly do PRE QUOTE jobs */
@@ -1378,7 +1380,7 @@ static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data)
result = Curl_pp_sendf(data, &ftpc->pp, "PRET %s",
data->set.str[STRING_CUSTOMREQUEST]?
data->set.str[STRING_CUSTOMREQUEST]:
- (data->set.ftp_list_only?"NLST":"LIST"));
+ (data->state.list_only?"NLST":"LIST"));
else if(data->set.upload)
result = Curl_pp_sendf(data, &ftpc->pp, "PRET STOR %s",
conn->proto.ftpc.file);
@@ -1401,7 +1403,7 @@ static CURLcode ftp_state_rest(struct Curl_easy *data,
struct FTP *ftp = data->req.p.ftp;
struct ftp_conn *ftpc = &conn->proto.ftpc;
- if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
+ if((ftp->transfer != PPTRANSFER_BODY) && ftpc->file) {
/* if a "head"-like request is being made (on a file) */
/* Determine if server can respond to REST command and therefore
@@ -1423,7 +1425,7 @@ static CURLcode ftp_state_size(struct Curl_easy *data,
struct FTP *ftp = data->req.p.ftp;
struct ftp_conn *ftpc = &conn->proto.ftpc;
- if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
+ if((ftp->transfer == PPTRANSFER_INFO) && ftpc->file) {
/* if a "head"-like request is being made (on a file) */
/* we know ftpc->file is a valid pointer to a file name */
@@ -1485,7 +1487,7 @@ static CURLcode ftp_state_list(struct Curl_easy *data)
cmd = aprintf("%s%s%s",
data->set.str[STRING_CUSTOMREQUEST]?
data->set.str[STRING_CUSTOMREQUEST]:
- (data->set.ftp_list_only?"NLST":"LIST"),
+ (data->state.list_only?"NLST":"LIST"),
lstArg? " ": "",
lstArg? lstArg: "");
free(lstArg);
@@ -1525,17 +1527,17 @@ static CURLcode ftp_state_type(struct Curl_easy *data)
information. Which in FTP can't be much more than the file size and
date. */
if(data->set.opt_no_body && ftpc->file &&
- ftp_need_type(conn, data->set.prefer_ascii)) {
+ ftp_need_type(conn, data->state.prefer_ascii)) {
/* The SIZE command is _not_ RFC 959 specified, and therefore many servers
may not support it! It is however the only way we have to get a file's
size! */
- ftp->transfer = FTPTRANSFER_INFO;
+ ftp->transfer = PPTRANSFER_INFO;
/* this means no actual transfer will be made */
/* Some servers return different sizes for different modes, and thus we
must set the proper type before we check the size */
- result = ftp_nb_type(data, conn, data->set.prefer_ascii, FTP_TYPE);
+ result = ftp_nb_type(data, conn, data->state.prefer_ascii, FTP_TYPE);
if(result)
return result;
}
@@ -1578,6 +1580,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
struct connectdata *conn = data->conn;
struct FTP *ftp = data->req.p.ftp;
struct ftp_conn *ftpc = &conn->proto.ftpc;
+ bool append = data->set.remote_append;
if((data->state.resume_from && !sizechecked) ||
((data->state.resume_from > 0) && sizechecked)) {
@@ -1604,7 +1607,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
}
/* enable append */
- data->set.ftp_append = TRUE;
+ append = TRUE;
/* Let's read off the proper amount of bytes from the input. */
if(conn->seek_func) {
@@ -1652,7 +1655,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
/* Set ->transfer so that we won't get any error in
* ftp_done() because we didn't transfer anything! */
- ftp->transfer = FTPTRANSFER_NONE;
+ ftp->transfer = PPTRANSFER_NONE;
state(data, FTP_STOP);
return CURLE_OK;
@@ -1661,8 +1664,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
/* we've passed, proceed as normal */
} /* resume_from */
- result = Curl_pp_sendf(data, &ftpc->pp,
- data->set.ftp_append?"APPE %s":"STOR %s",
+ result = Curl_pp_sendf(data, &ftpc->pp, append?"APPE %s":"STOR %s",
ftpc->file);
if(!result)
state(data, FTP_STOR);
@@ -1739,7 +1741,7 @@ static CURLcode ftp_state_quote(struct Curl_easy *data,
result = ftp_state_cwd(data, conn);
break;
case FTP_RETR_PREQUOTE:
- if(ftp->transfer != FTPTRANSFER_BODY)
+ if(ftp->transfer != PPTRANSFER_BODY)
state(data, FTP_STOP);
else {
if(ftpc->known_filesize != -1) {
@@ -1747,13 +1749,19 @@ static CURLcode ftp_state_quote(struct Curl_easy *data,
result = ftp_state_retr(data, ftpc->known_filesize);
}
else {
- if(data->set.ignorecl) {
- /* This code is to support download of growing files. It prevents
- the state machine from requesting the file size from the
- server. With an unknown file size the download continues until
- the server terminates it, otherwise the client stops if the
- received byte count exceeds the reported file size. Set option
- CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this behavior.*/
+ if(data->set.ignorecl || data->state.prefer_ascii) {
+ /* 'ignorecl' is used to support download of growing files. It
+ prevents the state machine from requesting the file size from
+ the server. With an unknown file size the download continues
+ until the server terminates it, otherwise the client stops if
+ the received byte count exceeds the reported file size. Set
+ option CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this
+ behavior.
+
+ In addition: asking for the size for 'TYPE A' transfers is not
+ constructive since servers don't report the converted size. So
+ skip it.
+ */
result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
if(!result)
state(data, FTP_RETR);
@@ -2092,6 +2100,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
data->set.get_filetime &&
(data->info.filetime >= 0) ) {
char headerbuf[128];
+ int headerbuflen;
time_t filetime = data->info.filetime;
struct tm buffer;
const struct tm *tm = &buffer;
@@ -2101,7 +2110,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
return result;
/* format: "Tue, 15 Nov 1994 12:45:26" */
- msnprintf(headerbuf, sizeof(headerbuf),
+ headerbuflen = msnprintf(headerbuf, sizeof(headerbuf),
"Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
tm->tm_mday,
@@ -2110,7 +2119,8 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
tm->tm_hour,
tm->tm_min,
tm->tm_sec);
- result = Curl_client_write(data, CLIENTWRITE_BOTH, headerbuf, 0);
+ result = Curl_client_write(data, CLIENTWRITE_BOTH, headerbuf,
+ headerbuflen);
if(result)
return result;
} /* end of a ridiculous amount of conditionals */
@@ -2133,7 +2143,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
default:
if(data->info.filetime <= data->set.timevalue) {
infof(data, "The requested document is not new enough\n");
- ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
+ ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */
data->info.timecond = TRUE;
state(data, FTP_STOP);
return CURLE_OK;
@@ -2142,7 +2152,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
case CURL_TIMECOND_IFUNMODSINCE:
if(data->info.filetime > data->set.timevalue) {
infof(data, "The requested document is not old enough\n");
- ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
+ ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */
data->info.timecond = TRUE;
state(data, FTP_STOP);
return CURLE_OK;
@@ -2250,7 +2260,7 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
/* Set ->transfer so that we won't get any error in ftp_done()
* because we didn't transfer the any file */
- ftp->transfer = FTPTRANSFER_NONE;
+ ftp->transfer = PPTRANSFER_NONE;
state(data, FTP_STOP);
return CURLE_OK;
}
@@ -2303,17 +2313,21 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data,
}
else if(ftpcode == 550) { /* "No such file or directory" */
- failf(data, "The file does not exist");
- return CURLE_REMOTE_FILE_NOT_FOUND;
+ /* allow a SIZE failure for (resumed) uploads, when probing what command
+ to use */
+ if(instate != FTP_STOR_SIZE) {
+ failf(data, "The file does not exist");
+ return CURLE_REMOTE_FILE_NOT_FOUND;
+ }
}
if(instate == FTP_SIZE) {
#ifdef CURL_FTP_HTTPSTYLE_HEAD
if(-1 != filesize) {
char clbuf[128];
- msnprintf(clbuf, sizeof(clbuf),
+ int clbuflen = msnprintf(clbuf, sizeof(clbuf),
"Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
- result = Curl_client_write(data, CLIENTWRITE_BOTH, clbuf, 0);
+ result = Curl_client_write(data, CLIENTWRITE_BOTH, clbuf, clbuflen);
if(result)
return result;
}
@@ -2347,7 +2361,8 @@ static CURLcode ftp_state_rest_resp(struct Curl_easy *data,
#ifdef CURL_FTP_HTTPSTYLE_HEAD
if(ftpcode == 350) {
char buffer[24]= { "Accept-ranges: bytes\r\n" };
- result = Curl_client_write(data, CLIENTWRITE_BOTH, buffer, 0);
+ result = Curl_client_write(data, CLIENTWRITE_BOTH, buffer,
+ strlen(buffer));
if(result)
return result;
}
@@ -2448,7 +2463,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
*/
if((instate != FTP_LIST) &&
- !data->set.prefer_ascii &&
+ !data->state.prefer_ascii &&
(ftp->downloadsize < 1)) {
/*
* It seems directory listings either don't show the size or very
@@ -2476,7 +2491,8 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
bytes--;
}
/* if we have nothing but digits: */
- if(bytes++) {
+ if(bytes) {
+ ++bytes;
/* get the number! */
(void)curlx_strtoofft(bytes, NULL, 0, &size);
}
@@ -2487,7 +2503,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
if(size > data->req.maxdownload && data->req.maxdownload > 0)
size = data->req.size = data->req.maxdownload;
- else if((instate != FTP_LIST) && (data->set.prefer_ascii))
+ else if((instate != FTP_LIST) && (data->state.prefer_ascii))
size = -1; /* kludge for servers that understate ASCII mode file size */
infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
@@ -2521,7 +2537,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
else {
if((instate == FTP_LIST) && (ftpcode == 450)) {
/* simply no matching files in the dir listing */
- ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
+ ftp->transfer = PPTRANSFER_NONE; /* don't download anything */
state(data, FTP_STOP); /* this phase is over */
}
else {
@@ -3291,7 +3307,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
close_secondarysocket(data, conn);
}
- if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
+ if(!result && (ftp->transfer == PPTRANSFER_BODY) && ftpc->ctl_valid &&
pp->pending_resp && !premature) {
/*
* Let's see what the server says about the transfer we just performed,
@@ -3314,8 +3330,10 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
}
- if(result)
+ if(result) {
+ Curl_safefree(ftp->pathalloc);
return result;
+ }
if(ftpc->dont_check && data->req.maxdownload > 0) {
/* we have just sent ABOR and there is no reliable way to check if it was
@@ -3351,7 +3369,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
if((-1 != data->state.infilesize) &&
(data->state.infilesize != data->req.writebytecount) &&
!data->set.crlf &&
- (ftp->transfer == FTPTRANSFER_BODY)) {
+ (ftp->transfer == PPTRANSFER_BODY)) {
failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
" out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
data->req.bytecount, data->state.infilesize);
@@ -3383,7 +3401,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
}
/* clear these for next connection */
- ftp->transfer = FTPTRANSFER_BODY;
+ ftp->transfer = PPTRANSFER_BODY;
ftpc->dont_check = FALSE;
/* Send any post-transfer QUOTE strings? */
@@ -3594,7 +3612,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
*completep = 0;
}
- if(ftp->transfer <= FTPTRANSFER_INFO) {
+ if(ftp->transfer <= PPTRANSFER_INFO) {
/* a transfer is about to take place, or if not a file name was given
so we'll do a SIZE on it later and then we need the right TYPE first */
@@ -3620,7 +3638,8 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
}
}
else if(data->set.upload) {
- result = ftp_nb_type(data, conn, data->set.prefer_ascii, FTP_STOR_TYPE);
+ result = ftp_nb_type(data, conn, data->state.prefer_ascii,
+ FTP_STOR_TYPE);
if(result)
return result;
@@ -3641,13 +3660,13 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
if(result)
;
- else if(data->set.ftp_list_only || !ftpc->file) {
+ else if(data->state.list_only || !ftpc->file) {
/* The specified path ends with a slash, and therefore we think this
is a directory that is requested, use LIST. But before that we
need to set ASCII transfer mode. */
/* But only if a body transfer was requested. */
- if(ftp->transfer == FTPTRANSFER_BODY) {
+ if(ftp->transfer == PPTRANSFER_BODY) {
result = ftp_nb_type(data, conn, TRUE, FTP_LIST_TYPE);
if(result)
return result;
@@ -3655,7 +3674,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
/* otherwise just fall through */
}
else {
- result = ftp_nb_type(data, conn, data->set.prefer_ascii,
+ result = ftp_nb_type(data, conn, data->state.prefer_ascii,
FTP_RETR_TYPE);
if(result)
return result;
@@ -3703,7 +3722,7 @@ CURLcode ftp_perform(struct Curl_easy *data,
if(data->set.opt_no_body) {
/* requested no body means no transfer... */
struct FTP *ftp = data->req.p.ftp;
- ftp->transfer = FTPTRANSFER_INFO;
+ ftp->transfer = PPTRANSFER_INFO;
}
*dophase_done = FALSE; /* not done yet */
@@ -4194,7 +4213,7 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
ftpc->file = NULL; /* instead of point to a zero byte,
we make it a NULL pointer */
- if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
+ if(data->set.upload && !ftpc->file && (ftp->transfer == PPTRANSFER_BODY)) {
/* We need a file name when uploading. Return error! */
failf(data, "Uploading to a URL without a file name!");
free(rawPath);
@@ -4242,7 +4261,7 @@ static CURLcode ftp_dophase_done(struct Curl_easy *data, bool connected)
}
}
- if(ftp->transfer != FTPTRANSFER_BODY)
+ if(ftp->transfer != PPTRANSFER_BODY)
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
else if(!connected)
@@ -4346,23 +4365,23 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
switch(command) {
case 'A': /* ASCII mode */
- data->set.prefer_ascii = TRUE;
+ data->state.prefer_ascii = TRUE;
break;
case 'D': /* directory mode */
- data->set.ftp_list_only = TRUE;
+ data->state.list_only = TRUE;
break;
case 'I': /* binary mode */
default:
/* switch off ASCII */
- data->set.prefer_ascii = FALSE;
+ data->state.prefer_ascii = FALSE;
break;
}
}
/* get some initial data into the ftp struct */
- ftp->transfer = FTPTRANSFER_BODY;
+ ftp->transfer = PPTRANSFER_BODY;
ftp->downloadsize = 0;
conn->proto.ftpc.known_filesize = -1; /* unknown size for now */