111
109
#define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV
112
#ifdef CURL_DISABLE_VERBOSE_STRINGS
113
#define ftp_pasv_verbose(a,b,c,d) do { } while (0)
114
116
/* Local API functions */
115
117
static CURLcode ftp_sendquote(struct connectdata *conn,
116
118
struct curl_slist *quote);
117
static CURLcode ftp_cwd(struct connectdata *conn, char *path);
118
static CURLcode ftp_mkd(struct connectdata *conn, char *path);
119
static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path);
120
119
static CURLcode ftp_quit(struct connectdata *conn);
121
static CURLcode ftp_3rdparty_pretransfer(struct connectdata *conn);
122
static CURLcode ftp_3rdparty_transfer(struct connectdata *conn);
123
120
static CURLcode ftp_parse_url_path(struct connectdata *conn);
124
static CURLcode ftp_cwd_and_create_path(struct connectdata *conn);
125
121
static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
126
static CURLcode ftp_3rdparty(struct connectdata *conn);
122
#ifndef CURL_DISABLE_VERBOSE_STRINGS
127
123
static void ftp_pasv_verbose(struct connectdata *conn,
128
124
Curl_addrinfo *ai,
129
125
char *newhost, /* ascii version */
131
128
static CURLcode ftp_state_post_rest(struct connectdata *conn);
132
129
static CURLcode ftp_state_post_cwd(struct connectdata *conn);
133
130
static CURLcode ftp_state_quote(struct connectdata *conn,
134
131
bool init, ftpstate instate);
132
static CURLcode ftp_nb_type(struct connectdata *conn,
133
bool ascii, ftpstate state);
134
static int ftp_need_type(struct connectdata *conn,
136
137
/* easy-to-use macro: */
137
#define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z))) return result
138
#define NBFTPSENDF(x,y,z) if((result = Curl_nbftpsendf(x,y,z))) return result
138
#define FTPSENDF(x,y,z) if ((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \
140
#define NBFTPSENDF(x,y,z) if ((result = Curl_nbftpsendf(x,y,z)) != CURLE_OK) \
140
static void freedirs(struct FTP *ftp)
143
static void freedirs(struct connectdata *conn)
145
struct ftp_conn *ftpc = &conn->proto.ftpc;
146
struct FTP *ftp = conn->data->reqdata.proto.ftp;
144
for (i=0; i < ftp->dirdepth; i++){
150
for (i=0; i < ftpc->dirdepth; i++){
332
343
/* output debug output if that is requested */
333
344
if(data->set.verbose)
334
345
Curl_debug(data, CURLINFO_HEADER_IN,
335
ftp->linestart_resp, perline, conn);
346
ftpc->linestart_resp, (size_t)perline, conn);
338
349
* We pass all response-lines to the callback function registered
339
350
* for "headers". The response lines can be seen as a kind of
342
result = Curl_client_write(data, CLIENTWRITE_HEADER,
343
ftp->linestart_resp, perline);
353
result = Curl_client_write(conn, CLIENTWRITE_HEADER,
354
ftpc->linestart_resp, perline);
347
if(perline>3 && lastline(ftp->linestart_resp)) {
358
if(perline>3 && lastline(ftpc->linestart_resp)) {
348
359
/* This is the end of the last line, copy the last line to the
349
360
start of the buffer and zero terminate, for old times sake (and
353
for(meow=ftp->linestart_resp, n=0; meow<ptr; meow++, n++)
364
for(meow=ftpc->linestart_resp, n=0; meow<ptr; meow++, n++)
355
366
*meow=0; /* zero terminate */
357
ftp->linestart_resp = ptr+1; /* advance pointer */
368
ftpc->linestart_resp = ptr+1; /* advance pointer */
358
369
i++; /* skip this before getting out */
360
*size = ftp->nread_resp; /* size of the response */
361
ftp->nread_resp = 0; /* restart */
371
*size = ftpc->nread_resp; /* size of the response */
372
ftpc->nread_resp = 0; /* restart */
364
375
perline=0; /* line starts over here */
365
ftp->linestart_resp = ptr+1;
376
ftpc->linestart_resp = ptr+1;
368
379
if(!keepon && (i != gotbytes)) {
465
475
the response for any given ftp response, not for the time
466
476
from connect to the given ftp response. */
467
477
timeout = data->set.ftp_response_timeout - /* timeout time */
468
Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
478
Curl_tvdiff(Curl_tvnow(), now); /* spent time */
469
479
else if(data->set.timeout)
470
480
/* if timeout is requested, find out how much remaining time we have */
471
481
timeout = data->set.timeout - /* timeout time */
472
Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
482
Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
474
484
/* Even without a requested timeout, we only wait response_time
475
485
seconds for the full response to arrive before we bail out */
476
timeout = ftp->response_time -
477
Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
486
timeout = ftpc->response_time -
487
Curl_tvdiff(Curl_tvnow(), now); /* spent time */
479
489
if(timeout <=0 ) {
480
490
failf(data, "FTP response timeout");
481
491
return CURLE_OPERATION_TIMEDOUT; /* already too little time */
485
495
interval_ms = 1 * 1000; /* use 1 second timeout intervals */
496
if(timeout < interval_ms)
497
interval_ms = timeout;
487
switch (Curl_select(sockfd, CURL_SOCKET_BAD, interval_ms)) {
499
switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, (int)interval_ms)) {
488
500
case -1: /* select() error, stop reading */
489
501
result = CURLE_RECV_ERROR;
490
failf(data, "FTP response aborted due to select() error: %d",
502
failf(data, "FTP response aborted due to select/poll error: %d",
493
505
case 0: /* timeout */
494
506
if(Curl_pgrsUpdate(conn))
1928
1979
/* We got a file size report, so we check that there actually is a
1929
1980
part of the file left to get, or else we go home. */
1930
if(conn->resume_from< 0) {
1981
if(data->reqdata.resume_from< 0) {
1931
1982
/* We're supposed to download the last abs(from) bytes */
1932
if(filesize < -conn->resume_from) {
1983
if(filesize < -data->reqdata.resume_from) {
1933
1984
failf(data, "Offset (%" FORMAT_OFF_T
1934
1985
") was beyond file size (%" FORMAT_OFF_T ")",
1935
conn->resume_from, filesize);
1986
data->reqdata.resume_from, filesize);
1936
1987
return CURLE_BAD_DOWNLOAD_RESUME;
1938
1989
/* convert to size to download */
1939
ftp->downloadsize = -conn->resume_from;
1990
ftp->downloadsize = -data->reqdata.resume_from;
1940
1991
/* download from where? */
1941
conn->resume_from = filesize - ftp->downloadsize;
1992
data->reqdata.resume_from = filesize - ftp->downloadsize;
1944
if(filesize < conn->resume_from) {
1995
if(filesize < data->reqdata.resume_from) {
1945
1996
failf(data, "Offset (%" FORMAT_OFF_T
1946
1997
") was beyond file size (%" FORMAT_OFF_T ")",
1947
conn->resume_from, filesize);
1998
data->reqdata.resume_from, filesize);
1948
1999
return CURLE_BAD_DOWNLOAD_RESUME;
1950
2001
/* Now store the number of bytes we are expected to download */
1951
ftp->downloadsize = filesize-conn->resume_from;
2002
ftp->downloadsize = filesize-data->reqdata.resume_from;
1955
2006
if(ftp->downloadsize == 0) {
1956
2007
/* no data to transfer */
1957
result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2008
result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1958
2009
infof(data, "File already completely downloaded\n");
1960
2011
/* Set no_transfer so that we won't get any error in Curl_ftp_done()
2793
2901
CURLcode Curl_ftp_connect(struct connectdata *conn,
2794
2902
bool *done) /* see description above */
2797
2904
CURLcode result;
2798
2905
#ifndef CURL_DISABLE_HTTP
2799
2906
/* for FTP over HTTP proxy */
2800
2907
struct HTTP http_proxy;
2801
2908
struct FTP *ftp_save;
2802
2909
#endif /* CURL_DISABLE_HTTP */
2910
struct ftp_conn *ftpc = &conn->proto.ftpc;
2911
struct SessionHandle *data=conn->data;
2804
2913
*done = FALSE; /* default to not done yet */
2806
ftp = (struct FTP *)calloc(sizeof(struct FTP), 1);
2808
return CURLE_OUT_OF_MEMORY;
2915
if (data->reqdata.proto.ftp) {
2916
Curl_ftp_disconnect(conn);
2917
free(data->reqdata.proto.ftp);
2918
data->reqdata.proto.ftp = NULL;
2810
conn->proto.ftp = ftp;
2921
result = ftp_init(conn);
2812
2925
/* We always support persistant connections on ftp */
2813
2926
conn->bits.close = FALSE;
2815
/* get some initial data into the ftp struct */
2816
ftp->bytecountp = &conn->bytecount;
2818
/* no need to duplicate them, this connectdata struct won't change */
2819
ftp->user = conn->user;
2820
ftp->passwd = conn->passwd;
2821
if (isBadFtpString(ftp->user) || isBadFtpString(ftp->passwd))
2822
return CURLE_URL_MALFORMAT;
2824
ftp->response_time = 3600; /* set default response time-out */
2928
ftpc->response_time = 3600000; /* set default response time-out */
2826
2930
#ifndef CURL_DISABLE_HTTP
2827
2931
if (conn->bits.tunnel_proxy && conn->bits.httpproxy) {
2884
2988
* Input argument is already checked for validity.
2886
CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
2990
CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status, bool premature)
2888
2992
struct SessionHandle *data = conn->data;
2889
struct FTP *ftp = conn->proto.ftp;
2993
struct FTP *ftp = data->reqdata.proto.ftp;
2994
struct ftp_conn *ftpc = &conn->proto.ftpc;
2892
2997
CURLcode result=CURLE_OK;
2893
bool was_ctl_valid = ftp->ctl_valid;
2998
bool was_ctl_valid = ftpc->ctl_valid;
2898
/* now store a copy of the directory we are in */
2900
free(ftp->prevpath);
2902
/* get the "raw" path */
2903
path = curl_easy_unescape(conn->data, conn->path, 0, NULL);
2905
return CURLE_OUT_OF_MEMORY;
2907
flen = ftp->file?strlen(ftp->file):0; /* file is "raw" already */
2908
dlen = strlen(path)-flen;
2909
if(dlen && !ftp->cwdfail) {
2910
ftp->prevpath = path;
2912
/* if 'path' is not the whole string */
2913
ftp->prevpath[dlen]=0; /* terminate */
2914
infof(data, "Remembering we are in dir %s\n", ftp->prevpath);
2917
ftp->prevpath = NULL; /* no path */
2920
/* free the dir tree and file parts */
3002
char *path_to_use = data->reqdata.path;
3003
struct Curl_transfer_keeper *k = &data->reqdata.keep;
3006
/* When the easy handle is removed from the multi while libcurl is still
3007
* trying to resolve the host name, it seems that the ftp struct is not
3008
* yet initialized, but the removal action calls Curl_done() which calls
3009
* this function. So we simply return success if no ftp pointer is set.
2923
3013
switch(status) {
2924
3014
case CURLE_BAD_DOWNLOAD_RESUME:
2926
3016
case CURLE_FTP_PORT_FAILED:
2927
3017
case CURLE_FTP_COULDNT_SET_BINARY:
2928
3018
case CURLE_FTP_COULDNT_RETR_FILE:
3019
case CURLE_FTP_COULDNT_STOR_FILE:
2929
3020
case CURLE_FTP_ACCESS_DENIED:
3021
case CURLE_FILESIZE_EXCEEDED:
2930
3022
/* the connection stays alive fine even though this happened */
2931
3023
/* fall-through */
2932
3024
case CURLE_OK: /* doesn't affect the control connection's status */
2933
ftp->ctl_valid = was_ctl_valid;
3026
ftpc->ctl_valid = was_ctl_valid;
3029
/* until we cope better with prematurely ended requests, let them
3030
* fallback as if in complete failure */
2935
3031
default: /* by default, an error means the control connection is
2936
3032
wedged and should not be used anymore */
2937
ftp->ctl_valid = FALSE;
3033
ftpc->ctl_valid = FALSE;
3034
ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3035
current path, as this connection is going */
3036
conn->bits.close = TRUE; /* marked for closure */
3040
/* now store a copy of the directory we are in */
3042
free(ftpc->prevpath);
3044
/* get the "raw" path */
3045
path = curl_easy_unescape(data, path_to_use, 0, NULL);
3047
return CURLE_OUT_OF_MEMORY;
3049
flen = ftp->file?strlen(ftp->file):0; /* file is "raw" already */
3050
dlen = strlen(path)-flen;
3051
if(dlen && !ftpc->cwdfail) {
3052
ftpc->prevpath = path;
3054
/* if 'path' is not the whole string */
3055
ftpc->prevpath[dlen]=0; /* terminate */
3056
infof(data, "Remembering we are in dir %s\n", ftpc->prevpath);
3059
ftpc->prevpath = NULL; /* no path */
3062
/* free the dir tree and file parts */
2941
3065
#ifdef HAVE_KRB4
2942
3066
Curl_sec_fflush_fd(conn, conn->sock[SECONDARYSOCKET]);
3078
3197
/***********************************************************************
3080
* ftp_transfertype()
3082
* Set transfer type. We only deal with ASCII or BINARY so this function
3201
* Returns TRUE if we in the current situation should send TYPE
3203
static int ftp_need_type(struct connectdata *conn,
3206
return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3209
/***********************************************************************
3213
* Set TYPE. We only deal with ASCII or BINARY so this function
3083
3214
* sets one of them.
3215
* If the transfer type is not sent, simulate on OK response in newstate
3085
static CURLcode ftp_transfertype(struct connectdata *conn,
3217
static CURLcode ftp_nb_type(struct connectdata *conn,
3218
bool ascii, ftpstate newstate)
3088
struct SessionHandle *data = conn->data;
3220
struct ftp_conn *ftpc = &conn->proto.ftpc;
3091
3221
CURLcode result;
3093
FTPSENDF(conn, "TYPE %s", ascii?"A":"I");
3095
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3099
if(ftpcode != 200) {
3100
failf(data, "Couldn't set %s mode",
3101
ascii?"ASCII":"binary");
3102
return ascii? CURLE_FTP_COULDNT_SET_ASCII:CURLE_FTP_COULDNT_SET_BINARY;
3222
int want = ascii?'A':'I';
3224
if (ftpc->transfertype == want) {
3225
state(conn, newstate);
3226
return ftp_state_type_resp(conn, 200, newstate);
3229
NBFTPSENDF(conn, "TYPE %c", want);
3230
state(conn, newstate);
3104
3232
/* keep track of our current transfer type */
3105
data->ftp_in_ascii_mode = ascii;
3233
ftpc->transfertype = (char)want;
3107
3234
return CURLE_OK;
3152
3282
if((-1 == to) && (from>=0)) {
3154
conn->resume_from = from;
3284
data->reqdata.resume_from = from;
3155
3285
DEBUGF(infof(conn->data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n",
3158
3288
else if(from < 0) {
3160
3290
totalsize = -from;
3161
conn->maxdownload = -from;
3162
conn->resume_from = from;
3291
data->reqdata.maxdownload = -from;
3292
data->reqdata.resume_from = from;
3163
3293
DEBUGF(infof(conn->data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n",
3168
3298
totalsize = to-from;
3169
conn->maxdownload = totalsize+1; /* include the last mentioned byte */
3170
conn->resume_from = from;
3299
data->reqdata.maxdownload = totalsize+1; /* include last byte */
3300
data->reqdata.resume_from = from;
3171
3301
DEBUGF(infof(conn->data, "FTP RANGE from %" FORMAT_OFF_T
3172
3302
" getting %" FORMAT_OFF_T " bytes\n",
3173
from, conn->maxdownload));
3303
from, data->reqdata.maxdownload));
3175
3305
DEBUGF(infof(conn->data, "range-download from %" FORMAT_OFF_T
3176
3306
" to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
3177
from, to, conn->maxdownload));
3178
ftp->dont_check = TRUE; /* dont check for successful transfer */
3307
from, to, data->reqdata.maxdownload));
3308
ftpc->dont_check = TRUE; /* dont check for successful transfer */
3311
data->reqdata.maxdownload = -1;
3180
3312
return CURLE_OK;
3482
3617
/* The FTP session may or may not have been allocated/setup at this point! */
3618
if(conn->data->reqdata.proto.ftp) {
3484
3619
(void)ftp_quit(conn); /* ignore errors on the QUIT */
3486
if(ftp->entrypath) {
3621
if(ftpc->entrypath) {
3487
3622
struct SessionHandle *data = conn->data;
3488
3623
data->state.most_recent_ftp_entrypath = NULL;
3489
free(ftp->entrypath);
3490
ftp->entrypath = NULL;
3498
free(ftp->prevpath);
3499
ftp->prevpath = NULL;
3505
/***********************************************************************
3509
* Makes a directory on the FTP server.
3513
static CURLcode ftp_mkd(struct connectdata *conn, char *path)
3515
CURLcode result=CURLE_OK;
3516
int ftpcode; /* for ftp status */
3519
/* Create a directory on the remote server */
3520
FTPSENDF(conn, "MKD %s", path);
3522
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3529
infof( conn->data , "Created remote directory %s\n" , path );
3532
failf(conn->data, "Permission denied to make directory %s", path);
3533
result = CURLE_FTP_ACCESS_DENIED;
3536
failf(conn->data, "unrecognized MKD response: %d", ftpcode );
3537
result = CURLE_FTP_ACCESS_DENIED;
3543
/***********************************************************************
3547
* Send 'CWD' to the remote server to Change Working Directory. It is the ftp
3548
* version of the unix 'cd' command. This function is only called from the
3549
* ftp_cwd_and_mkd() function these days.
3551
* This function does NOT call failf().
3554
CURLcode ftp_cwd(struct connectdata *conn, char *path)
3560
FTPSENDF(conn, "CWD %s", path);
3561
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3563
/* According to RFC959, CWD is supposed to return 250 on success, but
3564
there seem to be non-compliant FTP servers out there that return 200,
3565
so we accept any '2xy' code here. */
3566
if (ftpcode/100 != 2)
3567
result = CURLE_FTP_ACCESS_DENIED;
3573
/***********************************************************************
3577
* Change to the given directory. If the directory is not present, and we
3578
* have been told to allow it, then create the directory and cd to it.
3581
static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path)
3585
result = ftp_cwd(conn, path);
3587
if(conn->data->set.ftp_create_missing_dirs) {
3588
result = ftp_mkd(conn, path);
3590
/* ftp_mkd() calls failf() itself */
3592
result = ftp_cwd(conn, path);
3595
failf(conn->data, "Couldn't CWD to %s", path);
3602
/***********************************************************************
3604
* ftp_3rdparty_pretransfer()
3606
* Preparation for 3rd party transfer.
3609
static CURLcode ftp_3rdparty_pretransfer(struct connectdata *conn)
3611
CURLcode result = CURLE_OK;
3612
struct SessionHandle *data = conn->data;
3613
struct connectdata *sec_conn = conn->sec_conn;
3615
conn->xfertype = TARGET3RD;
3616
sec_conn->xfertype = SOURCE3RD;
3618
/* sets transfer type */
3619
result = ftp_transfertype(conn, data->set.ftp_ascii);
3623
result = ftp_transfertype(sec_conn, data->set.ftp_ascii);
3627
/* Send any PREQUOTE strings after transfer type is set? */
3628
if (data->set.source_prequote) {
3629
/* sends command(s) to source server before file transfer */
3630
result = ftp_sendquote(sec_conn, data->set.source_prequote);
3632
if (!result && data->set.prequote)
3633
result = ftp_sendquote(conn, data->set.prequote);
3640
/***********************************************************************
3642
* ftp_3rdparty_transfer()
3644
* Performs 3rd party transfer.
3647
static CURLcode ftp_3rdparty_transfer(struct connectdata *conn)
3649
CURLcode result = CURLE_OK;
3651
int ftpcode, ip[4], port[2];
3652
struct SessionHandle *data = conn->data;
3653
struct connectdata *sec_conn = conn->sec_conn;
3654
char *buf = data->state.buffer; /* this is our buffer */
3657
const char *stor_cmd;
3658
struct connectdata *pasv_conn;
3659
struct connectdata *port_conn;
3661
if (data->set.ftpport == NULL) {
3663
port_conn = sec_conn;
3666
pasv_conn = sec_conn;
3670
result = ftp_cwd_and_create_path(conn);
3674
/* sets the passive mode */
3675
FTPSENDF(pasv_conn, "%s", "PASV");
3676
result = Curl_GetFTPResponse(&nread, pasv_conn, &ftpcode);
3680
if (ftpcode != 227) {
3681
failf(data, "Odd return code after PASV: %03d", ftpcode);
3682
return CURLE_FTP_WEIRD_PASV_REPLY;
3686
if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
3687
&ip[0], &ip[1], &ip[2], &ip[3], &port[0], &port[1]))
3693
failf(pasv_conn->data, "Couldn't interpret the 227-reply");
3694
return CURLE_FTP_WEIRD_227_FORMAT;
3697
snprintf(pasv_port, sizeof(pasv_port), "%d,%d,%d,%d,%d,%d", ip[0], ip[1],
3698
ip[2], ip[3], port[0], port[1]);
3700
/* sets data connection between remote hosts */
3701
FTPSENDF(port_conn, "PORT %s", pasv_port);
3702
result = Curl_GetFTPResponse(&nread, port_conn, &ftpcode);
3706
if (ftpcode != 200) {
3707
failf(data, "PORT command attempts failed: %03d", ftpcode);
3708
return CURLE_FTP_PORT_FAILED;
3711
/* we might append onto the file instead of overwriting it */
3712
stor_cmd = data->set.ftp_append?"APPE":"STOR";
3714
/* transfers file between remote hosts */
3715
/* FIX: this should send a series of CWD commands and then RETR only the
3716
ftp->file file. The conn->path "full path" is not unescaped. Test case
3718
FTPSENDF(sec_conn, "RETR %s", sec_conn->path);
3720
if(!data->set.ftpport) {
3722
result = Curl_GetFTPResponse(&nread, sec_conn, &ftpcode);
3726
if((ftpcode != 150) && (ftpcode != 125)) {
3727
failf(data, "Failed RETR: %03d", ftpcode);
3728
return CURLE_FTP_COULDNT_RETR_FILE;
3731
result = Curl_ftpsendf(conn, "%s %s", stor_cmd, conn->proto.ftp->file);
3732
if(CURLE_OK == result)
3733
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3737
if (ftpcode >= 400) {
3738
failf(data, "Failed FTP upload: %03d", ftpcode);
3739
return CURLE_FTP_COULDNT_STOR_FILE;
3745
result = Curl_ftpsendf(conn, "%s %s", stor_cmd, conn->proto.ftp->file);
3746
if(CURLE_OK == result)
3747
result = Curl_GetFTPResponse(&nread, sec_conn, &ftpcode);
3751
if (ftpcode >= 400) {
3752
failf(data, "Failed FTP upload: %03d", ftpcode);
3753
return CURLE_FTP_COULDNT_STOR_FILE;
3756
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3760
if((ftpcode != 150) && (ftpcode != 125)) {
3761
failf(data, "Failed FTP upload: %03d", ftpcode);
3762
return CURLE_FTP_COULDNT_STOR_FILE;
3624
free(ftpc->entrypath);
3625
ftpc->entrypath = NULL;
3632
if(ftpc->prevpath) {
3633
free(ftpc->prevpath);
3634
ftpc->prevpath = NULL;
3766
3637
return CURLE_OK;
3777
3648
CURLcode ftp_parse_url_path(struct connectdata *conn)
3779
CURLcode retcode = CURLE_OK;
3780
3650
struct SessionHandle *data = conn->data;
3651
/* the ftp struct is already inited in ftp_connect() */
3652
struct FTP *ftp = data->reqdata.proto.ftp;
3653
struct ftp_conn *ftpc = &conn->proto.ftpc;
3784
3655
char *slash_pos; /* position of the first '/' char in curpos */
3785
char *cur_pos = conn->path; /* current position in path. point at the begin
3786
of next path component */
3788
/* the ftp struct is already inited in ftp_connect() */
3789
ftp = conn->proto.ftp;
3790
ftp->ctl_valid = FALSE;
3791
ftp->cwdfail = FALSE;
3656
char *path_to_use = data->reqdata.path;
3659
cur_pos = path_to_use; /* current position in path. point at the begin
3660
of next path component */
3662
ftpc->ctl_valid = FALSE;
3663
ftpc->cwdfail = FALSE;
3793
3665
switch(data->set.ftp_filemethod) {
3794
3666
case FTPFILE_NOCWD:
3795
3667
/* fastest, but less standard-compliant */
3796
ftp->file = conn->path; /* this is a full file path */
3668
ftp->file = data->reqdata.path; /* this is a full file path */
3799
3671
case FTPFILE_SINGLECWD:
3800
3672
/* get the last slash */
3801
3673
slash_pos=strrchr(cur_pos, '/');
3803
ftp->dirdepth = 1; /* we consider it to be a single dir */
3804
ftp->dirs = (char **)calloc(1, sizeof(ftp->dirs[0]));
3674
if(slash_pos || !*cur_pos) {
3675
ftpc->dirdepth = 1; /* we consider it to be a single dir */
3676
ftpc->dirs = (char **)calloc(1, sizeof(ftpc->dirs[0]));
3806
3678
return CURLE_OUT_OF_MEMORY;
3808
ftp->dirs[0] = curl_easy_unescape(conn->data, cur_pos,
3809
(int)(slash_pos-cur_pos), NULL);
3680
ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
3681
slash_pos?(int)(slash_pos-cur_pos):1,
3683
if(!ftpc->dirs[0]) {
3812
3685
return CURLE_OUT_OF_MEMORY;
3814
ftp->file = slash_pos+1; /* the rest is the file name */
3687
ftp->file = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
3817
3690
ftp->file = cur_pos; /* this is a file name only */
3820
3693
default: /* allow pretty much anything */
3821
3694
case FTPFILE_MULTICWD:
3823
ftp->diralloc = 5; /* default dir depth to allocate */
3824
ftp->dirs = (char **)calloc(ftp->diralloc, sizeof(ftp->dirs[0]));
3696
ftpc->diralloc = 5; /* default dir depth to allocate */
3697
ftpc->dirs = (char **)calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
3826
3699
return CURLE_OUT_OF_MEMORY;
3828
3701
/* parse the URL path into separate path components */
3829
while((slash_pos=strchr(cur_pos, '/'))) {
3702
while ((slash_pos = strchr(cur_pos, '/')) != NULL) {
3830
3703
/* 1 or 0 to indicate absolute directory */
3831
bool absolute_dir = (cur_pos - conn->path > 0) && (ftp->dirdepth == 0);
3704
bool absolute_dir = (bool)((cur_pos - data->reqdata.path > 0) &&
3705
(ftpc->dirdepth == 0));
3833
3707
/* seek out the next path component */
3834
3708
if (slash_pos-cur_pos) {
3835
/* we skip empty path components, like "x//y" since the FTP command CWD
3836
requires a parameter and a non-existant parameter a) doesn't work on
3837
many servers and b) has no effect on the others. */
3709
/* we skip empty path components, like "x//y" since the FTP command
3710
CWD requires a parameter and a non-existant parameter a) doesn't
3711
work on many servers and b) has no effect on the others. */
3838
3712
int len = (int)(slash_pos - cur_pos + absolute_dir);
3839
ftp->dirs[ftp->dirdepth] = curl_easy_unescape(conn->data,
3840
cur_pos - absolute_dir,
3842
if (!ftp->dirs[ftp->dirdepth]) { /* run out of memory ... */
3713
ftpc->dirs[ftpc->dirdepth] = curl_easy_unescape(conn->data,
3714
cur_pos - absolute_dir,
3716
if (!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
3843
3717
failf(data, "no memory");
3845
3719
return CURLE_OUT_OF_MEMORY;
3847
if (isBadFtpString(ftp->dirs[ftp->dirdepth])) {
3721
if (isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
3722
free(ftpc->dirs[ftpc->dirdepth]);
3849
3724
return CURLE_URL_MALFORMAT;
3897
3769
return CURLE_URL_MALFORMAT;
3900
ftp->cwddone = FALSE; /* default to not done */
3772
ftpc->cwddone = FALSE; /* default to not done */
3774
if(ftpc->prevpath) {
3903
3775
/* prevpath is "raw" so we convert the input path before we compare the
3905
char *path = curl_easy_unescape(conn->data, conn->path, 0, NULL);
3777
char *path = curl_easy_unescape(conn->data, data->reqdata.path, 0, NULL);
3907
3779
return CURLE_OUT_OF_MEMORY;
3909
3781
dlen = strlen(path) - (ftp->file?strlen(ftp->file):0);
3910
if((dlen == strlen(ftp->prevpath)) &&
3911
curl_strnequal(path, ftp->prevpath, dlen)) {
3782
if((dlen == strlen(ftpc->prevpath)) &&
3783
curl_strnequal(path, ftpc->prevpath, dlen)) {
3912
3784
infof(data, "Request has same path as previous transfer\n");
3913
ftp->cwddone = TRUE;
3785
ftpc->cwddone = TRUE;
3923
/***********************************************************************
3925
* ftp_cwd_and_create_path()
3927
* Creates full path on remote target host.
3931
CURLcode ftp_cwd_and_create_path(struct connectdata *conn)
3933
CURLcode result = CURLE_OK;
3934
/* the ftp struct is already inited in Curl_ftp_connect() */
3935
struct FTP *ftp = conn->proto.ftp;
3939
/* already done and fine */
3942
/* This is a re-used connection. Since we change directory to where the
3943
transfer is taking place, we must now get back to the original dir
3944
where we ended up after login: */
3945
if (conn->bits.reuse && ftp->entrypath) {
3946
if ((result = ftp_cwd_and_mkd(conn, ftp->entrypath)) != CURLE_OK)
3950
for (i=0; i < ftp->dirdepth; i++) {
3951
/* RFC 1738 says empty components should be respected too, but
3952
that is plain stupid since CWD can't be used with an empty argument */
3953
if ((result = ftp_cwd_and_mkd(conn, ftp->dirs[i])) != CURLE_OK)
3960
3793
/* call this when the DO phase has completed */