Newer
Older
ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
slash_pos?(int)(slash_pos-cur_pos):1,
NULL);
if(!ftpc->dirs[0]) {
Daniel Stenberg
committed
freedirs(ftpc);
return CURLE_OUT_OF_MEMORY;
}
ftpc->dirdepth = 1; /* we consider it to be a single dir */
filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
filename = cur_pos; /* this is a file name only */
default: /* allow pretty much anything */
case FTPFILE_MULTICWD:
ftpc->dirdepth = 0;
ftpc->diralloc = 5; /* default dir depth to allocate */
ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
if(!ftpc->dirs)
Daniel Stenberg
committed
/* we have a special case for listing the root dir only */
if(strequal(path_to_use, "/")) {
cur_pos++; /* make it point to the zero byte */
ftpc->dirs[0] = strdup("/");
ftpc->dirdepth++;
}
else {
/* parse the URL path into separate path components */
Daniel Stenberg
committed
while((slash_pos = strchr(cur_pos, '/')) != NULL) {
Daniel Stenberg
committed
/* 1 or 0 to indicate absolute directory */
Daniel Stenberg
committed
bool absolute_dir = (bool)((cur_pos - data->state.path > 0) &&
Daniel Stenberg
committed
(ftpc->dirdepth == 0));
/* seek out the next path component */
Daniel Stenberg
committed
if(slash_pos-cur_pos) {
Daniel Stenberg
committed
/* we skip empty path components, like "x//y" since the FTP command
CWD requires a parameter and a non-existant parameter a) doesn't
work on many servers and b) has no effect on the others. */
int len = (int)(slash_pos - cur_pos + absolute_dir);
ftpc->dirs[ftpc->dirdepth] =
curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);
Daniel Stenberg
committed
if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
Daniel Stenberg
committed
failf(data, "no memory");
Daniel Stenberg
committed
freedirs(ftpc);
Daniel Stenberg
committed
return CURLE_OUT_OF_MEMORY;
}
Daniel Stenberg
committed
if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
Daniel Stenberg
committed
free(ftpc->dirs[ftpc->dirdepth]);
Daniel Stenberg
committed
freedirs(ftpc);
Daniel Stenberg
committed
return CURLE_URL_MALFORMAT;
}
Daniel Stenberg
committed
else {
cur_pos = slash_pos + 1; /* jump to the rest of the string */
continue;
Daniel Stenberg
committed
cur_pos = slash_pos + 1; /* jump to the rest of the string */
if(++ftpc->dirdepth >= ftpc->diralloc) {
/* enlarge array */
char *bigger;
ftpc->diralloc *= 2; /* double the size each time */
bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
if(!bigger) {
Daniel Stenberg
committed
freedirs(ftpc);
Daniel Stenberg
committed
return CURLE_OUT_OF_MEMORY;
}
ftpc->dirs = (char **)bigger;
}
}
}
filename = cur_pos; /* the rest is the file name */
break;
} /* switch */
if(filename && *filename) {
ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
Daniel Stenberg
committed
freedirs(ftpc);
failf(data, "no memory");
return CURLE_OUT_OF_MEMORY;
}
Daniel Stenberg
committed
if(isBadFtpString(ftpc->file)) {
Daniel Stenberg
committed
freedirs(ftpc);
return CURLE_URL_MALFORMAT;
}
}
else
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)) {
/* We need a file name when uploading. Return error! */
failf(data, "Uploading to a URL without a file name!");
return CURLE_URL_MALFORMAT;
}
ftpc->cwddone = FALSE; /* default to not done */
if(ftpc->prevpath) {
Daniel Stenberg
committed
/* prevpath is "raw" so we convert the input path before we compare the
strings */
int dlen;
char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
Daniel Stenberg
committed
freedirs(ftpc);
Daniel Stenberg
committed
return CURLE_OUT_OF_MEMORY;
Daniel Stenberg
committed
dlen -= ftpc->file?(int)strlen(ftpc->file):0;
if((dlen == (int)strlen(ftpc->prevpath)) &&
strnequal(path, ftpc->prevpath, dlen)) {
infof(data, "Request has same path as previous transfer\n");
ftpc->cwddone = TRUE;
Daniel Stenberg
committed
free(path);
Daniel Stenberg
committed
}
/* call this when the DO phase has completed */
static CURLcode ftp_dophase_done(struct connectdata *conn,
bool connected)
{
CURLcode result = CURLE_OK;
Daniel Stenberg
committed
struct FTP *ftp = conn->data->state.proto.ftp;
struct ftp_conn *ftpc = &conn->proto.ftpc;
if(connected)
result = ftp_nextconnect(conn);
if(result && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
/* Failure detected, close the second socket if it was created already */
sclose(conn->sock[SECONDARYSOCKET]);
conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
}
if(ftp->transfer != FTPTRANSFER_BODY)
/* no data to transfer */
result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
else if(!connected)
/* since we didn't connect now, we want do_more to get called */
conn->bits.do_more = TRUE;
ftpc->ctl_valid = TRUE; /* seems good */
return result;
}
/* called from multi.c while DOing */
static CURLcode ftp_doing(struct connectdata *conn,
Patrick Monnerat
committed
bool *dophase_done)
{
CURLcode result;
result = ftp_multi_statemach(conn, dophase_done);
if(*dophase_done) {
result = ftp_dophase_done(conn, FALSE /* not connected */);
DEBUGF(infof(conn->data, "DO phase is complete\n"));
}
return result;
}
Daniel Stenberg
committed
/***********************************************************************
*
* ftp_regular_transfer()
*
* The input argument is already checked for validity.
*
* Performs all commands done before a regular transfer between a local and a
* remote host.
Daniel Stenberg
committed
*
* ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
* ftp_done() function without finding any major problem.
Daniel Stenberg
committed
*/
static
CURLcode ftp_regular_transfer(struct connectdata *conn,
bool *dophase_done)
Daniel Stenberg
committed
{
CURLcode result=CURLE_OK;
Daniel Stenberg
committed
struct SessionHandle *data = conn->data;
struct ftp_conn *ftpc = &conn->proto.ftpc;
Daniel Stenberg
committed
data->req.size = -1; /* make sure this is unknown at this point */
Daniel Stenberg
committed
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);
Curl_pgrsSetUploadSize(data, 0);
Curl_pgrsSetDownloadSize(data, 0);
ftpc->ctl_valid = TRUE; /* starts good */
result = ftp_perform(conn,
&connected, /* have we connected after PASV/PORT */
dophase_done); /* all commands in the DO-phase done? */
if(CURLE_OK == result) {
if(!*dophase_done)
/* the DO phase has not completed yet */
return CURLE_OK;
result = ftp_dophase_done(conn, connected);
if(result)
return result;
}
else
Daniel Stenberg
committed
freedirs(ftpc);
return result;
}
static CURLcode ftp_setup_connection(struct connectdata * conn)
Patrick Monnerat
committed
{
struct SessionHandle *data = conn->data;
char * type;
char command;
if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
/* Unless we have asked to tunnel ftp operations through the proxy, we
switch and use HTTP operations only */
#ifndef CURL_DISABLE_HTTP
Daniel Stenberg
committed
if(conn->handler == &Curl_handler_ftp)
conn->handler = &Curl_handler_ftp_proxy;
else {
#ifdef USE_SSL
conn->handler = &Curl_handler_ftps_proxy;
#else
failf(data, "FTPS not supported!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif
}
Daniel Stenberg
committed
/*
* We explicitly mark this connection as persistent here as we're doing
* FTP over HTTP and thus we accidentally avoid setting this value
* otherwise.
*/
conn->bits.close = FALSE;
Patrick Monnerat
committed
#else
failf(data, "FTP over http proxy requires HTTP support built-in!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif
}
Daniel Stenberg
committed
data->state.path++; /* don't include the initial slash */
Patrick Monnerat
committed
/* FTP URLs support an extension like ";type=<typecode>" that
* we'll try to get now! */
Daniel Stenberg
committed
type = strstr(data->state.path, ";type=");
Patrick Monnerat
committed
Daniel Stenberg
committed
if(!type)
Patrick Monnerat
committed
type = strstr(conn->host.rawalloc, ";type=");
Daniel Stenberg
committed
if(type) {
Patrick Monnerat
committed
*type = 0; /* it was in the middle of the hostname */
command = Curl_raw_toupper(type[6]);
Patrick Monnerat
committed
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
switch (command) {
case 'A': /* ASCII mode */
data->set.prefer_ascii = TRUE;
break;
case 'D': /* directory mode */
data->set.ftp_list_only = TRUE;
break;
case 'I': /* binary mode */
default:
/* switch off ASCII */
data->set.prefer_ascii = FALSE;
break;
}
}
return CURLE_OK;
}
#endif /* CURL_DISABLE_FTP */