1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 #include "curl_setup.h"
25 #ifndef CURL_DISABLE_FTP
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h>
30 #ifdef HAVE_ARPA_INET_H
31 #include <arpa/inet.h>
34 #include <sys/utsname.h>
44 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
46 #define in_addr_t unsigned long
49 #include <curl/curl.h>
57 #include "http.h" /* for HTTP proxy tunnel stuff */
61 #include "ftplistparser.h"
63 #include "strtoofft.h"
65 #include "vtls/vtls.h"
68 #include "inet_ntop.h"
69 #include "inet_pton.h"
71 #include "parsedate.h" /* for the week day and month names */
72 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
76 #include "speedcheck.h"
78 #include "http_proxy.h"
79 #include "non-ascii.h"
80 #include "curl_printf.h"
82 #include "curl_memory.h"
83 /* The last #include file should be: */
87 #define NI_MAXHOST 1025
89 #ifndef INET_ADDRSTRLEN
90 #define INET_ADDRSTRLEN 16
93 #ifdef CURL_DISABLE_VERBOSE_STRINGS
94 #define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt
97 /* Local API functions */
99 static void _state(struct connectdata *conn,
101 #define state(x,y) _state(x,y)
103 static void _state(struct connectdata *conn,
106 #define state(x,y) _state(x,y,__LINE__)
109 static CURLcode ftp_sendquote(struct connectdata *conn,
110 struct curl_slist *quote);
111 static CURLcode ftp_quit(struct connectdata *conn);
112 static CURLcode ftp_parse_url_path(struct connectdata *conn);
113 static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
114 #ifndef CURL_DISABLE_VERBOSE_STRINGS
115 static void ftp_pasv_verbose(struct connectdata *conn,
117 char *newhost, /* ascii version */
120 static CURLcode ftp_state_prepare_transfer(struct connectdata *conn);
121 static CURLcode ftp_state_mdtm(struct connectdata *conn);
122 static CURLcode ftp_state_quote(struct connectdata *conn,
123 bool init, ftpstate instate);
124 static CURLcode ftp_nb_type(struct connectdata *conn,
125 bool ascii, ftpstate newstate);
126 static int ftp_need_type(struct connectdata *conn,
128 static CURLcode ftp_do(struct connectdata *conn, bool *done);
129 static CURLcode ftp_done(struct connectdata *conn,
130 CURLcode, bool premature);
131 static CURLcode ftp_connect(struct connectdata *conn, bool *done);
132 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
133 static CURLcode ftp_do_more(struct connectdata *conn, int *completed);
134 static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
135 static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks,
137 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
139 static CURLcode ftp_doing(struct connectdata *conn,
141 static CURLcode ftp_setup_connection(struct connectdata * conn);
143 static CURLcode init_wc_data(struct connectdata *conn);
144 static CURLcode wc_statemach(struct connectdata *conn);
146 static void wc_data_dtor(void *ptr);
148 static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize);
150 static CURLcode ftp_readresp(curl_socket_t sockfd,
154 static CURLcode ftp_dophase_done(struct connectdata *conn,
157 /* easy-to-use macro: */
158 #define PPSENDF(x,y,z) if((result = Curl_pp_sendf(x,y,z))) \
163 * FTP protocol handler.
166 const struct Curl_handler Curl_handler_ftp = {
168 ftp_setup_connection, /* setup_connection */
171 ftp_do_more, /* do_more */
172 ftp_connect, /* connect_it */
173 ftp_multi_statemach, /* connecting */
174 ftp_doing, /* doing */
175 ftp_getsock, /* proto_getsock */
176 ftp_getsock, /* doing_getsock */
177 ftp_domore_getsock, /* domore_getsock */
178 ZERO_NULL, /* perform_getsock */
179 ftp_disconnect, /* disconnect */
180 ZERO_NULL, /* readwrite */
181 PORT_FTP, /* defport */
182 CURLPROTO_FTP, /* protocol */
183 PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
184 | PROTOPT_NOURLQUERY /* flags */
190 * FTPS protocol handler.
193 const struct Curl_handler Curl_handler_ftps = {
195 ftp_setup_connection, /* setup_connection */
198 ftp_do_more, /* do_more */
199 ftp_connect, /* connect_it */
200 ftp_multi_statemach, /* connecting */
201 ftp_doing, /* doing */
202 ftp_getsock, /* proto_getsock */
203 ftp_getsock, /* doing_getsock */
204 ftp_domore_getsock, /* domore_getsock */
205 ZERO_NULL, /* perform_getsock */
206 ftp_disconnect, /* disconnect */
207 ZERO_NULL, /* readwrite */
208 PORT_FTPS, /* defport */
209 CURLPROTO_FTPS, /* protocol */
210 PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
211 PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY /* flags */
215 #ifndef CURL_DISABLE_HTTP
217 * HTTP-proxyed FTP protocol handler.
220 static const struct Curl_handler Curl_handler_ftp_proxy = {
222 Curl_http_setup_conn, /* setup_connection */
223 Curl_http, /* do_it */
224 Curl_http_done, /* done */
225 ZERO_NULL, /* do_more */
226 ZERO_NULL, /* connect_it */
227 ZERO_NULL, /* connecting */
228 ZERO_NULL, /* doing */
229 ZERO_NULL, /* proto_getsock */
230 ZERO_NULL, /* doing_getsock */
231 ZERO_NULL, /* domore_getsock */
232 ZERO_NULL, /* perform_getsock */
233 ZERO_NULL, /* disconnect */
234 ZERO_NULL, /* readwrite */
235 PORT_FTP, /* defport */
236 CURLPROTO_HTTP, /* protocol */
237 PROTOPT_NONE /* flags */
243 * HTTP-proxyed FTPS protocol handler.
246 static const struct Curl_handler Curl_handler_ftps_proxy = {
248 Curl_http_setup_conn, /* setup_connection */
249 Curl_http, /* do_it */
250 Curl_http_done, /* done */
251 ZERO_NULL, /* do_more */
252 ZERO_NULL, /* connect_it */
253 ZERO_NULL, /* connecting */
254 ZERO_NULL, /* doing */
255 ZERO_NULL, /* proto_getsock */
256 ZERO_NULL, /* doing_getsock */
257 ZERO_NULL, /* domore_getsock */
258 ZERO_NULL, /* perform_getsock */
259 ZERO_NULL, /* disconnect */
260 ZERO_NULL, /* readwrite */
261 PORT_FTPS, /* defport */
262 CURLPROTO_HTTP, /* protocol */
263 PROTOPT_NONE /* flags */
270 * NOTE: back in the old days, we added code in the FTP code that made NOBODY
271 * requests on files respond with headers passed to the client/stdout that
272 * looked like HTTP ones.
274 * This approach is not very elegant, it causes confusion and is error-prone.
275 * It is subject for removal at the next (or at least a future) soname bump.
276 * Until then you can test the effects of the removal by undefining the
277 * following define named CURL_FTP_HTTPSTYLE_HEAD.
279 #define CURL_FTP_HTTPSTYLE_HEAD 1
281 static void freedirs(struct ftp_conn *ftpc)
285 for(i=0; i < ftpc->dirdepth; i++) {
293 Curl_safefree(ftpc->file);
295 /* no longer of any use */
296 Curl_safefree(ftpc->newhost);
299 /* Returns non-zero if the given string contains CR (\r) or LF (\n),
300 which are not allowed within RFC 959 <string>.
301 Note: The input string is in the client's encoding which might
302 not be ASCII, so escape sequences \r & \n must be used instead
303 of hex values 0x0d & 0x0a.
305 static bool isBadFtpString(const char *string)
307 return ((NULL != strchr(string, '\r')) ||
308 (NULL != strchr(string, '\n'))) ? TRUE : FALSE;
311 /***********************************************************************
313 * AcceptServerConnect()
315 * After connection request is received from the server this function is
316 * called to accept the connection and close the listening socket
319 static CURLcode AcceptServerConnect(struct connectdata *conn)
321 struct SessionHandle *data = conn->data;
322 curl_socket_t sock = conn->sock[SECONDARYSOCKET];
323 curl_socket_t s = CURL_SOCKET_BAD;
325 struct Curl_sockaddr_storage add;
327 struct sockaddr_in add;
329 curl_socklen_t size = (curl_socklen_t) sizeof(add);
331 if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
334 s=accept(sock, (struct sockaddr *) &add, &size);
336 Curl_closesocket(conn, sock); /* close the first socket */
338 if(CURL_SOCKET_BAD == s) {
339 failf(data, "Error accept()ing server connect");
340 return CURLE_FTP_PORT_FAILED;
342 infof(data, "Connection accepted from server\n");
344 conn->sock[SECONDARYSOCKET] = s;
345 (void)curlx_nonblock(s, TRUE); /* enable non-blocking */
346 conn->sock_accepted[SECONDARYSOCKET] = TRUE;
348 if(data->set.fsockopt) {
351 /* activate callback for setting socket options */
352 error = data->set.fsockopt(data->set.sockopt_client,
354 CURLSOCKTYPE_ACCEPT);
357 Curl_closesocket(conn, s); /* close the socket and bail out */
358 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
359 return CURLE_ABORTED_BY_CALLBACK;
368 * ftp_timeleft_accept() returns the amount of milliseconds left allowed for
369 * waiting server to connect. If the value is negative, the timeout time has
372 * The start time is stored in progress.t_acceptdata - as set with
373 * Curl_pgrsTime(..., TIMER_STARTACCEPT);
376 static long ftp_timeleft_accept(struct SessionHandle *data)
378 long timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
382 if(data->set.accepttimeout > 0)
383 timeout_ms = data->set.accepttimeout;
387 /* check if the generic timeout possibly is set shorter */
388 other = Curl_timeleft(data, &now, FALSE);
389 if(other && (other < timeout_ms))
390 /* note that this also works fine for when other happens to be negative
391 due to it already having elapsed */
394 /* subtract elapsed time */
395 timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata);
397 /* avoid returning 0 as that means no timeout! */
405 /***********************************************************************
407 * ReceivedServerConnect()
409 * After allowing server to connect to us from data port, this function
410 * checks both data connection for connection establishment and ctrl
411 * connection for a negative response regarding a failure in connecting
414 static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
416 struct SessionHandle *data = conn->data;
417 curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
418 curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
419 struct ftp_conn *ftpc = &conn->proto.ftpc;
420 struct pingpong *pp = &ftpc->pp;
428 timeout_ms = ftp_timeleft_accept(data);
429 infof(data, "Checking for server connect\n");
431 /* if a timeout was already reached, bail out */
432 failf(data, "Accept timeout occurred while waiting server connect");
433 return CURLE_FTP_ACCEPT_TIMEOUT;
436 /* First check whether there is a cached response from server */
437 if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
438 /* Data connection could not be established, let's return */
439 infof(data, "There is negative response in cache while serv connect\n");
440 Curl_GetFTPResponse(&nread, conn, &ftpcode);
441 return CURLE_FTP_ACCEPT_FAILED;
444 result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
446 /* see if the connection request is already here */
450 failf(data, "Error while waiting for server connect");
451 return CURLE_FTP_ACCEPT_FAILED;
452 case 0: /* Server connect is not received yet */
456 if(result & CURL_CSELECT_IN2) {
457 infof(data, "Ready to accept data connection from server\n");
460 else if(result & CURL_CSELECT_IN) {
461 infof(data, "Ctrl conn has data while waiting for data conn\n");
462 Curl_GetFTPResponse(&nread, conn, &ftpcode);
465 return CURLE_FTP_ACCEPT_FAILED;
467 return CURLE_FTP_WEIRD_SERVER_REPLY;
477 /***********************************************************************
481 * After connection from server is accepted this function is called to
482 * setup transfer parameters and initiate the data transfer.
485 static CURLcode InitiateTransfer(struct connectdata *conn)
487 struct SessionHandle *data = conn->data;
488 struct FTP *ftp = data->req.protop;
489 CURLcode result = CURLE_OK;
491 if(conn->ssl[SECONDARYSOCKET].use) {
492 /* since we only have a plaintext TCP connection here, we must now
493 * do the TLS stuff */
494 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
495 result = Curl_ssl_connect(conn, SECONDARYSOCKET);
500 if(conn->proto.ftpc.state_saved == FTP_STOR) {
501 *(ftp->bytecountp)=0;
503 /* When we know we're uploading a specified file, we can get the file
504 size prior to the actual upload. */
506 Curl_pgrsSetUploadSize(data, data->state.infilesize);
508 /* set the SO_SNDBUF for the secondary socket for those who need it */
509 Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
511 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
512 SECONDARYSOCKET, ftp->bytecountp);
516 Curl_setup_transfer(conn, SECONDARYSOCKET,
517 conn->proto.ftpc.retr_size_saved, FALSE,
518 ftp->bytecountp, -1, NULL); /* no upload here */
521 conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
522 state(conn, FTP_STOP);
527 /***********************************************************************
529 * AllowServerConnect()
531 * When we've issue the PORT command, we have told the server to connect to
532 * us. This function checks whether data connection is established if so it is
536 static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
538 struct SessionHandle *data = conn->data;
540 CURLcode result = CURLE_OK;
543 infof(data, "Preparing for accepting server on data port\n");
545 /* Save the time we start accepting server connect */
546 Curl_pgrsTime(data, TIMER_STARTACCEPT);
548 timeout_ms = ftp_timeleft_accept(data);
550 /* if a timeout was already reached, bail out */
551 failf(data, "Accept timeout occurred while waiting server connect");
552 return CURLE_FTP_ACCEPT_TIMEOUT;
555 /* see if the connection request is already here */
556 result = ReceivedServerConnect(conn, connected);
561 result = AcceptServerConnect(conn);
565 result = InitiateTransfer(conn);
570 /* Add timeout to multi handle and break out of the loop */
571 if(!result && *connected == FALSE) {
572 if(data->set.accepttimeout > 0)
573 Curl_expire(data, data->set.accepttimeout);
575 Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
582 /* macro to check for a three-digit ftp status code at the start of the
584 #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
587 /* macro to check for the last line in an FTP server response */
588 #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
590 static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len,
595 if((len > 3) && LASTLINE(line)) {
596 *code = curlx_sltosi(strtol(line, NULL, 10));
603 static CURLcode ftp_readresp(curl_socket_t sockfd,
605 int *ftpcode, /* return the ftp-code if done */
606 size_t *size) /* size of the response */
608 struct connectdata *conn = pp->conn;
609 struct SessionHandle *data = conn->data;
611 char * const buf = data->state.buffer;
613 CURLcode result = CURLE_OK;
616 result = Curl_pp_readresp(sockfd, pp, &code, size);
618 #if defined(HAVE_GSSAPI)
619 /* handle the security-oriented responses 6xx ***/
620 /* FIXME: some errorchecking perhaps... ***/
623 code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
626 code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
629 code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
632 /* normal ftp stuff we pass through! */
637 /* store the latest code for later retrieval */
638 data->info.httpcode=code;
644 /* 421 means "Service not available, closing control connection." and FTP
645 * servers use it to signal that idle session timeout has been exceeded.
646 * If we ignored the response, it could end up hanging in some cases.
648 * This response code can come at any point so having it treated
649 * generically is a good idea.
651 infof(data, "We got a 421 - timeout!\n");
652 state(conn, FTP_STOP);
653 return CURLE_OPERATION_TIMEDOUT;
659 /* --- parse FTP server responses --- */
662 * Curl_GetFTPResponse() is a BLOCKING function to read the full response
663 * from a server after a command.
667 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
668 struct connectdata *conn,
669 int *ftpcode) /* return the ftp-code */
672 * We cannot read just one byte per read() and then go back to select() as
673 * the OpenSSL read() doesn't grok that properly.
675 * Alas, read as much as possible, split up into lines, use the ending
676 * line in a response or continue reading. */
678 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
679 long timeout; /* timeout in milliseconds */
681 struct SessionHandle *data = conn->data;
682 CURLcode result = CURLE_OK;
683 struct ftp_conn *ftpc = &conn->proto.ftpc;
684 struct pingpong *pp = &ftpc->pp;
687 int value_to_be_ignored=0;
690 *ftpcode = 0; /* 0 for errors */
692 /* make the pointer point to something for the rest of this function */
693 ftpcode = &value_to_be_ignored;
697 while(!*ftpcode && !result) {
698 /* check and reset timeout value every lap */
699 timeout = Curl_pp_state_timeout(pp);
702 failf(data, "FTP response timeout");
703 return CURLE_OPERATION_TIMEDOUT; /* already too little time */
706 interval_ms = 1000; /* use 1 second timeout intervals */
707 if(timeout < interval_ms)
708 interval_ms = timeout;
711 * Since this function is blocking, we need to wait here for input on the
712 * connection and only then we call the response reading function. We do
713 * timeout at least every second to make the timeout check run.
715 * A caution here is that the ftp_readresp() function has a cache that may
716 * contain pieces of a response from the previous invoke and we need to
717 * make sure we don't just wait for input while there is unhandled data in
718 * that cache. But also, if the cache is there, we call ftp_readresp() and
719 * the cache wasn't good enough to continue we must not just busy-loop
720 * around this function.
724 if(pp->cache && (cache_skip < 2)) {
726 * There's a cache left since before. We then skipping the wait for
727 * socket action, unless this is the same cache like the previous round
728 * as then the cache was deemed not enough to act on and we then need to
729 * wait for more data anyway.
733 switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, interval_ms)) {
734 case -1: /* select() error, stop reading */
735 failf(data, "FTP response aborted due to select/poll error: %d",
737 return CURLE_RECV_ERROR;
739 case 0: /* timeout */
740 if(Curl_pgrsUpdate(conn))
741 return CURLE_ABORTED_BY_CALLBACK;
742 continue; /* just continue in our loop for the timeout duration */
744 default: /* for clarity */
748 result = ftp_readresp(sockfd, pp, ftpcode, &nread);
752 if(!nread && pp->cache)
753 /* bump cache skip counter as on repeated skips we must wait for more
757 /* when we got data or there is no cache left, we reset the cache skip
763 } /* while there's buffer left and loop is requested */
765 pp->pending_resp = FALSE;
770 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
771 /* for debug purposes */
772 static const char * const ftp_state_names[]={
811 /* This is the ONLY way to change FTP state! */
812 static void _state(struct connectdata *conn,
819 struct ftp_conn *ftpc = &conn->proto.ftpc;
821 #if defined(DEBUGBUILD)
823 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
826 if(ftpc->state != newstate)
827 infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
828 (void *)ftpc, lineno, ftp_state_names[ftpc->state],
829 ftp_state_names[newstate]);
833 ftpc->state = newstate;
836 static CURLcode ftp_state_user(struct connectdata *conn)
839 struct FTP *ftp = conn->data->req.protop;
841 PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
843 state(conn, FTP_USER);
844 conn->data->state.ftp_trying_alternative = FALSE;
849 static CURLcode ftp_state_pwd(struct connectdata *conn)
853 /* send PWD to discover our entry point */
854 PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD");
855 state(conn, FTP_PWD);
860 /* For the FTP "protocol connect" and "doing" phases only */
861 static int ftp_getsock(struct connectdata *conn,
862 curl_socket_t *socks,
865 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
868 /* For the FTP "DO_MORE" phase only */
869 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
872 struct ftp_conn *ftpc = &conn->proto.ftpc;
875 return GETSOCK_BLANK;
877 /* When in DO_MORE state, we could be either waiting for us to connect to a
878 * remote site, or we could wait for that site to connect to us. Or just
879 * handle ordinary commands.
882 if(FTP_STOP == ftpc->state) {
883 int bits = GETSOCK_READSOCK(0);
885 /* if stopped and still in this state, then we're also waiting for a
886 connect on the secondary connection */
887 socks[0] = conn->sock[FIRSTSOCKET];
889 if(!conn->data->set.ftp_use_port) {
892 /* PORT is used to tell the server to connect to us, and during that we
893 don't do happy eyeballs, but we do if we connect to the server */
894 for(s=1, i=0; i<2; i++) {
895 if(conn->tempsock[i] != CURL_SOCKET_BAD) {
896 socks[s] = conn->tempsock[i];
897 bits |= GETSOCK_WRITESOCK(s++);
902 socks[1] = conn->sock[SECONDARYSOCKET];
903 bits |= GETSOCK_WRITESOCK(1);
909 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
912 /* This is called after the FTP_QUOTE state is passed.
914 ftp_state_cwd() sends the range of CWD commands to the server to change to
915 the correct directory. It may also need to send MKD commands to create
916 missing ones, if that option is enabled.
918 static CURLcode ftp_state_cwd(struct connectdata *conn)
920 CURLcode result = CURLE_OK;
921 struct ftp_conn *ftpc = &conn->proto.ftpc;
924 /* already done and fine */
925 result = ftp_state_mdtm(conn);
927 ftpc->count2 = 0; /* count2 counts failed CWDs */
929 /* count3 is set to allow a MKD to fail once. In the case when first CWD
930 fails and then MKD fails (due to another session raced it to create the
931 dir) this then allows for a second try to CWD to it */
932 ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
934 if(conn->bits.reuse && ftpc->entrypath) {
935 /* This is a re-used connection. Since we change directory to where the
936 transfer is taking place, we must first get back to the original dir
937 where we ended up after login: */
938 ftpc->count1 = 0; /* we count this as the first path, then we add one
939 for all upcoming ones in the ftp->dirs[] array */
940 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
941 state(conn, FTP_CWD);
946 /* issue the first CWD, the rest is sent when the CWD responses are
948 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
949 state(conn, FTP_CWD);
952 /* No CWD necessary */
953 result = ftp_state_mdtm(conn);
966 static CURLcode ftp_state_use_port(struct connectdata *conn,
967 ftpport fcmd) /* start with this */
970 CURLcode result = CURLE_OK;
971 struct ftp_conn *ftpc = &conn->proto.ftpc;
972 struct SessionHandle *data=conn->data;
973 curl_socket_t portsock= CURL_SOCKET_BAD;
974 char myhost[256] = "";
976 struct Curl_sockaddr_storage ss;
977 Curl_addrinfo *res, *ai;
978 curl_socklen_t sslen;
979 char hbuf[NI_MAXHOST];
980 struct sockaddr *sa=(struct sockaddr *)&ss;
981 struct sockaddr_in * const sa4 = (void *)sa;
983 struct sockaddr_in6 * const sa6 = (void *)sa;
986 static const char mode[][5] = { "EPRT", "PORT" };
990 char *string_ftpport = data->set.str[STRING_FTPPORT];
991 struct Curl_dns_entry *h=NULL;
992 unsigned short port_min = 0;
993 unsigned short port_max = 0;
995 bool possibly_non_local = TRUE;
999 /* Step 1, figure out what is requested,
1001 * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
1004 if(data->set.str[STRING_FTPPORT] &&
1005 (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
1008 size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
1009 INET6_ADDRSTRLEN : strlen(string_ftpport);
1011 size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
1012 INET_ADDRSTRLEN : strlen(string_ftpport);
1014 char *ip_start = string_ftpport;
1015 char *ip_end = NULL;
1016 char *port_start = NULL;
1017 char *port_sep = NULL;
1019 addr = calloc(addrlen+1, 1);
1021 return CURLE_OUT_OF_MEMORY;
1024 if(*string_ftpport == '[') {
1025 /* [ipv6]:port(-range) */
1026 ip_start = string_ftpport + 1;
1027 if((ip_end = strchr(string_ftpport, ']')) != NULL )
1028 strncpy(addr, ip_start, ip_end - ip_start);
1032 if(*string_ftpport == ':') {
1034 ip_end = string_ftpport;
1036 else if((ip_end = strchr(string_ftpport, ':')) != NULL) {
1037 /* either ipv6 or (ipv4|domain|interface):port(-range) */
1039 if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
1041 port_min = port_max = 0;
1042 strcpy(addr, string_ftpport);
1043 ip_end = NULL; /* this got no port ! */
1047 /* (ipv4|domain|interface):port(-range) */
1048 strncpy(addr, string_ftpport, ip_end - ip_start );
1051 /* ipv4|interface */
1052 strcpy(addr, string_ftpport);
1054 /* parse the port */
1055 if(ip_end != NULL) {
1056 if((port_start = strchr(ip_end, ':')) != NULL) {
1057 port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
1058 if((port_sep = strchr(port_start, '-')) != NULL) {
1059 port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
1062 port_max = port_min;
1066 /* correct errors like:
1068 * :-4711 , in this case port_min is (unsigned)-1,
1069 * therefore port_min > port_max for all cases
1070 * but port_max = (unsigned)-1
1072 if(port_min > port_max )
1073 port_min = port_max = 0;
1077 /* attempt to get the address of the given interface name */
1078 switch(Curl_if2ip(conn->ip_addr->ai_family,
1079 Curl_ipv6_scope(conn->ip_addr->ai_addr),
1080 conn->scope_id, addr, hbuf, sizeof(hbuf))) {
1081 case IF2IP_NOT_FOUND:
1082 /* not an interface, use the given string as host name instead */
1085 case IF2IP_AF_NOT_SUPPORTED:
1086 return CURLE_FTP_PORT_FAILED;
1088 host = hbuf; /* use the hbuf for host name */
1092 /* there was only a port(-range) given, default the host */
1094 } /* data->set.ftpport */
1097 /* not an interface and not a host name, get default by extracting
1098 the IP from the control connection */
1101 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1102 failf(data, "getsockname() failed: %s",
1103 Curl_strerror(conn, SOCKERRNO) );
1105 return CURLE_FTP_PORT_FAILED;
1107 switch(sa->sa_family) {
1110 Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
1114 Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
1117 host = hbuf; /* use this host name */
1118 possibly_non_local = FALSE; /* we know it is local now */
1121 /* resolv ip/host to ip */
1122 rc = Curl_resolv(conn, host, 0, &h);
1123 if(rc == CURLRESOLV_PENDING)
1124 (void)Curl_resolver_wait_resolv(conn, &h);
1127 /* when we return from this function, we can forget about this entry
1128 to we can unlock it now already */
1129 Curl_resolv_unlock(data, h);
1132 res = NULL; /* failure! */
1135 failf(data, "failed to resolve the address provided to PORT: %s", host);
1137 return CURLE_FTP_PORT_FAILED;
1143 /* step 2, create a socket for the requested address */
1145 portsock = CURL_SOCKET_BAD;
1147 for(ai = res; ai; ai = ai->ai_next) {
1148 result = Curl_socket(conn, ai, NULL, &portsock);
1156 failf(data, "socket failure: %s", Curl_strerror(conn, error));
1157 return CURLE_FTP_PORT_FAILED;
1160 /* step 3, bind to a suitable local address */
1162 memcpy(sa, ai->ai_addr, ai->ai_addrlen);
1163 sslen = ai->ai_addrlen;
1165 for(port = port_min; port <= port_max;) {
1166 if(sa->sa_family == AF_INET)
1167 sa4->sin_port = htons(port);
1170 sa6->sin6_port = htons(port);
1172 /* Try binding the given address. */
1173 if(bind(portsock, sa, sslen) ) {
1176 if(possibly_non_local && (error == EADDRNOTAVAIL)) {
1177 /* The requested bind address is not local. Use the address used for
1178 * the control connection instead and restart the port loop
1181 infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
1182 Curl_strerror(conn, error) );
1185 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1186 failf(data, "getsockname() failed: %s",
1187 Curl_strerror(conn, SOCKERRNO) );
1188 Curl_closesocket(conn, portsock);
1189 return CURLE_FTP_PORT_FAILED;
1192 possibly_non_local = FALSE; /* don't try this again */
1195 else if(error != EADDRINUSE && error != EACCES) {
1196 failf(data, "bind(port=%hu) failed: %s", port,
1197 Curl_strerror(conn, error) );
1198 Curl_closesocket(conn, portsock);
1199 return CURLE_FTP_PORT_FAILED;
1208 /* maybe all ports were in use already*/
1209 if(port > port_max) {
1210 failf(data, "bind() failed, we ran out of ports!");
1211 Curl_closesocket(conn, portsock);
1212 return CURLE_FTP_PORT_FAILED;
1215 /* get the name again after the bind() so that we can extract the
1216 port number it uses now */
1218 if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
1219 failf(data, "getsockname() failed: %s",
1220 Curl_strerror(conn, SOCKERRNO) );
1221 Curl_closesocket(conn, portsock);
1222 return CURLE_FTP_PORT_FAILED;
1225 /* step 4, listen on the socket */
1227 if(listen(portsock, 1)) {
1228 failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
1229 Curl_closesocket(conn, portsock);
1230 return CURLE_FTP_PORT_FAILED;
1233 /* step 5, send the proper FTP command */
1235 /* get a plain printable version of the numerical address to work with
1237 Curl_printable_address(ai, myhost, sizeof(myhost));
1240 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
1241 /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
1242 request and enable EPRT again! */
1243 conn->bits.ftp_use_eprt = TRUE;
1246 for(; fcmd != DONE; fcmd++) {
1248 if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
1249 /* if disabled, goto next */
1252 if((PORT == fcmd) && sa->sa_family != AF_INET)
1253 /* PORT is IPv4 only */
1256 switch(sa->sa_family) {
1258 port = ntohs(sa4->sin_port);
1262 port = ntohs(sa6->sin6_port);
1266 continue; /* might as well skip this */
1271 * Two fine examples from RFC2428;
1273 * EPRT |1|132.235.1.2|6275|
1275 * EPRT |2|1080::8:800:200C:417A|5282|
1278 result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
1279 sa->sa_family == AF_INET?1:2,
1282 failf(data, "Failure sending EPRT command: %s",
1283 curl_easy_strerror(result));
1284 Curl_closesocket(conn, portsock);
1285 /* don't retry using PORT */
1286 ftpc->count1 = PORT;
1288 state(conn, FTP_STOP);
1293 else if(PORT == fcmd) {
1294 char *source = myhost;
1297 /* translate x.x.x.x to x,x,x,x */
1298 while(source && *source) {
1307 snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
1309 result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
1311 failf(data, "Failure sending PORT command: %s",
1312 curl_easy_strerror(result));
1313 Curl_closesocket(conn, portsock);
1315 state(conn, FTP_STOP);
1322 /* store which command was sent */
1323 ftpc->count1 = fcmd;
1325 /* we set the secondary socket variable to this for now, it is only so that
1326 the cleanup function will close it in case we fail before the true
1327 secondary stuff is made */
1328 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
1329 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
1330 conn->sock[SECONDARYSOCKET] = portsock;
1332 /* this tcpconnect assignment below is a hackish work-around to make the
1333 multi interface with active FTP work - as it will not wait for a
1334 (passive) connect in Curl_is_connected().
1336 The *proper* fix is to make sure that the active connection from the
1337 server is done in a non-blocking way. Currently, it is still BLOCKING.
1339 conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
1341 state(conn, FTP_PORT);
1345 static CURLcode ftp_state_use_pasv(struct connectdata *conn)
1347 struct ftp_conn *ftpc = &conn->proto.ftpc;
1348 CURLcode result = CURLE_OK;
1350 Here's the excecutive summary on what to do:
1352 PASV is RFC959, expect:
1353 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1355 LPSV is RFC1639, expect:
1356 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1358 EPSV is RFC2428, expect:
1359 229 Entering Extended Passive Mode (|||port|)
1363 static const char mode[][5] = { "EPSV", "PASV" };
1367 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
1368 /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1369 request and enable EPSV again! */
1370 conn->bits.ftp_use_epsv = TRUE;
1373 modeoff = conn->bits.ftp_use_epsv?0:1;
1375 PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
1377 ftpc->count1 = modeoff;
1378 state(conn, FTP_PASV);
1379 infof(conn->data, "Connect data stream passively\n");
1385 * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc.
1387 * REST is the last command in the chain of commands when a "head"-like
1388 * request is made. Thus, if an actual transfer is to be made this is where we
1389 * take off for real.
1391 static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
1393 CURLcode result = CURLE_OK;
1394 struct FTP *ftp = conn->data->req.protop;
1395 struct SessionHandle *data = conn->data;
1397 if(ftp->transfer != FTPTRANSFER_BODY) {
1398 /* doesn't transfer any data */
1400 /* still possibly do PRE QUOTE jobs */
1401 state(conn, FTP_RETR_PREQUOTE);
1402 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1404 else if(data->set.ftp_use_port) {
1405 /* We have chosen to use the PORT (or similar) command */
1406 result = ftp_state_use_port(conn, EPRT);
1409 /* We have chosen (this is default) to use the PASV (or similar) command */
1410 if(data->set.ftp_use_pret) {
1411 /* The user has requested that we send a PRET command
1412 to prepare the server for the upcoming PASV */
1413 if(!conn->proto.ftpc.file) {
1414 PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
1415 data->set.str[STRING_CUSTOMREQUEST]?
1416 data->set.str[STRING_CUSTOMREQUEST]:
1417 (data->set.ftp_list_only?"NLST":"LIST"));
1419 else if(data->set.upload) {
1420 PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
1423 PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
1425 state(conn, FTP_PRET);
1428 result = ftp_state_use_pasv(conn);
1434 static CURLcode ftp_state_rest(struct connectdata *conn)
1436 CURLcode result = CURLE_OK;
1437 struct FTP *ftp = conn->data->req.protop;
1438 struct ftp_conn *ftpc = &conn->proto.ftpc;
1440 if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
1441 /* if a "head"-like request is being made (on a file) */
1443 /* Determine if server can respond to REST command and therefore
1444 whether it supports range */
1445 PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
1447 state(conn, FTP_REST);
1450 result = ftp_state_prepare_transfer(conn);
1455 static CURLcode ftp_state_size(struct connectdata *conn)
1457 CURLcode result = CURLE_OK;
1458 struct FTP *ftp = conn->data->req.protop;
1459 struct ftp_conn *ftpc = &conn->proto.ftpc;
1461 if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
1462 /* if a "head"-like request is being made (on a file) */
1464 /* we know ftpc->file is a valid pointer to a file name */
1465 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1467 state(conn, FTP_SIZE);
1470 result = ftp_state_rest(conn);
1475 static CURLcode ftp_state_list(struct connectdata *conn)
1477 CURLcode result = CURLE_OK;
1478 struct SessionHandle *data = conn->data;
1480 /* If this output is to be machine-parsed, the NLST command might be better
1481 to use, since the LIST command output is not specified or standard in any
1482 way. It has turned out that the NLST list output is not the same on all
1483 servers either... */
1486 if FTPFILE_NOCWD was specified, we are currently in
1487 the user's home directory, so we should add the path
1488 as argument for the LIST / NLST / or custom command.
1489 Whether the server will support this, is uncertain.
1491 The other ftp_filemethods will CWD into dir/dir/ first and
1492 then just do LIST (in that case: nothing to do here)
1494 char *cmd, *lstArg, *slashPos;
1497 if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
1499 data->state.path[0] &&
1500 strchr(data->state.path, '/')) {
1502 lstArg = strdup(data->state.path);
1504 return CURLE_OUT_OF_MEMORY;
1506 /* Check if path does not end with /, as then we cut off the file part */
1507 if(lstArg[strlen(lstArg) - 1] != '/') {
1509 /* chop off the file part if format is dir/dir/file */
1510 slashPos = strrchr(lstArg, '/');
1512 *(slashPos+1) = '\0';
1516 cmd = aprintf( "%s%s%s",
1517 data->set.str[STRING_CUSTOMREQUEST]?
1518 data->set.str[STRING_CUSTOMREQUEST]:
1519 (data->set.ftp_list_only?"NLST":"LIST"),
1521 lstArg? lstArg: "" );
1525 return CURLE_OUT_OF_MEMORY;
1528 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
1536 state(conn, FTP_LIST);
1541 static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
1543 CURLcode result = CURLE_OK;
1545 /* We've sent the TYPE, now we must send the list of prequote strings */
1547 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1552 static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
1554 CURLcode result = CURLE_OK;
1556 /* We've sent the TYPE, now we must send the list of prequote strings */
1558 result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
1563 static CURLcode ftp_state_type(struct connectdata *conn)
1565 CURLcode result = CURLE_OK;
1566 struct FTP *ftp = conn->data->req.protop;
1567 struct SessionHandle *data = conn->data;
1568 struct ftp_conn *ftpc = &conn->proto.ftpc;
1570 /* If we have selected NOBODY and HEADER, it means that we only want file
1571 information. Which in FTP can't be much more than the file size and
1573 if(data->set.opt_no_body && ftpc->file &&
1574 ftp_need_type(conn, data->set.prefer_ascii)) {
1575 /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
1576 may not support it! It is however the only way we have to get a file's
1579 ftp->transfer = FTPTRANSFER_INFO;
1580 /* this means no actual transfer will be made */
1582 /* Some servers return different sizes for different modes, and thus we
1583 must set the proper type before we check the size */
1584 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
1589 result = ftp_state_size(conn);
1594 /* This is called after the CWD commands have been done in the beginning of
1596 static CURLcode ftp_state_mdtm(struct connectdata *conn)
1598 CURLcode result = CURLE_OK;
1599 struct SessionHandle *data = conn->data;
1600 struct ftp_conn *ftpc = &conn->proto.ftpc;
1602 /* Requested time of file or time-depended transfer? */
1603 if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
1605 /* we have requested to get the modified-time of the file, this is a white
1606 spot as the MDTM is not mentioned in RFC959 */
1607 PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
1609 state(conn, FTP_MDTM);
1612 result = ftp_state_type(conn);
1618 /* This is called after the TYPE and possible quote commands have been sent */
1619 static CURLcode ftp_state_ul_setup(struct connectdata *conn,
1622 CURLcode result = CURLE_OK;
1623 struct FTP *ftp = conn->data->req.protop;
1624 struct SessionHandle *data = conn->data;
1625 struct ftp_conn *ftpc = &conn->proto.ftpc;
1626 int seekerr = CURL_SEEKFUNC_OK;
1628 if((data->state.resume_from && !sizechecked) ||
1629 ((data->state.resume_from > 0) && sizechecked)) {
1630 /* we're about to continue the uploading of a file */
1631 /* 1. get already existing file's size. We use the SIZE command for this
1632 which may not exist in the server! The SIZE command is not in
1635 /* 2. This used to set REST. But since we can do append, we
1636 don't another ftp command. We just skip the source file
1637 offset and then we APPEND the rest on the file instead */
1639 /* 3. pass file-size number of bytes in the source file */
1640 /* 4. lower the infilesize counter */
1641 /* => transfer as usual */
1643 if(data->state.resume_from < 0 ) {
1644 /* Got no given size to start from, figure it out */
1645 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1646 state(conn, FTP_STOR_SIZE);
1651 data->set.ftp_append = TRUE;
1653 /* Let's read off the proper amount of bytes from the input. */
1654 if(conn->seek_func) {
1655 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1659 if(seekerr != CURL_SEEKFUNC_OK) {
1660 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1661 failf(data, "Could not seek stream");
1662 return CURLE_FTP_COULDNT_USE_REST;
1664 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1666 curl_off_t passed=0;
1668 size_t readthisamountnow =
1669 (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
1670 BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
1672 size_t actuallyread =
1673 data->set.fread_func(data->state.buffer, 1, readthisamountnow,
1676 passed += actuallyread;
1677 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1678 /* this checks for greater-than only to make sure that the
1679 CURL_READFUNC_ABORT return code still aborts */
1680 failf(data, "Failed to read data");
1681 return CURLE_FTP_COULDNT_USE_REST;
1683 } while(passed < data->state.resume_from);
1686 /* now, decrease the size of the read */
1687 if(data->state.infilesize>0) {
1688 data->state.infilesize -= data->state.resume_from;
1690 if(data->state.infilesize <= 0) {
1691 infof(data, "File already completely uploaded\n");
1693 /* no data to transfer */
1694 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1696 /* Set ->transfer so that we won't get any error in
1697 * ftp_done() because we didn't transfer anything! */
1698 ftp->transfer = FTPTRANSFER_NONE;
1700 state(conn, FTP_STOP);
1704 /* we've passed, proceed as normal */
1707 PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
1710 state(conn, FTP_STOR);
1715 static CURLcode ftp_state_quote(struct connectdata *conn,
1719 CURLcode result = CURLE_OK;
1720 struct SessionHandle *data = conn->data;
1721 struct FTP *ftp = data->req.protop;
1722 struct ftp_conn *ftpc = &conn->proto.ftpc;
1724 struct curl_slist *item;
1729 item = data->set.quote;
1731 case FTP_RETR_PREQUOTE:
1732 case FTP_STOR_PREQUOTE:
1733 item = data->set.prequote;
1736 item = data->set.postquote;
1742 * 'count1' to iterate over the commands to send
1743 * 'count2' to store wether to allow commands to fail
1754 /* Skip count1 items in the linked list */
1755 while((i< ftpc->count1) && item) {
1760 char *cmd = item->data;
1763 ftpc->count2 = 1; /* the sent command is allowed to fail */
1766 ftpc->count2 = 0; /* failure means cancel operation */
1768 PPSENDF(&ftpc->pp, "%s", cmd);
1769 state(conn, instate);
1775 /* No more quote to send, continue to ... */
1779 result = ftp_state_cwd(conn);
1781 case FTP_RETR_PREQUOTE:
1782 if(ftp->transfer != FTPTRANSFER_BODY)
1783 state(conn, FTP_STOP);
1785 if(ftpc->known_filesize != -1) {
1786 Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
1787 result = ftp_state_retr(conn, ftpc->known_filesize);
1790 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1791 state(conn, FTP_RETR_SIZE);
1795 case FTP_STOR_PREQUOTE:
1796 result = ftp_state_ul_setup(conn, FALSE);
1806 /* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
1808 static CURLcode ftp_epsv_disable(struct connectdata *conn)
1810 CURLcode result = CURLE_OK;
1812 if(conn->bits.ipv6) {
1813 /* We can't disable EPSV when doing IPv6, so this is instead a fail */
1814 failf(conn->data, "Failed EPSV attempt, exiting\n");
1815 return CURLE_FTP_WEIRD_SERVER_REPLY;
1818 infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
1819 /* disable it for next transfer */
1820 conn->bits.ftp_use_epsv = FALSE;
1821 conn->data->state.errorbuf = FALSE; /* allow error message to get
1823 PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV");
1824 conn->proto.ftpc.count1++;
1825 /* remain in/go to the FTP_PASV state */
1826 state(conn, FTP_PASV);
1831 * Perform the necessary magic that needs to be done once the TCP connection
1832 * to the proxy has completed.
1834 static CURLcode proxy_magic(struct connectdata *conn,
1835 char *newhost, unsigned short newport,
1838 CURLcode result = CURLE_OK;
1839 struct SessionHandle *data = conn->data;
1841 #if defined(CURL_DISABLE_PROXY)
1848 switch(conn->proxytype) {
1849 case CURLPROXY_SOCKS5:
1850 case CURLPROXY_SOCKS5_HOSTNAME:
1851 result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost,
1852 newport, SECONDARYSOCKET, conn);
1855 case CURLPROXY_SOCKS4:
1856 result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1857 SECONDARYSOCKET, conn, FALSE);
1860 case CURLPROXY_SOCKS4A:
1861 result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1862 SECONDARYSOCKET, conn, TRUE);
1865 case CURLPROXY_HTTP:
1866 case CURLPROXY_HTTP_1_0:
1867 /* do nothing here. handled later. */
1870 failf(data, "unknown proxytype option given");
1871 result = CURLE_COULDNT_CONNECT;
1875 if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
1877 /* We want "seamless" FTP operations through HTTP proxy tunnel */
1879 /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the
1880 * member conn->proto.http; we want FTP through HTTP and we have to
1881 * change the member temporarily for connecting to the HTTP proxy. After
1882 * Curl_proxyCONNECT we have to set back the member to the original
1883 * struct FTP pointer
1885 struct HTTP http_proxy;
1886 struct FTP *ftp_save = data->req.protop;
1887 memset(&http_proxy, 0, sizeof(http_proxy));
1888 data->req.protop = &http_proxy;
1890 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport, TRUE);
1892 data->req.protop = ftp_save;
1897 if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) {
1898 /* the CONNECT procedure is not complete, the tunnel is not yet up */
1899 state(conn, FTP_STOP); /* this phase is completed */
1909 static char *control_address(struct connectdata *conn)
1911 /* Returns the control connection IP address.
1912 If a proxy tunnel is used, returns the original host name instead, because
1913 the effective control connection address is the proxy address,
1914 not the ftp host. */
1915 if(conn->bits.tunnel_proxy ||
1916 conn->proxytype == CURLPROXY_SOCKS5 ||
1917 conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
1918 conn->proxytype == CURLPROXY_SOCKS4 ||
1919 conn->proxytype == CURLPROXY_SOCKS4A)
1920 return conn->host.name;
1922 return conn->ip_addr_str;
1925 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1928 struct ftp_conn *ftpc = &conn->proto.ftpc;
1930 struct SessionHandle *data=conn->data;
1931 struct Curl_dns_entry *addr=NULL;
1933 unsigned short connectport; /* the local port connect() should use! */
1934 char *str=&data->state.buffer[4]; /* start on the first letter */
1936 /* if we come here again, make sure the former name is cleared */
1937 Curl_safefree(ftpc->newhost);
1939 if((ftpc->count1 == 0) &&
1941 /* positive EPSV response */
1942 char *ptr = strchr(str, '(');
1947 if(5 == sscanf(ptr, "%c%c%c%u%c",
1953 const char sep1 = separator[0];
1956 /* The four separators should be identical, or else this is an oddly
1957 formatted reply and we bail out immediately. */
1958 for(i=1; i<4; i++) {
1959 if(separator[i] != sep1) {
1960 ptr=NULL; /* set to NULL to signal error */
1965 failf(data, "Illegal port number in EPSV reply");
1966 return CURLE_FTP_WEIRD_PASV_REPLY;
1969 ftpc->newport = (unsigned short)(num & 0xffff);
1970 ftpc->newhost = strdup(control_address(conn));
1972 return CURLE_OUT_OF_MEMORY;
1979 failf(data, "Weirdly formatted EPSV reply");
1980 return CURLE_FTP_WEIRD_PASV_REPLY;
1983 else if((ftpc->count1 == 1) &&
1985 /* positive PASV response */
1990 * Scan for a sequence of six comma-separated numbers and use them as
1991 * IP+port indicators.
1993 * Found reply-strings include:
1994 * "227 Entering Passive Mode (127,0,0,1,4,51)"
1995 * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1996 * "227 Entering passive mode. 127,0,0,1,4,51"
1999 if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
2000 &ip[0], &ip[1], &ip[2], &ip[3],
2001 &port[0], &port[1]))
2007 failf(data, "Couldn't interpret the 227-response");
2008 return CURLE_FTP_WEIRD_227_FORMAT;
2011 /* we got OK from server */
2012 if(data->set.ftp_skip_ip) {
2013 /* told to ignore the remotely given IP but instead use the host we used
2014 for the control connection */
2015 infof(data, "Skip %d.%d.%d.%d for data connection, re-use %s instead\n",
2016 ip[0], ip[1], ip[2], ip[3],
2018 ftpc->newhost = strdup(control_address(conn));
2021 ftpc->newhost = aprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
2024 return CURLE_OUT_OF_MEMORY;
2026 ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
2028 else if(ftpc->count1 == 0) {
2029 /* EPSV failed, move on to PASV */
2030 return ftp_epsv_disable(conn);
2033 failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
2034 return CURLE_FTP_WEIRD_PASV_REPLY;
2037 if(conn->bits.proxy) {
2039 * This connection uses a proxy and we need to connect to the proxy again
2040 * here. We don't want to rely on a former host lookup that might've
2041 * expired now, instead we remake the lookup here and now!
2043 rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
2044 if(rc == CURLRESOLV_PENDING)
2045 /* BLOCKING, ignores the return code but 'addr' will be NULL in
2047 (void)Curl_resolver_wait_resolv(conn, &addr);
2050 (unsigned short)conn->port; /* we connect to the proxy's port */
2053 failf(data, "Can't resolve proxy host %s:%hu",
2054 conn->proxy.name, connectport);
2055 return CURLE_FTP_CANT_GET_HOST;
2059 /* normal, direct, ftp connection */
2060 rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr);
2061 if(rc == CURLRESOLV_PENDING)
2063 (void)Curl_resolver_wait_resolv(conn, &addr);
2065 connectport = ftpc->newport; /* we connect to the remote port */
2068 failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
2069 return CURLE_FTP_CANT_GET_HOST;
2073 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
2074 result = Curl_connecthost(conn, addr);
2077 Curl_resolv_unlock(data, addr); /* we're done using this address */
2078 if(ftpc->count1 == 0 && ftpcode == 229)
2079 return ftp_epsv_disable(conn);
2086 * When this is used from the multi interface, this might've returned with
2087 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
2088 * connect to connect.
2091 if(data->set.verbose)
2092 /* this just dumps information about this second connection */
2093 ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport);
2095 Curl_resolv_unlock(data, addr); /* we're done using this address */
2096 conn->bits.do_more = TRUE;
2097 state(conn, FTP_STOP); /* this phase is completed */
2102 static CURLcode ftp_state_port_resp(struct connectdata *conn,
2105 struct SessionHandle *data = conn->data;
2106 struct ftp_conn *ftpc = &conn->proto.ftpc;
2107 ftpport fcmd = (ftpport)ftpc->count1;
2108 CURLcode result = CURLE_OK;
2110 /* The FTP spec tells a positive response should have code 200.
2111 Be more permissive here to tolerate deviant servers. */
2112 if(ftpcode / 100 != 2) {
2113 /* the command failed */
2116 infof(data, "disabling EPRT usage\n");
2117 conn->bits.ftp_use_eprt = FALSE;
2122 failf(data, "Failed to do PORT");
2123 result = CURLE_FTP_PORT_FAILED;
2127 result = ftp_state_use_port(conn, fcmd);
2130 infof(data, "Connect data stream actively\n");
2131 state(conn, FTP_STOP); /* end of DO phase */
2132 result = ftp_dophase_done(conn, FALSE);
2138 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
2141 CURLcode result = CURLE_OK;
2142 struct SessionHandle *data=conn->data;
2143 struct FTP *ftp = data->req.protop;
2144 struct ftp_conn *ftpc = &conn->proto.ftpc;
2149 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
2150 last .sss part is optional and means fractions of a second */
2151 int year, month, day, hour, minute, second;
2152 char *buf = data->state.buffer;
2153 if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
2154 &year, &month, &day, &hour, &minute, &second)) {
2155 /* we have a time, reformat it */
2156 time_t secs=time(NULL);
2157 /* using the good old yacc/bison yuck */
2158 snprintf(buf, sizeof(conn->data->state.buffer),
2159 "%04d%02d%02d %02d:%02d:%02d GMT",
2160 year, month, day, hour, minute, second);
2161 /* now, convert this into a time() value: */
2162 data->info.filetime = (long)curl_getdate(buf, &secs);
2165 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2166 /* If we asked for a time of the file and we actually got one as well,
2167 we "emulate" a HTTP-style header in our output. */
2169 if(data->set.opt_no_body &&
2171 data->set.get_filetime &&
2172 (data->info.filetime>=0) ) {
2173 time_t filetime = (time_t)data->info.filetime;
2175 const struct tm *tm = &buffer;
2177 result = Curl_gmtime(filetime, &buffer);
2181 /* format: "Tue, 15 Nov 1994 12:45:26" */
2182 snprintf(buf, BUFSIZE-1,
2183 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
2184 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2186 Curl_month[tm->tm_mon],
2191 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2194 } /* end of a ridiculous amount of conditionals */
2199 infof(data, "unsupported MDTM reply format\n");
2201 case 550: /* "No such file or directory" */
2202 failf(data, "Given file does not exist");
2203 result = CURLE_FTP_COULDNT_RETR_FILE;
2207 if(data->set.timecondition) {
2208 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2209 switch(data->set.timecondition) {
2210 case CURL_TIMECOND_IFMODSINCE:
2212 if(data->info.filetime <= data->set.timevalue) {
2213 infof(data, "The requested document is not new enough\n");
2214 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2215 data->info.timecond = TRUE;
2216 state(conn, FTP_STOP);
2220 case CURL_TIMECOND_IFUNMODSINCE:
2221 if(data->info.filetime > data->set.timevalue) {
2222 infof(data, "The requested document is not old enough\n");
2223 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2224 data->info.timecond = TRUE;
2225 state(conn, FTP_STOP);
2232 infof(data, "Skipping time comparison\n");
2237 result = ftp_state_type(conn);
2242 static CURLcode ftp_state_type_resp(struct connectdata *conn,
2246 CURLcode result = CURLE_OK;
2247 struct SessionHandle *data=conn->data;
2249 if(ftpcode/100 != 2) {
2250 /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
2251 successful 'TYPE I'. While that is not as RFC959 says, it is still a
2252 positive response code and we allow that. */
2253 failf(data, "Couldn't set desired mode");
2254 return CURLE_FTP_COULDNT_SET_TYPE;
2257 infof(data, "Got a %03d response code instead of the assumed 200\n",
2260 if(instate == FTP_TYPE)
2261 result = ftp_state_size(conn);
2262 else if(instate == FTP_LIST_TYPE)
2263 result = ftp_state_list(conn);
2264 else if(instate == FTP_RETR_TYPE)
2265 result = ftp_state_retr_prequote(conn);
2266 else if(instate == FTP_STOR_TYPE)
2267 result = ftp_state_stor_prequote(conn);
2272 static CURLcode ftp_state_retr(struct connectdata *conn,
2273 curl_off_t filesize)
2275 CURLcode result = CURLE_OK;
2276 struct SessionHandle *data=conn->data;
2277 struct FTP *ftp = data->req.protop;
2278 struct ftp_conn *ftpc = &conn->proto.ftpc;
2280 if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
2281 failf(data, "Maximum file size exceeded");
2282 return CURLE_FILESIZE_EXCEEDED;
2284 ftp->downloadsize = filesize;
2286 if(data->state.resume_from) {
2287 /* We always (attempt to) get the size of downloads, so it is done before
2288 this even when not doing resumes. */
2289 if(filesize == -1) {
2290 infof(data, "ftp server doesn't support SIZE\n");
2291 /* We couldn't get the size and therefore we can't know if there really
2292 is a part of the file left to get, although the server will just
2293 close the connection when we start the connection so it won't cause
2294 us any harm, just not make us exit as nicely. */
2297 /* We got a file size report, so we check that there actually is a
2298 part of the file left to get, or else we go home. */
2299 if(data->state.resume_from< 0) {
2300 /* We're supposed to download the last abs(from) bytes */
2301 if(filesize < -data->state.resume_from) {
2302 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2303 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2304 data->state.resume_from, filesize);
2305 return CURLE_BAD_DOWNLOAD_RESUME;
2307 /* convert to size to download */
2308 ftp->downloadsize = -data->state.resume_from;
2309 /* download from where? */
2310 data->state.resume_from = filesize - ftp->downloadsize;
2313 if(filesize < data->state.resume_from) {
2314 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2315 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2316 data->state.resume_from, filesize);
2317 return CURLE_BAD_DOWNLOAD_RESUME;
2319 /* Now store the number of bytes we are expected to download */
2320 ftp->downloadsize = filesize-data->state.resume_from;
2324 if(ftp->downloadsize == 0) {
2325 /* no data to transfer */
2326 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2327 infof(data, "File already completely downloaded\n");
2329 /* Set ->transfer so that we won't get any error in ftp_done()
2330 * because we didn't transfer the any file */
2331 ftp->transfer = FTPTRANSFER_NONE;
2332 state(conn, FTP_STOP);
2336 /* Set resume file transfer offset */
2337 infof(data, "Instructs server to resume from offset %"
2338 CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
2340 PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
2341 data->state.resume_from);
2343 state(conn, FTP_RETR_REST);
2347 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2348 state(conn, FTP_RETR);
2354 static CURLcode ftp_state_size_resp(struct connectdata *conn,
2358 CURLcode result = CURLE_OK;
2359 struct SessionHandle *data=conn->data;
2360 curl_off_t filesize;
2361 char *buf = data->state.buffer;
2363 /* get the size from the ascii string: */
2364 filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
2366 if(instate == FTP_SIZE) {
2367 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2368 if(-1 != filesize) {
2369 snprintf(buf, sizeof(data->state.buffer),
2370 "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
2371 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2376 Curl_pgrsSetDownloadSize(data, filesize);
2377 result = ftp_state_rest(conn);
2379 else if(instate == FTP_RETR_SIZE) {
2380 Curl_pgrsSetDownloadSize(data, filesize);
2381 result = ftp_state_retr(conn, filesize);
2383 else if(instate == FTP_STOR_SIZE) {
2384 data->state.resume_from = filesize;
2385 result = ftp_state_ul_setup(conn, TRUE);
2391 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
2395 CURLcode result = CURLE_OK;
2396 struct ftp_conn *ftpc = &conn->proto.ftpc;
2401 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2402 if(ftpcode == 350) {
2403 char buffer[24]= { "Accept-ranges: bytes\r\n" };
2404 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
2409 result = ftp_state_prepare_transfer(conn);
2413 if(ftpcode != 350) {
2414 failf(conn->data, "Couldn't use REST");
2415 result = CURLE_FTP_COULDNT_USE_REST;
2418 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2419 state(conn, FTP_RETR);
2427 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
2428 int ftpcode, ftpstate instate)
2430 CURLcode result = CURLE_OK;
2431 struct SessionHandle *data = conn->data;
2434 failf(data, "Failed FTP upload: %0d", ftpcode);
2435 state(conn, FTP_STOP);
2436 /* oops, we never close the sockets! */
2437 return CURLE_UPLOAD_FAILED;
2440 conn->proto.ftpc.state_saved = instate;
2442 /* PORT means we are now awaiting the server to connect to us. */
2443 if(data->set.ftp_use_port) {
2446 state(conn, FTP_STOP); /* no longer in STOR state */
2448 result = AllowServerConnect(conn, &connected);
2453 struct ftp_conn *ftpc = &conn->proto.ftpc;
2454 infof(data, "Data conn was not available immediately\n");
2455 ftpc->wait_data_conn = TRUE;
2461 return InitiateTransfer(conn);
2464 /* for LIST and RETR responses */
2465 static CURLcode ftp_state_get_resp(struct connectdata *conn,
2469 CURLcode result = CURLE_OK;
2470 struct SessionHandle *data = conn->data;
2471 struct FTP *ftp = data->req.protop;
2472 char *buf = data->state.buffer;
2474 if((ftpcode == 150) || (ftpcode == 125)) {
2478 150 Opening BINARY mode data connection for /etc/passwd (2241
2479 bytes). (ok, the file is being transferred)
2482 150 Opening ASCII mode data connection for /bin/ls
2485 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2488 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
2491 125 Data connection already open; Transfer starting. */
2493 curl_off_t size=-1; /* default unknown size */
2497 * It appears that there are FTP-servers that return size 0 for files when
2498 * SIZE is used on the file while being in BINARY mode. To work around
2499 * that (stupid) behavior, we attempt to parse the RETR response even if
2500 * the SIZE returned size zero.
2502 * Debugging help from Salvatore Sorrentino on February 26, 2003.
2505 if((instate != FTP_LIST) &&
2506 !data->set.prefer_ascii &&
2507 (ftp->downloadsize < 1)) {
2509 * It seems directory listings either don't show the size or very
2510 * often uses size 0 anyway. ASCII transfers may very well turn out
2511 * that the transferred amount of data is not the same as this line
2512 * tells, why using this number in those cases only confuses us.
2514 * Example D above makes this parsing a little tricky */
2516 bytes=strstr(buf, " bytes");
2518 long in=(long)(bytes-buf);
2519 /* this is a hint there is size information in there! ;-) */
2521 /* scan for the left parenthesis and break there */
2524 /* skip only digits */
2525 if(!ISDIGIT(*bytes)) {
2529 /* one more estep backwards */
2532 /* if we have nothing but digits: */
2534 /* get the number! */
2535 size = curlx_strtoofft(bytes, NULL, 0);
2539 else if(ftp->downloadsize > -1)
2540 size = ftp->downloadsize;
2542 if(size > data->req.maxdownload && data->req.maxdownload > 0)
2543 size = data->req.size = data->req.maxdownload;
2544 else if((instate != FTP_LIST) && (data->set.prefer_ascii))
2545 size = -1; /* kludge for servers that understate ASCII mode file size */
2547 infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
2548 data->req.maxdownload);
2550 if(instate != FTP_LIST)
2551 infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n",
2555 conn->proto.ftpc.state_saved = instate;
2556 conn->proto.ftpc.retr_size_saved = size;
2558 if(data->set.ftp_use_port) {
2561 result = AllowServerConnect(conn, &connected);
2566 struct ftp_conn *ftpc = &conn->proto.ftpc;
2567 infof(data, "Data conn was not available immediately\n");
2568 state(conn, FTP_STOP);
2569 ftpc->wait_data_conn = TRUE;
2573 return InitiateTransfer(conn);
2576 if((instate == FTP_LIST) && (ftpcode == 450)) {
2577 /* simply no matching files in the dir listing */
2578 ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
2579 state(conn, FTP_STOP); /* this phase is over */
2582 failf(data, "RETR response: %03d", ftpcode);
2583 return instate == FTP_RETR && ftpcode == 550?
2584 CURLE_REMOTE_FILE_NOT_FOUND:
2585 CURLE_FTP_COULDNT_RETR_FILE;
2592 /* after USER, PASS and ACCT */
2593 static CURLcode ftp_state_loggedin(struct connectdata *conn)
2595 CURLcode result = CURLE_OK;
2597 if(conn->ssl[FIRSTSOCKET].use) {
2598 /* PBSZ = PROTECTION BUFFER SIZE.
2600 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2602 Specifically, the PROT command MUST be preceded by a PBSZ
2603 command and a PBSZ command MUST be preceded by a successful
2604 security data exchange (the TLS negotiation in this case)
2606 ... (and on page 8):
2608 Thus the PBSZ command must still be issued, but must have a
2609 parameter of '0' to indicate that no buffering is taking place
2610 and the data connection should not be encapsulated.
2612 PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
2613 state(conn, FTP_PBSZ);
2616 result = ftp_state_pwd(conn);
2621 /* for USER and PASS responses */
2622 static CURLcode ftp_state_user_resp(struct connectdata *conn,
2626 CURLcode result = CURLE_OK;
2627 struct SessionHandle *data = conn->data;
2628 struct FTP *ftp = data->req.protop;
2629 struct ftp_conn *ftpc = &conn->proto.ftpc;
2630 (void)instate; /* no use for this yet */
2632 /* some need password anyway, and others just return 2xx ignored */
2633 if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2634 /* 331 Password required for ...
2635 (the server requires to send the user's password too) */
2636 PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
2637 state(conn, FTP_PASS);
2639 else if(ftpcode/100 == 2) {
2640 /* 230 User ... logged in.
2641 (the user logged in with or without password) */
2642 result = ftp_state_loggedin(conn);
2644 else if(ftpcode == 332) {
2645 if(data->set.str[STRING_FTP_ACCOUNT]) {
2646 PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
2647 state(conn, FTP_ACCT);
2650 failf(data, "ACCT requested but none available");
2651 result = CURLE_LOGIN_DENIED;
2655 /* All other response codes, like:
2657 530 User ... access denied
2658 (the server denies to log the specified user) */
2660 if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2661 !conn->data->state.ftp_trying_alternative) {
2662 /* Ok, USER failed. Let's try the supplied command. */
2663 PPSENDF(&conn->proto.ftpc.pp, "%s",
2664 conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2665 conn->data->state.ftp_trying_alternative = TRUE;
2666 state(conn, FTP_USER);
2670 failf(data, "Access denied: %03d", ftpcode);
2671 result = CURLE_LOGIN_DENIED;
2677 /* for ACCT response */
2678 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
2681 CURLcode result = CURLE_OK;
2682 struct SessionHandle *data = conn->data;
2683 if(ftpcode != 230) {
2684 failf(data, "ACCT rejected by server: %03d", ftpcode);
2685 result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2688 result = ftp_state_loggedin(conn);
2694 static CURLcode ftp_statemach_act(struct connectdata *conn)
2697 curl_socket_t sock = conn->sock[FIRSTSOCKET];
2698 struct SessionHandle *data=conn->data;
2700 struct ftp_conn *ftpc = &conn->proto.ftpc;
2701 struct pingpong *pp = &ftpc->pp;
2702 static const char ftpauth[][4] = { "SSL", "TLS" };
2706 return Curl_pp_flushsend(pp);
2708 result = ftp_readresp(sock, pp, &ftpcode, &nread);
2713 /* we have now received a full FTP server response */
2714 switch(ftpc->state) {
2717 /* 230 User logged in - already! */
2718 return ftp_state_user_resp(conn, ftpcode, ftpc->state);
2719 else if(ftpcode != 220) {
2720 failf(data, "Got a %03d ftp-server response when 220 was expected",
2722 return CURLE_FTP_WEIRD_SERVER_REPLY;
2725 /* We have received a 220 response fine, now we proceed. */
2728 /* If not anonymous login, try a secure login. Note that this
2729 procedure is still BLOCKING. */
2731 Curl_sec_request_prot(conn, "private");
2732 /* We set private first as default, in case the line below fails to
2733 set a valid level */
2734 Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2736 if(Curl_sec_login(conn))
2737 infof(data, "Logging in with password in cleartext!\n");
2739 infof(data, "Authentication successful\n");
2743 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
2744 /* We don't have a SSL/TLS connection yet, but FTPS is
2745 requested. Try a FTPS connection now */
2748 switch(data->set.ftpsslauth) {
2749 case CURLFTPAUTH_DEFAULT:
2750 case CURLFTPAUTH_SSL:
2751 ftpc->count2 = 1; /* add one to get next */
2754 case CURLFTPAUTH_TLS:
2755 ftpc->count2 = -1; /* subtract one to get next */
2759 failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2760 (int)data->set.ftpsslauth);
2761 return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
2763 PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2764 state(conn, FTP_AUTH);
2767 result = ftp_state_user(conn);
2775 /* we have gotten the response to a previous AUTH command */
2777 /* RFC2228 (page 5) says:
2779 * If the server is willing to accept the named security mechanism,
2780 * and does not require any security data, it must respond with
2781 * reply code 234/334.
2784 if((ftpcode == 234) || (ftpcode == 334)) {
2785 /* Curl_ssl_connect is BLOCKING */
2786 result = Curl_ssl_connect(conn, FIRSTSOCKET);
2788 conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
2789 result = ftp_state_user(conn);
2792 else if(ftpc->count3 < 1) {
2794 ftpc->count1 += ftpc->count2; /* get next attempt */
2795 result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2796 /* remain in this same state */
2799 if(data->set.use_ssl > CURLUSESSL_TRY)
2800 /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2801 result = CURLE_USE_SSL_FAILED;
2803 /* ignore the failure and continue */
2804 result = ftp_state_user(conn);
2813 result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
2817 result = ftp_state_acct_resp(conn, ftpcode);
2821 PPSENDF(&ftpc->pp, "PROT %c",
2822 data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2823 state(conn, FTP_PROT);
2828 if(ftpcode/100 == 2)
2829 /* We have enabled SSL for the data connection! */
2830 conn->ssl[SECONDARYSOCKET].use =
2831 (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
2832 /* FTP servers typically responds with 500 if they decide to reject
2834 else if(data->set.use_ssl > CURLUSESSL_CONTROL)
2835 /* we failed and bails out */
2836 return CURLE_USE_SSL_FAILED;
2838 if(data->set.ftp_ccc) {
2839 /* CCC - Clear Command Channel
2841 PPSENDF(&ftpc->pp, "%s", "CCC");
2842 state(conn, FTP_CCC);
2845 result = ftp_state_pwd(conn);
2853 /* First shut down the SSL layer (note: this call will block) */
2854 result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
2857 failf(conn->data, "Failed to clear the command channel (CCC)");
2862 /* Then continue as normal */
2863 result = ftp_state_pwd(conn);
2869 if(ftpcode == 257) {
2870 char *ptr=&data->state.buffer[4]; /* start on the first letter */
2874 dir = malloc(nread + 1);
2876 return CURLE_OUT_OF_MEMORY;
2878 /* Reply format is like
2879 257<space>[rubbish]"<directory-name>"<space><commentary> and the
2882 The directory name can contain any character; embedded
2883 double-quotes should be escaped by double-quotes (the
2884 "quote-doubling" convention).
2887 /* scan for the first double-quote for non-standard responses */
2888 while(ptr < &data->state.buffer[sizeof(data->state.buffer)]
2889 && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
2893 /* it started good */
2895 for(store = dir; *ptr;) {
2897 if('\"' == ptr[1]) {
2898 /* "quote-doubling" */
2904 *store = '\0'; /* zero terminate */
2905 break; /* get out of this loop */
2914 /* If the path name does not look like an absolute path (i.e.: it
2915 does not start with a '/'), we probably need some server-dependent
2916 adjustments. For example, this is the case when connecting to
2917 an OS400 FTP server: this server supports two name syntaxes,
2918 the default one being incompatible with standard pathes. In
2919 addition, this server switches automatically to the regular path
2920 syntax when one is encountered in a command: this results in
2921 having an entrypath in the wrong syntax when later used in CWD.
2922 The method used here is to check the server OS: we do it only
2923 if the path name looks strange to minimize overhead on other
2926 if(!ftpc->server_os && dir[0] != '/') {
2928 result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
2933 Curl_safefree(ftpc->entrypath);
2934 ftpc->entrypath = dir; /* remember this */
2935 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2936 /* also save it where getinfo can access it: */
2937 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2938 state(conn, FTP_SYST);
2942 Curl_safefree(ftpc->entrypath);
2943 ftpc->entrypath = dir; /* remember this */
2944 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2945 /* also save it where getinfo can access it: */
2946 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2949 /* couldn't get the path */
2951 infof(data, "Failed to figure out path\n");
2954 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2955 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2959 if(ftpcode == 215) {
2960 char *ptr=&data->state.buffer[4]; /* start on the first letter */
2964 os = malloc(nread + 1);
2966 return CURLE_OUT_OF_MEMORY;
2968 /* Reply format is like
2969 215<space><OS-name><space><commentary>
2973 for(store = os; *ptr && *ptr != ' ';)
2975 *store = '\0'; /* zero terminate */
2977 /* Check for special servers here. */
2979 if(strequal(os, "OS/400")) {
2980 /* Force OS400 name format 1. */
2981 result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
2986 /* remember target server OS */
2987 Curl_safefree(ftpc->server_os);
2988 ftpc->server_os = os;
2989 state(conn, FTP_NAMEFMT);
2993 /* Nothing special for the target server. */
2994 /* remember target server OS */
2995 Curl_safefree(ftpc->server_os);
2996 ftpc->server_os = os;
3000 /* Cannot identify server OS. Continue anyway and cross fingers. */
3003 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
3004 DEBUGF(infof(data, "protocol connect phase DONE\n"));
3008 if(ftpcode == 250) {
3009 /* Name format change successful: reload initial path. */
3010 ftp_state_pwd(conn);
3014 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
3015 DEBUGF(infof(data, "protocol connect phase DONE\n"));
3020 case FTP_RETR_PREQUOTE:
3021 case FTP_STOR_PREQUOTE:
3022 if((ftpcode >= 400) && !ftpc->count2) {
3023 /* failure response code, and not allowed to fail */
3024 failf(conn->data, "QUOT command failed with %03d", ftpcode);
3025 return CURLE_QUOTE_ERROR;
3027 result = ftp_state_quote(conn, FALSE, ftpc->state);
3034 if(ftpcode/100 != 2) {
3035 /* failure to CWD there */
3036 if(conn->data->set.ftp_create_missing_dirs &&
3037 ftpc->count1 && !ftpc->count2) {
3039 ftpc->count2++; /* counter to prevent CWD-MKD loops */
3040 PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
3041 state(conn, FTP_MKD);
3044 /* return failure */
3045 failf(data, "Server denied you to change to the given directory");
3046 ftpc->cwdfail = TRUE; /* don't remember this path as we failed
3048 return CURLE_REMOTE_ACCESS_DENIED;
3054 if(++ftpc->count1 <= ftpc->dirdepth) {
3056 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3059 result = ftp_state_mdtm(conn);
3067 if((ftpcode/100 != 2) && !ftpc->count3--) {
3068 /* failure to MKD the dir */
3069 failf(data, "Failed to MKD dir: %03d", ftpcode);
3070 return CURLE_REMOTE_ACCESS_DENIED;
3072 state(conn, FTP_CWD);
3074 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3078 result = ftp_state_mdtm_resp(conn, ftpcode);
3085 result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
3091 result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
3096 result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
3100 if(ftpcode != 200) {
3101 /* there only is this one standard OK return code. */
3102 failf(data, "PRET command not accepted: %03d", ftpcode);
3103 return CURLE_FTP_PRET_FAILED;
3105 result = ftp_state_use_pasv(conn);
3109 result = ftp_state_pasv_resp(conn, ftpcode);
3113 result = ftp_state_port_resp(conn, ftpcode);
3118 result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
3122 result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
3126 /* fallthrough, just stop! */
3128 /* internal error */
3129 state(conn, FTP_STOP);
3138 /* called repeatedly until done from multi.c */
3139 static CURLcode ftp_multi_statemach(struct connectdata *conn,
3142 struct ftp_conn *ftpc = &conn->proto.ftpc;
3143 CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
3145 /* Check for the state outside of the Curl_socket_ready() return code checks
3146 since at times we are in fact already in this state when this function
3148 *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
3153 static CURLcode ftp_block_statemach(struct connectdata *conn)
3155 struct ftp_conn *ftpc = &conn->proto.ftpc;
3156 struct pingpong *pp = &ftpc->pp;
3157 CURLcode result = CURLE_OK;
3159 while(ftpc->state != FTP_STOP) {
3160 result = Curl_pp_statemach(pp, TRUE);
3169 * ftp_connect() should do everything that is to be considered a part of
3170 * the connection phase.
3172 * The variable 'done' points to will be TRUE if the protocol-layer connect
3173 * phase is done when this function returns, or FALSE if not.
3176 static CURLcode ftp_connect(struct connectdata *conn,
3177 bool *done) /* see description above */
3180 struct ftp_conn *ftpc = &conn->proto.ftpc;
3181 struct pingpong *pp = &ftpc->pp;
3183 *done = FALSE; /* default to not done yet */
3185 /* We always support persistent connections on ftp */
3186 connkeep(conn, "FTP default");
3188 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
3189 pp->statemach_act = ftp_statemach_act;
3190 pp->endofresp = ftp_endofresp;
3193 if(conn->handler->flags & PROTOPT_SSL) {
3195 result = Curl_ssl_connect(conn, FIRSTSOCKET);
3200 Curl_pp_init(pp); /* init the generic pingpong data */
3202 /* When we connect, we start in the state where we await the 220
3204 state(conn, FTP_WAIT220);
3206 result = ftp_multi_statemach(conn, done);
3211 /***********************************************************************
3215 * The DONE function. This does what needs to be done after a single DO has
3218 * Input argument is already checked for validity.
3220 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
3223 struct SessionHandle *data = conn->data;
3224 struct FTP *ftp = data->req.protop;
3225 struct ftp_conn *ftpc = &conn->proto.ftpc;
3226 struct pingpong *pp = &ftpc->pp;
3229 CURLcode result = CURLE_OK;
3230 bool was_ctl_valid = ftpc->ctl_valid;
3232 const char *path_to_use = data->state.path;
3235 /* When the easy handle is removed from the multi while libcurl is still
3236 * trying to resolve the host name, it seems that the ftp struct is not
3237 * yet initialized, but the removal action calls Curl_done() which calls
3238 * this function. So we simply return success if no ftp pointer is set.
3243 case CURLE_BAD_DOWNLOAD_RESUME:
3244 case CURLE_FTP_WEIRD_PASV_REPLY:
3245 case CURLE_FTP_PORT_FAILED:
3246 case CURLE_FTP_ACCEPT_FAILED:
3247 case CURLE_FTP_ACCEPT_TIMEOUT:
3248 case CURLE_FTP_COULDNT_SET_TYPE:
3249 case CURLE_FTP_COULDNT_RETR_FILE:
3250 case CURLE_PARTIAL_FILE:
3251 case CURLE_UPLOAD_FAILED:
3252 case CURLE_REMOTE_ACCESS_DENIED:
3253 case CURLE_FILESIZE_EXCEEDED:
3254 case CURLE_REMOTE_FILE_NOT_FOUND:
3255 case CURLE_WRITE_ERROR:
3256 /* the connection stays alive fine even though this happened */
3258 case CURLE_OK: /* doesn't affect the control connection's status */
3260 ftpc->ctl_valid = was_ctl_valid;
3263 /* until we cope better with prematurely ended requests, let them
3264 * fallback as if in complete failure */
3265 default: /* by default, an error means the control connection is
3266 wedged and should not be used anymore */
3267 ftpc->ctl_valid = FALSE;
3268 ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3269 current path, as this connection is going */
3270 connclose(conn, "FTP ended with bad error code");
3271 result = status; /* use the already set error code */
3275 /* now store a copy of the directory we are in */
3276 free(ftpc->prevpath);
3278 if(data->set.wildcardmatch) {
3279 if(data->set.chunk_end && ftpc->file) {
3280 data->set.chunk_end(data->wildcard.customptr);
3282 ftpc->known_filesize = -1;
3285 /* get the "raw" path */
3286 path = curl_easy_unescape(data, path_to_use, 0, NULL);
3288 /* out of memory, but we can limp along anyway (and should try to
3289 * since we may already be in the out of memory cleanup path) */
3291 result = CURLE_OUT_OF_MEMORY;
3292 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3293 connclose(conn, "FTP: out of memory!"); /* mark for connection closure */
3294 ftpc->prevpath = NULL; /* no path remembering */
3297 size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
3298 size_t dlen = strlen(path)-flen;
3299 if(!ftpc->cwdfail) {
3300 if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
3301 ftpc->prevpath = path;
3303 /* if 'path' is not the whole string */
3304 ftpc->prevpath[dlen]=0; /* terminate */
3307 /* we never changed dir */
3308 ftpc->prevpath=strdup("");
3312 infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
3315 ftpc->prevpath = NULL; /* no path */
3319 /* free the dir tree and file parts */
3322 /* shut down the socket to inform the server we're done */
3325 shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */
3328 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3329 if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
3330 /* partial download completed */
3331 result = Curl_pp_sendf(pp, "%s", "ABOR");
3333 failf(data, "Failure sending ABOR command: %s",
3334 curl_easy_strerror(result));
3335 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3336 connclose(conn, "ABOR command failed"); /* connection closure */
3340 if(conn->ssl[SECONDARYSOCKET].use) {
3341 /* The secondary socket is using SSL so we must close down that part
3342 first before we close the socket for real */
3343 Curl_ssl_close(conn, SECONDARYSOCKET);
3345 /* Note that we keep "use" set to TRUE since that (next) connection is
3346 still requested to use SSL */
3348 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
3349 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
3350 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
3351 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
3355 if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
3356 pp->pending_resp && !premature) {
3358 * Let's see what the server says about the transfer we just performed,
3359 * but lower the timeout as sometimes this connection has died while the
3360 * data has been transferred. This happens when doing through NATs etc that
3361 * abandon old silent connections.
3363 long old_time = pp->response_time;
3365 pp->response_time = 60*1000; /* give it only a minute for now */
3366 pp->response = Curl_tvnow(); /* timeout relative now */
3368 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3370 pp->response_time = old_time; /* set this back to previous value */
3372 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3373 failf(data, "control connection looks dead");
3374 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3375 connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
3381 if(ftpc->dont_check && data->req.maxdownload > 0) {
3382 /* we have just sent ABOR and there is no reliable way to check if it was
3383 * successful or not; we have to close the connection now */
3384 infof(data, "partial download completed, closing connection\n");
3385 connclose(conn, "Partial download with no ability to check");
3389 if(!ftpc->dont_check) {
3390 /* 226 Transfer complete, 250 Requested file action okay, completed. */
3391 if((ftpcode != 226) && (ftpcode != 250)) {
3392 failf(data, "server did not report OK, got %d", ftpcode);
3393 result = CURLE_PARTIAL_FILE;
3398 if(result || premature)
3399 /* the response code from the transfer showed an error already so no
3400 use checking further */
3402 else if(data->set.upload) {
3403 if((-1 != data->state.infilesize) &&
3404 (data->state.infilesize != *ftp->bytecountp) &&
3406 (ftp->transfer == FTPTRANSFER_BODY)) {
3407 failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
3408 " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
3409 *ftp->bytecountp, data->state.infilesize);
3410 result = CURLE_PARTIAL_FILE;
3414 if((-1 != data->req.size) &&
3415 (data->req.size != *ftp->bytecountp) &&
3416 #ifdef CURL_DO_LINEEND_CONV
3417 /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3418 * we'll check to see if the discrepancy can be explained by the number
3419 * of CRLFs we've changed to LFs.
3421 ((data->req.size + data->state.crlf_conversions) !=
3422 *ftp->bytecountp) &&
3423 #endif /* CURL_DO_LINEEND_CONV */
3424 (data->req.maxdownload != *ftp->bytecountp)) {
3425 failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
3426 " bytes", *ftp->bytecountp);
3427 result = CURLE_PARTIAL_FILE;
3429 else if(!ftpc->dont_check &&
3430 !*ftp->bytecountp &&
3431 (data->req.size>0)) {
3432 failf(data, "No data was received!");
3433 result = CURLE_FTP_COULDNT_RETR_FILE;
3437 /* clear these for next connection */
3438 ftp->transfer = FTPTRANSFER_BODY;
3439 ftpc->dont_check = FALSE;
3441 /* Send any post-transfer QUOTE strings? */
3442 if(!status && !result && !premature && data->set.postquote)
3443 result = ftp_sendquote(conn, data->set.postquote);
3448 /***********************************************************************
3452 * Where a 'quote' means a list of custom commands to send to the server.
3453 * The quote list is passed as an argument.
3459 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
3461 struct curl_slist *item;
3465 struct ftp_conn *ftpc = &conn->proto.ftpc;
3466 struct pingpong *pp = &ftpc->pp;
3471 char *cmd = item->data;
3472 bool acceptfail = FALSE;
3474 /* if a command starts with an asterisk, which a legal FTP command never
3475 can, the command will be allowed to fail without it causing any
3476 aborts or cancels etc. It will cause libcurl to act as if the command
3477 is successful, whatever the server reponds. */
3484 PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
3486 pp->response = Curl_tvnow(); /* timeout relative now */
3488 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3492 if(!acceptfail && (ftpcode >= 400)) {
3493 failf(conn->data, "QUOT string not accepted: %s", cmd);
3494 return CURLE_QUOTE_ERROR;
3504 /***********************************************************************
3508 * Returns TRUE if we in the current situation should send TYPE
3510 static int ftp_need_type(struct connectdata *conn,
3513 return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3516 /***********************************************************************
3520 * Set TYPE. We only deal with ASCII or BINARY so this function
3522 * If the transfer type is not sent, simulate on OK response in newstate
3524 static CURLcode ftp_nb_type(struct connectdata *conn,
3525 bool ascii, ftpstate newstate)
3527 struct ftp_conn *ftpc = &conn->proto.ftpc;
3529 char want = (char)(ascii?'A':'I');
3531 if(ftpc->transfertype == want) {
3532 state(conn, newstate);
3533 return ftp_state_type_resp(conn, 200, newstate);
3536 PPSENDF(&ftpc->pp, "TYPE %c", want);
3537 state(conn, newstate);
3539 /* keep track of our current transfer type */
3540 ftpc->transfertype = want;
3544 /***************************************************************************
3546 * ftp_pasv_verbose()
3548 * This function only outputs some informationals about this second connection
3549 * when we've issued a PASV command before and thus we have connected to a
3550 * possibly new IP address.
3553 #ifndef CURL_DISABLE_VERBOSE_STRINGS
3555 ftp_pasv_verbose(struct connectdata *conn,
3557 char *newhost, /* ascii version */
3561 Curl_printable_address(ai, buf, sizeof(buf));
3562 infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3567 Check if this is a range download, and if so, set the internal variables
3571 static CURLcode ftp_range(struct connectdata *conn)
3573 curl_off_t from, to;
3576 struct SessionHandle *data = conn->data;
3577 struct ftp_conn *ftpc = &conn->proto.ftpc;
3579 if(data->state.use_range && data->state.range) {
3580 from=curlx_strtoofft(data->state.range, &ptr, 0);
3581 while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
3583 to=curlx_strtoofft(ptr, &ptr2, 0);
3585 /* we didn't get any digit */
3588 if((-1 == to) && (from>=0)) {
3590 data->state.resume_from = from;
3591 DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T
3592 " to end of file\n", from));
3596 data->req.maxdownload = -from;
3597 data->state.resume_from = from;
3598 DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T
3599 " bytes\n", -from));
3603 data->req.maxdownload = (to-from)+1; /* include last byte */
3604 data->state.resume_from = from;
3605 DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T
3606 " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
3607 from, data->req.maxdownload));
3609 DEBUGF(infof(conn->data, "range-download from %" CURL_FORMAT_CURL_OFF_T
3610 " to %" CURL_FORMAT_CURL_OFF_T ", totally %"
3611 CURL_FORMAT_CURL_OFF_T " bytes\n",
3612 from, to, data->req.maxdownload));
3613 ftpc->dont_check = TRUE; /* dont check for successful transfer */
3616 data->req.maxdownload = -1;
3624 * This function shall be called when the second FTP (data) connection is
3627 * 'complete' can return 0 for incomplete, 1 for done and -1 for go back
3628 * (which basically is only for when PASV is being sent to retry a failed
3632 static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
3634 struct SessionHandle *data=conn->data;
3635 struct ftp_conn *ftpc = &conn->proto.ftpc;
3636 CURLcode result = CURLE_OK;
3637 bool connected = FALSE;
3638 bool complete = FALSE;
3640 /* the ftp struct is inited in ftp_connect() */
3641 struct FTP *ftp = data->req.protop;
3643 /* if the second connection isn't done yet, wait for it */
3644 if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
3645 if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
3646 /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
3647 aren't used so we blank their arguments. TODO: make this nicer */
3648 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0, FALSE);
3653 result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
3655 /* Ready to do more? */
3657 DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
3658 if(conn->bits.proxy) {
3659 infof(data, "Connection to proxy confirmed\n");
3660 result = proxy_magic(conn, ftpc->newhost, ftpc->newport, &connected);
3664 if(result && (ftpc->count1 == 0)) {
3665 *completep = -1; /* go back to DOING please */
3666 /* this is a EPSV connect failing, try PASV instead */
3667 return ftp_epsv_disable(conn);
3674 /* already in a state so skip the intial commands.
3675 They are only done to kickstart the do_more state */
3676 result = ftp_multi_statemach(conn, &complete);
3678 *completep = (int)complete;
3680 /* if we got an error or if we don't wait for a data connection return
3682 if(result || (ftpc->wait_data_conn != TRUE))
3685 if(ftpc->wait_data_conn)
3686 /* if we reach the end of the FTP state machine here, *complete will be
3687 TRUE but so is ftpc->wait_data_conn, which says we need to wait for
3688 the data connection and therefore we're not actually complete */
3692 if(ftp->transfer <= FTPTRANSFER_INFO) {
3693 /* a transfer is about to take place, or if not a file name was given
3694 so we'll do a SIZE on it later and then we need the right TYPE first */
3696 if(ftpc->wait_data_conn == TRUE) {
3699 result = ReceivedServerConnect(conn, &serv_conned);
3701 return result; /* Failed to accept data connection */
3704 /* It looks data connection is established */
3705 result = AcceptServerConnect(conn);
3706 ftpc->wait_data_conn = FALSE;
3708 result = InitiateTransfer(conn);
3713 *completep = 1; /* this state is now complete when the server has
3714 connected back to us */
3717 else if(data->set.upload) {
3718 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
3722 result = ftp_multi_statemach(conn, &complete);
3723 *completep = (int)complete;
3727 ftp->downloadsize = -1; /* unknown as of yet */
3729 result = ftp_range(conn);
3732 else if(data->set.ftp_list_only || !ftpc->file) {
3733 /* The specified path ends with a slash, and therefore we think this
3734 is a directory that is requested, use LIST. But before that we
3735 need to set ASCII transfer mode. */
3737 /* But only if a body transfer was requested. */
3738 if(ftp->transfer == FTPTRANSFER_BODY) {
3739 result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
3743 /* otherwise just fall through */
3746 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
3751 result = ftp_multi_statemach(conn, &complete);
3752 *completep = (int)complete;
3757 if(!result && (ftp->transfer != FTPTRANSFER_BODY))
3758 /* no data to transfer. FIX: it feels like a kludge to have this here
3760 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3762 if(!ftpc->wait_data_conn) {
3763 /* no waiting for the data connection so this is now complete */
3765 DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
3773 /***********************************************************************
3777 * This is the actual DO function for FTP. Get a file/directory according to
3778 * the options previously setup.
3782 CURLcode ftp_perform(struct connectdata *conn,
3783 bool *connected, /* connect status after PASV / PORT */
3786 /* this is FTP and no proxy */
3787 CURLcode result=CURLE_OK;
3789 DEBUGF(infof(conn->data, "DO phase starts\n"));
3791 if(conn->data->set.opt_no_body) {
3792 /* requested no body means no transfer... */
3793 struct FTP *ftp = conn->data->req.protop;
3794 ftp->transfer = FTPTRANSFER_INFO;
3797 *dophase_done = FALSE; /* not done yet */
3799 /* start the first command in the DO phase */
3800 result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
3804 /* run the state-machine */
3805 result = ftp_multi_statemach(conn, dophase_done);
3807 *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
3809 infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected);
3812 DEBUGF(infof(conn->data, "DO phase is complete1\n"));
3817 static void wc_data_dtor(void *ptr)
3819 struct ftp_wc_tmpdata *tmp = ptr;
3821 Curl_ftp_parselist_data_free(&tmp->parser);
3825 static CURLcode init_wc_data(struct connectdata *conn)
3828 char *path = conn->data->state.path;
3829 struct WildcardData *wildcard = &(conn->data->wildcard);
3830 CURLcode result = CURLE_OK;
3831 struct ftp_wc_tmpdata *ftp_tmp;
3833 last_slash = strrchr(conn->data->state.path, '/');
3836 if(last_slash[0] == '\0') {
3837 wildcard->state = CURLWC_CLEAN;
3838 result = ftp_parse_url_path(conn);
3842 wildcard->pattern = strdup(last_slash);
3843 if(!wildcard->pattern)
3844 return CURLE_OUT_OF_MEMORY;
3845 last_slash[0] = '\0'; /* cut file from path */
3848 else { /* there is only 'wildcard pattern' or nothing */
3850 wildcard->pattern = strdup(path);
3851 if(!wildcard->pattern)
3852 return CURLE_OUT_OF_MEMORY;
3855 else { /* only list */
3856 wildcard->state = CURLWC_CLEAN;
3857 result = ftp_parse_url_path(conn);
3862 /* program continues only if URL is not ending with slash, allocate needed
3863 resources for wildcard transfer */
3865 /* allocate ftp protocol specific temporary wildcard data */
3866 ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata));
3868 Curl_safefree(wildcard->pattern);
3869 return CURLE_OUT_OF_MEMORY;
3872 /* INITIALIZE parselist structure */
3873 ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
3874 if(!ftp_tmp->parser) {
3875 Curl_safefree(wildcard->pattern);
3877 return CURLE_OUT_OF_MEMORY;
3880 wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
3881 wildcard->tmp_dtor = wc_data_dtor;
3883 /* wildcard does not support NOCWD option (assert it?) */
3884 if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
3885 conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
3887 /* try to parse ftp url */
3888 result = ftp_parse_url_path(conn);
3890 Curl_safefree(wildcard->pattern);
3891 wildcard->tmp_dtor(wildcard->tmp);
3892 wildcard->tmp_dtor = ZERO_NULL;
3893 wildcard->tmp = NULL;
3897 wildcard->path = strdup(conn->data->state.path);
3898 if(!wildcard->path) {
3899 Curl_safefree(wildcard->pattern);
3900 wildcard->tmp_dtor(wildcard->tmp);
3901 wildcard->tmp_dtor = ZERO_NULL;
3902 wildcard->tmp = NULL;
3903 return CURLE_OUT_OF_MEMORY;
3906 /* backup old write_function */
3907 ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
3908 /* parsing write function */
3909 conn->data->set.fwrite_func = Curl_ftp_parselist;
3910 /* backup old file descriptor */
3911 ftp_tmp->backup.file_descriptor = conn->data->set.out;
3912 /* let the writefunc callback know what curl pointer is working with */
3913 conn->data->set.out = conn;
3915 infof(conn->data, "Wildcard - Parsing started\n");
3919 /* This is called recursively */
3920 static CURLcode wc_statemach(struct connectdata *conn)
3922 struct WildcardData * const wildcard = &(conn->data->wildcard);
3923 CURLcode result = CURLE_OK;
3925 switch (wildcard->state) {
3927 result = init_wc_data(conn);
3928 if(wildcard->state == CURLWC_CLEAN)
3932 wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
3935 case CURLWC_MATCHING: {
3936 /* In this state is LIST response successfully parsed, so lets restore
3937 previous WRITEFUNCTION callback and WRITEDATA pointer */
3938 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3939 conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
3940 conn->data->set.out = ftp_tmp->backup.file_descriptor;
3941 ftp_tmp->backup.write_function = ZERO_NULL;
3942 ftp_tmp->backup.file_descriptor = NULL;
3943 wildcard->state = CURLWC_DOWNLOADING;
3945 if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
3946 /* error found in LIST parsing */
3947 wildcard->state = CURLWC_CLEAN;
3948 return wc_statemach(conn);
3950 else if(wildcard->filelist->size == 0) {
3951 /* no corresponding file */
3952 wildcard->state = CURLWC_CLEAN;
3953 return CURLE_REMOTE_FILE_NOT_FOUND;
3955 return wc_statemach(conn);
3958 case CURLWC_DOWNLOADING: {
3959 /* filelist has at least one file, lets get first one */
3960 struct ftp_conn *ftpc = &conn->proto.ftpc;
3961 struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
3963 char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
3965 return CURLE_OUT_OF_MEMORY;
3967 /* switch default "state.pathbuffer" and tmp_path, good to see
3968 ftp_parse_url_path function to understand this trick */
3969 Curl_safefree(conn->data->state.pathbuffer);
3970 conn->data->state.pathbuffer = tmp_path;
3971 conn->data->state.path = tmp_path;
3973 infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
3974 if(conn->data->set.chunk_bgn) {
3975 long userresponse = conn->data->set.chunk_bgn(
3976 finfo, wildcard->customptr, (int)wildcard->filelist->size);
3977 switch(userresponse) {
3978 case CURL_CHUNK_BGN_FUNC_SKIP:
3979 infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
3981 wildcard->state = CURLWC_SKIP;
3982 return wc_statemach(conn);
3983 case CURL_CHUNK_BGN_FUNC_FAIL:
3984 return CURLE_CHUNK_FAILED;
3988 if(finfo->filetype != CURLFILETYPE_FILE) {
3989 wildcard->state = CURLWC_SKIP;
3990 return wc_statemach(conn);
3993 if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
3994 ftpc->known_filesize = finfo->size;
3996 result = ftp_parse_url_path(conn);
4000 /* we don't need the Curl_fileinfo of first file anymore */
4001 Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
4003 if(wildcard->filelist->size == 0) { /* remains only one file to down. */
4004 wildcard->state = CURLWC_CLEAN;
4005 /* after that will be ftp_do called once again and no transfer
4006 will be done because of CURLWC_CLEAN state */
4012 if(conn->data->set.chunk_end)
4013 conn->data->set.chunk_end(conn->data->wildcard.customptr);
4014 Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
4015 wildcard->state = (wildcard->filelist->size == 0) ?
4016 CURLWC_CLEAN : CURLWC_DOWNLOADING;
4017 return wc_statemach(conn);
4020 case CURLWC_CLEAN: {
4021 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
4024 result = Curl_ftp_parselist_geterror(ftp_tmp->parser);
4026 wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
4037 /***********************************************************************
4041 * This function is registered as 'curl_do' function. It decodes the path
4042 * parts etc as a wrapper to the actual DO function (ftp_perform).
4044 * The input argument is already checked for validity.
4046 static CURLcode ftp_do(struct connectdata *conn, bool *done)
4048 CURLcode result = CURLE_OK;
4049 struct ftp_conn *ftpc = &conn->proto.ftpc;
4051 *done = FALSE; /* default to false */
4052 ftpc->wait_data_conn = FALSE; /* default to no such wait */
4054 if(conn->data->set.wildcardmatch) {
4055 result = wc_statemach(conn);
4056 if(conn->data->wildcard.state == CURLWC_SKIP ||
4057 conn->data->wildcard.state == CURLWC_DONE) {
4058 /* do not call ftp_regular_transfer */
4061 if(result) /* error, loop or skipping the file */
4064 else { /* no wildcard FSM needed */
4065 result = ftp_parse_url_path(conn);
4070 result = ftp_regular_transfer(conn, done);
4076 CURLcode Curl_ftpsendf(struct connectdata *conn,
4077 const char *fmt, ...)
4079 ssize_t bytes_written;
4080 #define SBUF_SIZE 1024
4084 CURLcode result = CURLE_OK;
4086 enum protection_level data_sec = conn->data_prot;
4091 write_len = vsnprintf(s, SBUF_SIZE-3, fmt, ap);
4094 strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
4099 result = Curl_convert_to_network(conn->data, s, write_len);
4100 /* Curl_convert_to_network calls failf if unsuccessful */
4106 conn->data_prot = PROT_CMD;
4108 result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
4111 DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
4112 conn->data_prot = data_sec;
4118 if(conn->data->set.verbose)
4119 Curl_debug(conn->data, CURLINFO_HEADER_OUT,
4120 sptr, (size_t)bytes_written, conn);
4122 if(bytes_written != (ssize_t)write_len) {
4123 write_len -= bytes_written;
4124 sptr += bytes_written;
4133 /***********************************************************************
4137 * This should be called before calling sclose() on an ftp control connection
4138 * (not data connections). We should then wait for the response from the
4139 * server before returning. The calling code should then try to close the
4143 static CURLcode ftp_quit(struct connectdata *conn)
4145 CURLcode result = CURLE_OK;
4147 if(conn->proto.ftpc.ctl_valid) {
4148 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT");
4150 failf(conn->data, "Failure sending QUIT command: %s",
4151 curl_easy_strerror(result));
4152 conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
4153 connclose(conn, "QUIT command failed"); /* mark for connection closure */
4154 state(conn, FTP_STOP);
4158 state(conn, FTP_QUIT);
4160 result = ftp_block_statemach(conn);
4166 /***********************************************************************
4170 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
4171 * resources. BLOCKING.
4173 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
4175 struct ftp_conn *ftpc= &conn->proto.ftpc;
4176 struct pingpong *pp = &ftpc->pp;
4178 /* We cannot send quit unconditionally. If this connection is stale or
4179 bad in any way, sending quit and waiting around here will make the
4180 disconnect wait in vain and cause more problems than we need to.
4182 ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
4183 will try to send the QUIT command, otherwise it will just return.
4186 ftpc->ctl_valid = FALSE;
4188 /* The FTP session may or may not have been allocated/setup at this point! */
4189 (void)ftp_quit(conn); /* ignore errors on the QUIT */
4191 if(ftpc->entrypath) {
4192 struct SessionHandle *data = conn->data;
4193 if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
4194 data->state.most_recent_ftp_entrypath = NULL;
4196 free(ftpc->entrypath);
4197 ftpc->entrypath = NULL;
4201 free(ftpc->prevpath);
4202 ftpc->prevpath = NULL;
4203 free(ftpc->server_os);
4204 ftpc->server_os = NULL;
4206 Curl_pp_disconnect(pp);
4215 /***********************************************************************
4217 * ftp_parse_url_path()
4219 * Parse the URL path into separate path components.
4223 CURLcode ftp_parse_url_path(struct connectdata *conn)
4225 struct SessionHandle *data = conn->data;
4226 /* the ftp struct is already inited in ftp_connect() */
4227 struct FTP *ftp = data->req.protop;
4228 struct ftp_conn *ftpc = &conn->proto.ftpc;
4229 const char *slash_pos; /* position of the first '/' char in curpos */
4230 const char *path_to_use = data->state.path;
4231 const char *cur_pos;
4232 const char *filename = NULL;
4234 cur_pos = path_to_use; /* current position in path. point at the begin
4235 of next path component */
4237 ftpc->ctl_valid = FALSE;
4238 ftpc->cwdfail = FALSE;
4240 switch(data->set.ftp_filemethod) {
4242 /* fastest, but less standard-compliant */
4245 The best time to check whether the path is a file or directory is right
4248 the first condition in the if() right here, is there just in case
4249 someone decides to set path to NULL one day
4251 if(data->state.path &&
4252 data->state.path[0] &&
4253 (data->state.path[strlen(data->state.path) - 1] != '/') )
4254 filename = data->state.path; /* this is a full file path */
4256 ftpc->file is not used anywhere other than for operations on a file.
4257 In other words, never for directory operations.
4258 So we can safely leave filename as NULL here and use it as a
4259 argument in dir/file decisions.
4263 case FTPFILE_SINGLECWD:
4264 /* get the last slash */
4265 if(!path_to_use[0]) {
4266 /* no dir, no file */
4270 slash_pos=strrchr(cur_pos, '/');
4271 if(slash_pos || !*cur_pos) {
4272 size_t dirlen = slash_pos-cur_pos;
4274 ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
4276 return CURLE_OUT_OF_MEMORY;
4281 ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
4282 slash_pos ? curlx_uztosi(dirlen) : 1,
4284 if(!ftpc->dirs[0]) {
4286 return CURLE_OUT_OF_MEMORY;
4288 ftpc->dirdepth = 1; /* we consider it to be a single dir */
4289 filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
4292 filename = cur_pos; /* this is a file name only */
4295 default: /* allow pretty much anything */
4296 case FTPFILE_MULTICWD:
4298 ftpc->diralloc = 5; /* default dir depth to allocate */
4299 ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
4301 return CURLE_OUT_OF_MEMORY;
4303 /* we have a special case for listing the root dir only */
4304 if(strequal(path_to_use, "/")) {
4305 cur_pos++; /* make it point to the zero byte */
4306 ftpc->dirs[0] = strdup("/");
4310 /* parse the URL path into separate path components */
4311 while((slash_pos = strchr(cur_pos, '/')) != NULL) {
4312 /* 1 or 0 pointer offset to indicate absolute directory */
4313 ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
4314 (ftpc->dirdepth == 0))?1:0;
4316 /* seek out the next path component */
4317 if(slash_pos-cur_pos) {
4318 /* we skip empty path components, like "x//y" since the FTP command
4319 CWD requires a parameter and a non-existent parameter a) doesn't
4320 work on many servers and b) has no effect on the others. */
4321 int len = curlx_sztosi(slash_pos - cur_pos + absolute_dir);
4322 ftpc->dirs[ftpc->dirdepth] =
4323 curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);
4324 if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
4325 failf(data, "no memory");
4327 return CURLE_OUT_OF_MEMORY;
4329 if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
4330 free(ftpc->dirs[ftpc->dirdepth]);
4332 return CURLE_URL_MALFORMAT;
4336 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4337 if(!ftpc->dirdepth) {
4338 /* path starts with a slash, add that as a directory */
4339 ftpc->dirs[ftpc->dirdepth] = strdup("/");
4340 if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */
4341 failf(data, "no memory");
4343 return CURLE_OUT_OF_MEMORY;
4349 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4350 if(++ftpc->dirdepth >= ftpc->diralloc) {
4353 ftpc->diralloc *= 2; /* double the size each time */
4354 bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
4357 return CURLE_OUT_OF_MEMORY;
4359 ftpc->dirs = bigger;
4363 filename = cur_pos; /* the rest is the file name */
4367 if(filename && *filename) {
4368 ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
4369 if(NULL == ftpc->file) {
4371 failf(data, "no memory");
4372 return CURLE_OUT_OF_MEMORY;
4374 if(isBadFtpString(ftpc->file)) {
4376 return CURLE_URL_MALFORMAT;
4380 ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
4383 if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
4384 /* We need a file name when uploading. Return error! */
4385 failf(data, "Uploading to a URL without a file name!");
4386 return CURLE_URL_MALFORMAT;
4389 ftpc->cwddone = FALSE; /* default to not done */
4391 if(ftpc->prevpath) {
4392 /* prevpath is "raw" so we convert the input path before we compare the
4395 char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
4398 return CURLE_OUT_OF_MEMORY;
4401 dlen -= ftpc->file?curlx_uztosi(strlen(ftpc->file)):0;
4402 if((dlen == curlx_uztosi(strlen(ftpc->prevpath))) &&
4403 strnequal(path, ftpc->prevpath, dlen)) {
4404 infof(data, "Request has same path as previous transfer\n");
4405 ftpc->cwddone = TRUE;
4413 /* call this when the DO phase has completed */
4414 static CURLcode ftp_dophase_done(struct connectdata *conn,
4417 struct FTP *ftp = conn->data->req.protop;
4418 struct ftp_conn *ftpc = &conn->proto.ftpc;
4422 CURLcode result = ftp_do_more(conn, &completed);
4425 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
4426 /* close the second socket if it was created already */
4427 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
4428 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
4434 if(ftp->transfer != FTPTRANSFER_BODY)
4435 /* no data to transfer */
4436 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
4438 /* since we didn't connect now, we want do_more to get called */
4439 conn->bits.do_more = TRUE;
4441 ftpc->ctl_valid = TRUE; /* seems good */
4446 /* called from multi.c while DOing */
4447 static CURLcode ftp_doing(struct connectdata *conn,
4450 CURLcode result = ftp_multi_statemach(conn, dophase_done);
4453 DEBUGF(infof(conn->data, "DO phase failed\n"));
4454 else if(*dophase_done) {
4455 result = ftp_dophase_done(conn, FALSE /* not connected */);
4457 DEBUGF(infof(conn->data, "DO phase is complete2\n"));
4462 /***********************************************************************
4464 * ftp_regular_transfer()
4466 * The input argument is already checked for validity.
4468 * Performs all commands done before a regular transfer between a local and a
4471 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
4472 * ftp_done() function without finding any major problem.
4475 CURLcode ftp_regular_transfer(struct connectdata *conn,
4478 CURLcode result=CURLE_OK;
4479 bool connected=FALSE;
4480 struct SessionHandle *data = conn->data;
4481 struct ftp_conn *ftpc = &conn->proto.ftpc;
4482 data->req.size = -1; /* make sure this is unknown at this point */
4484 Curl_pgrsSetUploadCounter(data, 0);
4485 Curl_pgrsSetDownloadCounter(data, 0);
4486 Curl_pgrsSetUploadSize(data, -1);
4487 Curl_pgrsSetDownloadSize(data, -1);
4489 ftpc->ctl_valid = TRUE; /* starts good */
4491 result = ftp_perform(conn,
4492 &connected, /* have we connected after PASV/PORT */
4493 dophase_done); /* all commands in the DO-phase done? */
4498 /* the DO phase has not completed yet */
4501 result = ftp_dophase_done(conn, connected);
4512 static CURLcode ftp_setup_connection(struct connectdata *conn)
4514 struct SessionHandle *data = conn->data;
4519 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
4520 /* Unless we have asked to tunnel ftp operations through the proxy, we
4521 switch and use HTTP operations only */
4522 #ifndef CURL_DISABLE_HTTP
4523 if(conn->handler == &Curl_handler_ftp)
4524 conn->handler = &Curl_handler_ftp_proxy;
4527 conn->handler = &Curl_handler_ftps_proxy;
4529 failf(data, "FTPS not supported!");
4530 return CURLE_UNSUPPORTED_PROTOCOL;
4533 /* set it up as a HTTP connection instead */
4534 return conn->handler->setup_connection(conn);
4536 failf(data, "FTP over http proxy requires HTTP support built-in!");
4537 return CURLE_UNSUPPORTED_PROTOCOL;
4541 conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
4543 return CURLE_OUT_OF_MEMORY;
4545 data->state.path++; /* don't include the initial slash */
4546 data->state.slash_removed = TRUE; /* we've skipped the slash */
4548 /* FTP URLs support an extension like ";type=<typecode>" that
4549 * we'll try to get now! */
4550 type = strstr(data->state.path, ";type=");
4553 type = strstr(conn->host.rawalloc, ";type=");
4556 *type = 0; /* it was in the middle of the hostname */
4557 command = Curl_raw_toupper(type[6]);
4558 conn->bits.type_set = TRUE;
4561 case 'A': /* ASCII mode */
4562 data->set.prefer_ascii = TRUE;
4565 case 'D': /* directory mode */
4566 data->set.ftp_list_only = TRUE;
4569 case 'I': /* binary mode */
4571 /* switch off ASCII */
4572 data->set.prefer_ascii = FALSE;
4577 /* get some initial data into the ftp struct */
4578 ftp->bytecountp = &conn->data->req.bytecount;
4579 ftp->transfer = FTPTRANSFER_BODY;
4580 ftp->downloadsize = 0;
4582 /* No need to duplicate user+password, the connectdata struct won't change
4583 during a session, but we re-init them here since on subsequent inits
4584 since the conn struct may have changed or been replaced.
4586 ftp->user = conn->user;
4587 ftp->passwd = conn->passwd;
4588 if(isBadFtpString(ftp->user))
4589 return CURLE_URL_MALFORMAT;
4590 if(isBadFtpString(ftp->passwd))
4591 return CURLE_URL_MALFORMAT;
4593 conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
4598 #endif /* CURL_DISABLE_FTP */