1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2020, 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 https://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 */
60 #include "ftplistparser.h"
61 #include "curl_range.h"
62 #include "curl_krb5.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"
81 /* The last 3 #include files should be in this order */
82 #include "curl_printf.h"
83 #include "curl_memory.h"
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,
116 struct Curl_addrinfo *ai,
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);
136 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks);
137 static CURLcode ftp_doing(struct connectdata *conn,
139 static CURLcode ftp_setup_connection(struct connectdata *conn);
140 static CURLcode init_wc_data(struct connectdata *conn);
141 static CURLcode wc_statemach(struct connectdata *conn);
142 static void wc_data_dtor(void *ptr);
143 static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize);
144 static CURLcode ftp_readresp(curl_socket_t sockfd,
148 static CURLcode ftp_dophase_done(struct connectdata *conn,
152 * FTP protocol handler.
155 const struct Curl_handler Curl_handler_ftp = {
157 ftp_setup_connection, /* setup_connection */
160 ftp_do_more, /* do_more */
161 ftp_connect, /* connect_it */
162 ftp_multi_statemach, /* connecting */
163 ftp_doing, /* doing */
164 ftp_getsock, /* proto_getsock */
165 ftp_getsock, /* doing_getsock */
166 ftp_domore_getsock, /* domore_getsock */
167 ZERO_NULL, /* perform_getsock */
168 ftp_disconnect, /* disconnect */
169 ZERO_NULL, /* readwrite */
170 ZERO_NULL, /* connection_check */
171 PORT_FTP, /* defport */
172 CURLPROTO_FTP, /* protocol */
173 CURLPROTO_FTP, /* family */
174 PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD |
175 PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP |
176 PROTOPT_WILDCARD /* flags */
182 * FTPS protocol handler.
185 const struct Curl_handler Curl_handler_ftps = {
187 ftp_setup_connection, /* setup_connection */
190 ftp_do_more, /* do_more */
191 ftp_connect, /* connect_it */
192 ftp_multi_statemach, /* connecting */
193 ftp_doing, /* doing */
194 ftp_getsock, /* proto_getsock */
195 ftp_getsock, /* doing_getsock */
196 ftp_domore_getsock, /* domore_getsock */
197 ZERO_NULL, /* perform_getsock */
198 ftp_disconnect, /* disconnect */
199 ZERO_NULL, /* readwrite */
200 ZERO_NULL, /* connection_check */
201 PORT_FTPS, /* defport */
202 CURLPROTO_FTPS, /* protocol */
203 CURLPROTO_FTP, /* family */
204 PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
205 PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_WILDCARD /* flags */
209 static void close_secondarysocket(struct connectdata *conn)
211 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
212 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
213 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
215 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
216 #ifndef CURL_DISABLE_PROXY
217 conn->bits.proxy_ssl_connected[SECONDARYSOCKET] = FALSE;
222 * NOTE: back in the old days, we added code in the FTP code that made NOBODY
223 * requests on files respond with headers passed to the client/stdout that
224 * looked like HTTP ones.
226 * This approach is not very elegant, it causes confusion and is error-prone.
227 * It is subject for removal at the next (or at least a future) soname bump.
228 * Until then you can test the effects of the removal by undefining the
229 * following define named CURL_FTP_HTTPSTYLE_HEAD.
231 #define CURL_FTP_HTTPSTYLE_HEAD 1
233 static void freedirs(struct ftp_conn *ftpc)
237 for(i = 0; i < ftpc->dirdepth; i++) {
239 ftpc->dirs[i] = NULL;
245 Curl_safefree(ftpc->file);
247 /* no longer of any use */
248 Curl_safefree(ftpc->newhost);
251 /***********************************************************************
253 * AcceptServerConnect()
255 * After connection request is received from the server this function is
256 * called to accept the connection and close the listening socket
259 static CURLcode AcceptServerConnect(struct connectdata *conn)
261 struct Curl_easy *data = conn->data;
262 curl_socket_t sock = conn->sock[SECONDARYSOCKET];
263 curl_socket_t s = CURL_SOCKET_BAD;
265 struct Curl_sockaddr_storage add;
267 struct sockaddr_in add;
269 curl_socklen_t size = (curl_socklen_t) sizeof(add);
271 if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
274 s = accept(sock, (struct sockaddr *) &add, &size);
276 Curl_closesocket(conn, sock); /* close the first socket */
278 if(CURL_SOCKET_BAD == s) {
279 failf(data, "Error accept()ing server connect");
280 return CURLE_FTP_PORT_FAILED;
282 infof(data, "Connection accepted from server\n");
283 /* when this happens within the DO state it is important that we mark us as
284 not needing DO_MORE anymore */
285 conn->bits.do_more = FALSE;
287 conn->sock[SECONDARYSOCKET] = s;
288 (void)curlx_nonblock(s, TRUE); /* enable non-blocking */
289 conn->bits.sock_accepted = TRUE;
291 if(data->set.fsockopt) {
294 /* activate callback for setting socket options */
295 Curl_set_in_callback(data, true);
296 error = data->set.fsockopt(data->set.sockopt_client,
298 CURLSOCKTYPE_ACCEPT);
299 Curl_set_in_callback(data, false);
302 close_secondarysocket(conn);
303 return CURLE_ABORTED_BY_CALLBACK;
312 * ftp_timeleft_accept() returns the amount of milliseconds left allowed for
313 * waiting server to connect. If the value is negative, the timeout time has
316 * The start time is stored in progress.t_acceptdata - as set with
317 * Curl_pgrsTime(..., TIMER_STARTACCEPT);
320 static timediff_t ftp_timeleft_accept(struct Curl_easy *data)
322 timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
326 if(data->set.accepttimeout > 0)
327 timeout_ms = data->set.accepttimeout;
331 /* check if the generic timeout possibly is set shorter */
332 other = Curl_timeleft(data, &now, FALSE);
333 if(other && (other < timeout_ms))
334 /* note that this also works fine for when other happens to be negative
335 due to it already having elapsed */
338 /* subtract elapsed time */
339 timeout_ms -= Curl_timediff(now, data->progress.t_acceptdata);
341 /* avoid returning 0 as that means no timeout! */
349 /***********************************************************************
351 * ReceivedServerConnect()
353 * After allowing server to connect to us from data port, this function
354 * checks both data connection for connection establishment and ctrl
355 * connection for a negative response regarding a failure in connecting
358 static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
360 struct Curl_easy *data = conn->data;
361 curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
362 curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
363 struct ftp_conn *ftpc = &conn->proto.ftpc;
364 struct pingpong *pp = &ftpc->pp;
366 timediff_t timeout_ms;
372 timeout_ms = ftp_timeleft_accept(data);
373 infof(data, "Checking for server connect\n");
375 /* if a timeout was already reached, bail out */
376 failf(data, "Accept timeout occurred while waiting server connect");
377 return CURLE_FTP_ACCEPT_TIMEOUT;
380 /* First check whether there is a cached response from server */
381 if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
382 /* Data connection could not be established, let's return */
383 infof(data, "There is negative response in cache while serv connect\n");
384 (void)Curl_GetFTPResponse(&nread, conn, &ftpcode);
385 return CURLE_FTP_ACCEPT_FAILED;
388 result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
390 /* see if the connection request is already here */
394 failf(data, "Error while waiting for server connect");
395 return CURLE_FTP_ACCEPT_FAILED;
396 case 0: /* Server connect is not received yet */
400 if(result & CURL_CSELECT_IN2) {
401 infof(data, "Ready to accept data connection from server\n");
404 else if(result & CURL_CSELECT_IN) {
405 infof(data, "Ctrl conn has data while waiting for data conn\n");
406 (void)Curl_GetFTPResponse(&nread, conn, &ftpcode);
409 return CURLE_FTP_ACCEPT_FAILED;
411 return CURLE_WEIRD_SERVER_REPLY;
421 /***********************************************************************
425 * After connection from server is accepted this function is called to
426 * setup transfer parameters and initiate the data transfer.
429 static CURLcode InitiateTransfer(struct connectdata *conn)
431 struct Curl_easy *data = conn->data;
432 CURLcode result = CURLE_OK;
434 if(conn->bits.ftp_use_data_ssl) {
435 /* since we only have a plaintext TCP connection here, we must now
436 * do the TLS stuff */
437 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
438 result = Curl_ssl_connect(conn, SECONDARYSOCKET);
443 if(conn->proto.ftpc.state_saved == FTP_STOR) {
444 /* When we know we're uploading a specified file, we can get the file
445 size prior to the actual upload. */
446 Curl_pgrsSetUploadSize(data, data->state.infilesize);
448 /* set the SO_SNDBUF for the secondary socket for those who need it */
449 Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
451 Curl_setup_transfer(data, -1, -1, FALSE, SECONDARYSOCKET);
455 Curl_setup_transfer(data, SECONDARYSOCKET,
456 conn->proto.ftpc.retr_size_saved, FALSE, -1);
459 conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
460 state(conn, FTP_STOP);
465 /***********************************************************************
467 * AllowServerConnect()
469 * When we've issue the PORT command, we have told the server to connect to
470 * us. This function checks whether data connection is established if so it is
474 static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
476 struct Curl_easy *data = conn->data;
477 timediff_t timeout_ms;
478 CURLcode result = CURLE_OK;
481 infof(data, "Preparing for accepting server on data port\n");
483 /* Save the time we start accepting server connect */
484 Curl_pgrsTime(data, TIMER_STARTACCEPT);
486 timeout_ms = ftp_timeleft_accept(data);
488 /* if a timeout was already reached, bail out */
489 failf(data, "Accept timeout occurred while waiting server connect");
490 return CURLE_FTP_ACCEPT_TIMEOUT;
493 /* see if the connection request is already here */
494 result = ReceivedServerConnect(conn, connected);
499 result = AcceptServerConnect(conn);
503 result = InitiateTransfer(conn);
508 /* Add timeout to multi handle and break out of the loop */
509 if(*connected == FALSE) {
510 Curl_expire(data, data->set.accepttimeout > 0 ?
511 data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, 0);
518 /* macro to check for a three-digit ftp status code at the start of the
520 #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
523 /* macro to check for the last line in an FTP server response */
524 #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
526 static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len,
531 if((len > 3) && LASTLINE(line)) {
532 *code = curlx_sltosi(strtol(line, NULL, 10));
539 static CURLcode ftp_readresp(curl_socket_t sockfd,
541 int *ftpcode, /* return the ftp-code if done */
542 size_t *size) /* size of the response */
544 struct connectdata *conn = pp->conn;
545 struct Curl_easy *data = conn->data;
547 char * const buf = data->state.buffer;
550 CURLcode result = Curl_pp_readresp(sockfd, pp, &code, size);
552 #if defined(HAVE_GSSAPI)
553 /* handle the security-oriented responses 6xx ***/
556 code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
559 code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
562 code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
565 /* normal ftp stuff we pass through! */
570 /* store the latest code for later retrieval */
571 data->info.httpcode = code;
577 /* 421 means "Service not available, closing control connection." and FTP
578 * servers use it to signal that idle session timeout has been exceeded.
579 * If we ignored the response, it could end up hanging in some cases.
581 * This response code can come at any point so having it treated
582 * generically is a good idea.
584 infof(data, "We got a 421 - timeout!\n");
585 state(conn, FTP_STOP);
586 return CURLE_OPERATION_TIMEDOUT;
592 /* --- parse FTP server responses --- */
595 * Curl_GetFTPResponse() is a BLOCKING function to read the full response
596 * from a server after a command.
600 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
601 struct connectdata *conn,
602 int *ftpcode) /* return the ftp-code */
605 * We cannot read just one byte per read() and then go back to select() as
606 * the OpenSSL read() doesn't grok that properly.
608 * Alas, read as much as possible, split up into lines, use the ending
609 * line in a response or continue reading. */
611 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
612 struct Curl_easy *data = conn->data;
613 CURLcode result = CURLE_OK;
614 struct ftp_conn *ftpc = &conn->proto.ftpc;
615 struct pingpong *pp = &ftpc->pp;
618 int value_to_be_ignored = 0;
621 *ftpcode = 0; /* 0 for errors */
623 /* make the pointer point to something for the rest of this function */
624 ftpcode = &value_to_be_ignored;
628 while(!*ftpcode && !result) {
629 /* check and reset timeout value every lap */
630 timediff_t timeout = Curl_pp_state_timeout(pp, FALSE);
631 timediff_t interval_ms;
634 failf(data, "FTP response timeout");
635 return CURLE_OPERATION_TIMEDOUT; /* already too little time */
638 interval_ms = 1000; /* use 1 second timeout intervals */
639 if(timeout < interval_ms)
640 interval_ms = timeout;
643 * Since this function is blocking, we need to wait here for input on the
644 * connection and only then we call the response reading function. We do
645 * timeout at least every second to make the timeout check run.
647 * A caution here is that the ftp_readresp() function has a cache that may
648 * contain pieces of a response from the previous invoke and we need to
649 * make sure we don't just wait for input while there is unhandled data in
650 * that cache. But also, if the cache is there, we call ftp_readresp() and
651 * the cache wasn't good enough to continue we must not just busy-loop
652 * around this function.
656 if(pp->cache && (cache_skip < 2)) {
658 * There's a cache left since before. We then skipping the wait for
659 * socket action, unless this is the same cache like the previous round
660 * as then the cache was deemed not enough to act on and we then need to
661 * wait for more data anyway.
664 else if(!Curl_conn_data_pending(conn, FIRSTSOCKET)) {
665 switch(SOCKET_READABLE(sockfd, interval_ms)) {
666 case -1: /* select() error, stop reading */
667 failf(data, "FTP response aborted due to select/poll error: %d",
669 return CURLE_RECV_ERROR;
671 case 0: /* timeout */
672 if(Curl_pgrsUpdate(conn))
673 return CURLE_ABORTED_BY_CALLBACK;
674 continue; /* just continue in our loop for the timeout duration */
676 default: /* for clarity */
680 result = ftp_readresp(sockfd, pp, ftpcode, &nread);
684 if(!nread && pp->cache)
685 /* bump cache skip counter as on repeated skips we must wait for more
689 /* when we got data or there is no cache left, we reset the cache skip
695 } /* while there's buffer left and loop is requested */
697 pp->pending_resp = FALSE;
702 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
703 /* for debug purposes */
704 static const char * const ftp_state_names[]={
743 /* This is the ONLY way to change FTP state! */
744 static void _state(struct connectdata *conn,
751 struct ftp_conn *ftpc = &conn->proto.ftpc;
753 #if defined(DEBUGBUILD)
755 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
758 if(ftpc->state != newstate)
759 infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
760 (void *)ftpc, lineno, ftp_state_names[ftpc->state],
761 ftp_state_names[newstate]);
765 ftpc->state = newstate;
768 static CURLcode ftp_state_user(struct connectdata *conn)
770 CURLcode result = Curl_pp_sendf(&conn->proto.ftpc.pp, "USER %s",
771 conn->user?conn->user:"");
773 state(conn, FTP_USER);
774 conn->data->state.ftp_trying_alternative = FALSE;
779 static CURLcode ftp_state_pwd(struct connectdata *conn)
781 CURLcode result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "PWD");
783 state(conn, FTP_PWD);
788 /* For the FTP "protocol connect" and "doing" phases only */
789 static int ftp_getsock(struct connectdata *conn,
790 curl_socket_t *socks)
792 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks);
795 /* For the FTP "DO_MORE" phase only */
796 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks)
798 struct ftp_conn *ftpc = &conn->proto.ftpc;
800 /* When in DO_MORE state, we could be either waiting for us to connect to a
801 * remote site, or we could wait for that site to connect to us. Or just
802 * handle ordinary commands.
805 if(SOCKS_STATE(conn->cnnct.state))
806 return Curl_SOCKS_getsock(conn, socks, SECONDARYSOCKET);
808 if(FTP_STOP == ftpc->state) {
809 int bits = GETSOCK_READSOCK(0);
812 /* if stopped and still in this state, then we're also waiting for a
813 connect on the secondary connection */
814 socks[0] = conn->sock[FIRSTSOCKET];
816 if(!conn->data->set.ftp_use_port) {
819 /* PORT is used to tell the server to connect to us, and during that we
820 don't do happy eyeballs, but we do if we connect to the server */
821 for(s = 1, i = 0; i<2; i++) {
822 if(conn->tempsock[i] != CURL_SOCKET_BAD) {
823 socks[s] = conn->tempsock[i];
824 bits |= GETSOCK_WRITESOCK(s++);
830 socks[1] = conn->sock[SECONDARYSOCKET];
831 bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1);
836 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks);
839 /* This is called after the FTP_QUOTE state is passed.
841 ftp_state_cwd() sends the range of CWD commands to the server to change to
842 the correct directory. It may also need to send MKD commands to create
843 missing ones, if that option is enabled.
845 static CURLcode ftp_state_cwd(struct connectdata *conn)
847 CURLcode result = CURLE_OK;
848 struct ftp_conn *ftpc = &conn->proto.ftpc;
851 /* already done and fine */
852 result = ftp_state_mdtm(conn);
854 /* FTPFILE_NOCWD with full path: expect ftpc->cwddone! */
855 DEBUGASSERT((conn->data->set.ftp_filemethod != FTPFILE_NOCWD) ||
856 !(ftpc->dirdepth && ftpc->dirs[0][0] == '/'));
858 ftpc->count2 = 0; /* count2 counts failed CWDs */
860 /* count3 is set to allow a MKD to fail once. In the case when first CWD
861 fails and then MKD fails (due to another session raced it to create the
862 dir) this then allows for a second try to CWD to it */
863 ftpc->count3 = (conn->data->set.ftp_create_missing_dirs == 2)?1:0;
865 if(conn->bits.reuse && ftpc->entrypath &&
866 /* no need to go to entrypath when we have an absolute path */
867 !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')) {
868 /* This is a re-used connection. Since we change directory to where the
869 transfer is taking place, we must first get back to the original dir
870 where we ended up after login: */
871 ftpc->cwdcount = 0; /* we count this as the first path, then we add one
872 for all upcoming ones in the ftp->dirs[] array */
873 result = Curl_pp_sendf(&ftpc->pp, "CWD %s", ftpc->entrypath);
875 state(conn, FTP_CWD);
880 /* issue the first CWD, the rest is sent when the CWD responses are
882 result = Curl_pp_sendf(&ftpc->pp, "CWD %s",
883 ftpc->dirs[ftpc->cwdcount -1]);
885 state(conn, FTP_CWD);
888 /* No CWD necessary */
889 result = ftp_state_mdtm(conn);
902 static CURLcode ftp_state_use_port(struct connectdata *conn,
903 ftpport fcmd) /* start with this */
906 CURLcode result = CURLE_OK;
907 struct ftp_conn *ftpc = &conn->proto.ftpc;
908 struct Curl_easy *data = conn->data;
909 curl_socket_t portsock = CURL_SOCKET_BAD;
910 char myhost[MAX_IPADR_LEN + 1] = "";
912 struct Curl_sockaddr_storage ss;
913 struct Curl_addrinfo *res, *ai;
914 curl_socklen_t sslen;
915 char hbuf[NI_MAXHOST];
916 struct sockaddr *sa = (struct sockaddr *)&ss;
917 struct sockaddr_in * const sa4 = (void *)sa;
919 struct sockaddr_in6 * const sa6 = (void *)sa;
921 static const char mode[][5] = { "EPRT", "PORT" };
925 char *string_ftpport = data->set.str[STRING_FTPPORT];
926 struct Curl_dns_entry *h = NULL;
927 unsigned short port_min = 0;
928 unsigned short port_max = 0;
930 bool possibly_non_local = TRUE;
931 char buffer[STRERROR_LEN];
934 /* Step 1, figure out what is requested,
936 * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
939 if(data->set.str[STRING_FTPPORT] &&
940 (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
943 size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
944 INET6_ADDRSTRLEN : strlen(string_ftpport);
946 size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
947 INET_ADDRSTRLEN : strlen(string_ftpport);
949 char *ip_start = string_ftpport;
951 char *port_start = NULL;
952 char *port_sep = NULL;
954 addr = calloc(addrlen + 1, 1);
956 return CURLE_OUT_OF_MEMORY;
959 if(*string_ftpport == '[') {
960 /* [ipv6]:port(-range) */
961 ip_start = string_ftpport + 1;
962 ip_end = strchr(string_ftpport, ']');
964 strncpy(addr, ip_start, ip_end - ip_start);
968 if(*string_ftpport == ':') {
970 ip_end = string_ftpport;
973 ip_end = strchr(string_ftpport, ':');
975 /* either ipv6 or (ipv4|domain|interface):port(-range) */
977 if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
979 port_min = port_max = 0;
980 strcpy(addr, string_ftpport);
981 ip_end = NULL; /* this got no port ! */
985 /* (ipv4|domain|interface):port(-range) */
986 strncpy(addr, string_ftpport, ip_end - ip_start);
990 strcpy(addr, string_ftpport);
995 port_start = strchr(ip_end, ':');
997 port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10));
998 port_sep = strchr(port_start, '-');
1000 port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
1003 port_max = port_min;
1007 /* correct errors like:
1009 * :-4711, in this case port_min is (unsigned)-1,
1010 * therefore port_min > port_max for all cases
1011 * but port_max = (unsigned)-1
1013 if(port_min > port_max)
1014 port_min = port_max = 0;
1018 /* attempt to get the address of the given interface name */
1019 switch(Curl_if2ip(conn->ip_addr->ai_family,
1020 Curl_ipv6_scope(conn->ip_addr->ai_addr),
1021 conn->scope_id, addr, hbuf, sizeof(hbuf))) {
1022 case IF2IP_NOT_FOUND:
1023 /* not an interface, use the given string as host name instead */
1026 case IF2IP_AF_NOT_SUPPORTED:
1027 return CURLE_FTP_PORT_FAILED;
1029 host = hbuf; /* use the hbuf for host name */
1033 /* there was only a port(-range) given, default the host */
1035 } /* data->set.ftpport */
1039 /* not an interface and not a host name, get default by extracting
1040 the IP from the control connection */
1042 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1043 failf(data, "getsockname() failed: %s",
1044 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1046 return CURLE_FTP_PORT_FAILED;
1048 switch(sa->sa_family) {
1051 r = Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
1055 r = Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
1059 return CURLE_FTP_PORT_FAILED;
1060 host = hbuf; /* use this host name */
1061 possibly_non_local = FALSE; /* we know it is local now */
1064 /* resolv ip/host to ip */
1065 rc = Curl_resolv(conn, host, 0, FALSE, &h);
1066 if(rc == CURLRESOLV_PENDING)
1067 (void)Curl_resolver_wait_resolv(conn, &h);
1070 /* when we return from this function, we can forget about this entry
1071 to we can unlock it now already */
1072 Curl_resolv_unlock(data, h);
1075 res = NULL; /* failure! */
1078 failf(data, "failed to resolve the address provided to PORT: %s", host);
1080 return CURLE_FTP_PORT_FAILED;
1086 /* step 2, create a socket for the requested address */
1088 portsock = CURL_SOCKET_BAD;
1090 for(ai = res; ai; ai = ai->ai_next) {
1091 result = Curl_socket(conn, ai, NULL, &portsock);
1099 failf(data, "socket failure: %s",
1100 Curl_strerror(error, buffer, sizeof(buffer)));
1101 return CURLE_FTP_PORT_FAILED;
1104 /* step 3, bind to a suitable local address */
1106 memcpy(sa, ai->ai_addr, ai->ai_addrlen);
1107 sslen = ai->ai_addrlen;
1109 for(port = port_min; port <= port_max;) {
1110 if(sa->sa_family == AF_INET)
1111 sa4->sin_port = htons(port);
1114 sa6->sin6_port = htons(port);
1116 /* Try binding the given address. */
1117 if(bind(portsock, sa, sslen) ) {
1120 if(possibly_non_local && (error == EADDRNOTAVAIL)) {
1121 /* The requested bind address is not local. Use the address used for
1122 * the control connection instead and restart the port loop
1124 infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
1125 Curl_strerror(error, buffer, sizeof(buffer)));
1128 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1129 failf(data, "getsockname() failed: %s",
1130 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1131 Curl_closesocket(conn, portsock);
1132 return CURLE_FTP_PORT_FAILED;
1135 possibly_non_local = FALSE; /* don't try this again */
1138 if(error != EADDRINUSE && error != EACCES) {
1139 failf(data, "bind(port=%hu) failed: %s", port,
1140 Curl_strerror(error, buffer, sizeof(buffer)));
1141 Curl_closesocket(conn, portsock);
1142 return CURLE_FTP_PORT_FAILED;
1151 /* maybe all ports were in use already*/
1152 if(port > port_max) {
1153 failf(data, "bind() failed, we ran out of ports!");
1154 Curl_closesocket(conn, portsock);
1155 return CURLE_FTP_PORT_FAILED;
1158 /* get the name again after the bind() so that we can extract the
1159 port number it uses now */
1161 if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
1162 failf(data, "getsockname() failed: %s",
1163 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1164 Curl_closesocket(conn, portsock);
1165 return CURLE_FTP_PORT_FAILED;
1168 /* step 4, listen on the socket */
1170 if(listen(portsock, 1)) {
1171 failf(data, "socket failure: %s",
1172 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1173 Curl_closesocket(conn, portsock);
1174 return CURLE_FTP_PORT_FAILED;
1177 /* step 5, send the proper FTP command */
1179 /* get a plain printable version of the numerical address to work with
1181 Curl_printable_address(ai, myhost, sizeof(myhost));
1184 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
1185 /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
1186 request and enable EPRT again! */
1187 conn->bits.ftp_use_eprt = TRUE;
1190 for(; fcmd != DONE; fcmd++) {
1192 if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
1193 /* if disabled, goto next */
1196 if((PORT == fcmd) && sa->sa_family != AF_INET)
1197 /* PORT is IPv4 only */
1200 switch(sa->sa_family) {
1202 port = ntohs(sa4->sin_port);
1206 port = ntohs(sa6->sin6_port);
1210 continue; /* might as well skip this */
1215 * Two fine examples from RFC2428;
1217 * EPRT |1|132.235.1.2|6275|
1219 * EPRT |2|1080::8:800:200C:417A|5282|
1222 result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
1223 sa->sa_family == AF_INET?1:2,
1226 failf(data, "Failure sending EPRT command: %s",
1227 curl_easy_strerror(result));
1228 Curl_closesocket(conn, portsock);
1229 /* don't retry using PORT */
1230 ftpc->count1 = PORT;
1232 state(conn, FTP_STOP);
1238 /* large enough for [IP address],[num],[num] */
1239 char target[sizeof(myhost) + 20];
1240 char *source = myhost;
1241 char *dest = target;
1243 /* translate x.x.x.x to x,x,x,x */
1244 while(source && *source) {
1253 msnprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
1255 result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], target);
1257 failf(data, "Failure sending PORT command: %s",
1258 curl_easy_strerror(result));
1259 Curl_closesocket(conn, portsock);
1261 state(conn, FTP_STOP);
1268 /* store which command was sent */
1269 ftpc->count1 = fcmd;
1271 close_secondarysocket(conn);
1273 /* we set the secondary socket variable to this for now, it is only so that
1274 the cleanup function will close it in case we fail before the true
1275 secondary stuff is made */
1276 conn->sock[SECONDARYSOCKET] = portsock;
1278 /* this tcpconnect assignment below is a hackish work-around to make the
1279 multi interface with active FTP work - as it will not wait for a
1280 (passive) connect in Curl_is_connected().
1282 The *proper* fix is to make sure that the active connection from the
1283 server is done in a non-blocking way. Currently, it is still BLOCKING.
1285 conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
1287 state(conn, FTP_PORT);
1291 static CURLcode ftp_state_use_pasv(struct connectdata *conn)
1293 struct ftp_conn *ftpc = &conn->proto.ftpc;
1294 CURLcode result = CURLE_OK;
1296 Here's the executive summary on what to do:
1298 PASV is RFC959, expect:
1299 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1301 LPSV is RFC1639, expect:
1302 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1304 EPSV is RFC2428, expect:
1305 229 Entering Extended Passive Mode (|||port|)
1309 static const char mode[][5] = { "EPSV", "PASV" };
1313 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
1314 /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1315 request and enable EPSV again! */
1316 conn->bits.ftp_use_epsv = TRUE;
1319 modeoff = conn->bits.ftp_use_epsv?0:1;
1321 result = Curl_pp_sendf(&ftpc->pp, "%s", mode[modeoff]);
1323 ftpc->count1 = modeoff;
1324 state(conn, FTP_PASV);
1325 infof(conn->data, "Connect data stream passively\n");
1331 * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc.
1333 * REST is the last command in the chain of commands when a "head"-like
1334 * request is made. Thus, if an actual transfer is to be made this is where we
1335 * take off for real.
1337 static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
1339 CURLcode result = CURLE_OK;
1340 struct FTP *ftp = conn->data->req.protop;
1341 struct Curl_easy *data = conn->data;
1343 if(ftp->transfer != FTPTRANSFER_BODY) {
1344 /* doesn't transfer any data */
1346 /* still possibly do PRE QUOTE jobs */
1347 state(conn, FTP_RETR_PREQUOTE);
1348 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1350 else if(data->set.ftp_use_port) {
1351 /* We have chosen to use the PORT (or similar) command */
1352 result = ftp_state_use_port(conn, EPRT);
1355 /* We have chosen (this is default) to use the PASV (or similar) command */
1356 if(data->set.ftp_use_pret) {
1357 /* The user has requested that we send a PRET command
1358 to prepare the server for the upcoming PASV */
1359 struct ftp_conn *ftpc = &conn->proto.ftpc;
1360 if(!conn->proto.ftpc.file)
1361 result = Curl_pp_sendf(&ftpc->pp, "PRET %s",
1362 data->set.str[STRING_CUSTOMREQUEST]?
1363 data->set.str[STRING_CUSTOMREQUEST]:
1364 (data->set.ftp_list_only?"NLST":"LIST"));
1365 else if(data->set.upload)
1366 result = Curl_pp_sendf(&ftpc->pp, "PRET STOR %s",
1367 conn->proto.ftpc.file);
1369 result = Curl_pp_sendf(&ftpc->pp, "PRET RETR %s",
1370 conn->proto.ftpc.file);
1372 state(conn, FTP_PRET);
1375 result = ftp_state_use_pasv(conn);
1380 static CURLcode ftp_state_rest(struct connectdata *conn)
1382 CURLcode result = CURLE_OK;
1383 struct FTP *ftp = conn->data->req.protop;
1384 struct ftp_conn *ftpc = &conn->proto.ftpc;
1386 if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
1387 /* if a "head"-like request is being made (on a file) */
1389 /* Determine if server can respond to REST command and therefore
1390 whether it supports range */
1391 result = Curl_pp_sendf(&ftpc->pp, "REST %d", 0);
1393 state(conn, FTP_REST);
1396 result = ftp_state_prepare_transfer(conn);
1401 static CURLcode ftp_state_size(struct connectdata *conn)
1403 CURLcode result = CURLE_OK;
1404 struct FTP *ftp = conn->data->req.protop;
1405 struct ftp_conn *ftpc = &conn->proto.ftpc;
1407 if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
1408 /* if a "head"-like request is being made (on a file) */
1410 /* we know ftpc->file is a valid pointer to a file name */
1411 result = Curl_pp_sendf(&ftpc->pp, "SIZE %s", ftpc->file);
1413 state(conn, FTP_SIZE);
1416 result = ftp_state_rest(conn);
1421 static CURLcode ftp_state_list(struct connectdata *conn)
1423 CURLcode result = CURLE_OK;
1424 struct Curl_easy *data = conn->data;
1425 struct FTP *ftp = data->req.protop;
1427 /* If this output is to be machine-parsed, the NLST command might be better
1428 to use, since the LIST command output is not specified or standard in any
1429 way. It has turned out that the NLST list output is not the same on all
1430 servers either... */
1433 if FTPFILE_NOCWD was specified, we should add the path
1434 as argument for the LIST / NLST / or custom command.
1435 Whether the server will support this, is uncertain.
1437 The other ftp_filemethods will CWD into dir/dir/ first and
1438 then just do LIST (in that case: nothing to do here)
1440 char *lstArg = NULL;
1443 if((data->set.ftp_filemethod == FTPFILE_NOCWD) && ftp->path) {
1444 /* url-decode before evaluation: e.g. paths starting/ending with %2f */
1445 const char *slashPos = NULL;
1446 char *rawPath = NULL;
1447 result = Curl_urldecode(data, ftp->path, 0, &rawPath, NULL, REJECT_CTRL);
1451 slashPos = strrchr(rawPath, '/');
1453 /* chop off the file part if format is dir/file otherwise remove
1454 the trailing slash for dir/dir/ except for absolute path / */
1455 size_t n = slashPos - rawPath;
1466 cmd = aprintf("%s%s%s",
1467 data->set.str[STRING_CUSTOMREQUEST]?
1468 data->set.str[STRING_CUSTOMREQUEST]:
1469 (data->set.ftp_list_only?"NLST":"LIST"),
1471 lstArg? lstArg: "");
1475 return CURLE_OUT_OF_MEMORY;
1477 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
1481 state(conn, FTP_LIST);
1486 static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
1488 /* We've sent the TYPE, now we must send the list of prequote strings */
1489 return ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1492 static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
1494 /* We've sent the TYPE, now we must send the list of prequote strings */
1495 return ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
1498 static CURLcode ftp_state_type(struct connectdata *conn)
1500 CURLcode result = CURLE_OK;
1501 struct FTP *ftp = conn->data->req.protop;
1502 struct Curl_easy *data = conn->data;
1503 struct ftp_conn *ftpc = &conn->proto.ftpc;
1505 /* If we have selected NOBODY and HEADER, it means that we only want file
1506 information. Which in FTP can't be much more than the file size and
1508 if(data->set.opt_no_body && ftpc->file &&
1509 ftp_need_type(conn, data->set.prefer_ascii)) {
1510 /* The SIZE command is _not_ RFC 959 specified, and therefore many servers
1511 may not support it! It is however the only way we have to get a file's
1514 ftp->transfer = FTPTRANSFER_INFO;
1515 /* this means no actual transfer will be made */
1517 /* Some servers return different sizes for different modes, and thus we
1518 must set the proper type before we check the size */
1519 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
1524 result = ftp_state_size(conn);
1529 /* This is called after the CWD commands have been done in the beginning of
1531 static CURLcode ftp_state_mdtm(struct connectdata *conn)
1533 CURLcode result = CURLE_OK;
1534 struct Curl_easy *data = conn->data;
1535 struct ftp_conn *ftpc = &conn->proto.ftpc;
1537 /* Requested time of file or time-depended transfer? */
1538 if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
1540 /* we have requested to get the modified-time of the file, this is a white
1541 spot as the MDTM is not mentioned in RFC959 */
1542 result = Curl_pp_sendf(&ftpc->pp, "MDTM %s", ftpc->file);
1545 state(conn, FTP_MDTM);
1548 result = ftp_state_type(conn);
1554 /* This is called after the TYPE and possible quote commands have been sent */
1555 static CURLcode ftp_state_ul_setup(struct connectdata *conn,
1558 CURLcode result = CURLE_OK;
1559 struct FTP *ftp = conn->data->req.protop;
1560 struct Curl_easy *data = conn->data;
1561 struct ftp_conn *ftpc = &conn->proto.ftpc;
1563 if((data->state.resume_from && !sizechecked) ||
1564 ((data->state.resume_from > 0) && sizechecked)) {
1565 /* we're about to continue the uploading of a file */
1566 /* 1. get already existing file's size. We use the SIZE command for this
1567 which may not exist in the server! The SIZE command is not in
1570 /* 2. This used to set REST. But since we can do append, we
1571 don't another ftp command. We just skip the source file
1572 offset and then we APPEND the rest on the file instead */
1574 /* 3. pass file-size number of bytes in the source file */
1575 /* 4. lower the infilesize counter */
1576 /* => transfer as usual */
1577 int seekerr = CURL_SEEKFUNC_OK;
1579 if(data->state.resume_from < 0) {
1580 /* Got no given size to start from, figure it out */
1581 result = Curl_pp_sendf(&ftpc->pp, "SIZE %s", ftpc->file);
1583 state(conn, FTP_STOR_SIZE);
1588 data->set.ftp_append = TRUE;
1590 /* Let's read off the proper amount of bytes from the input. */
1591 if(conn->seek_func) {
1592 Curl_set_in_callback(data, true);
1593 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1595 Curl_set_in_callback(data, false);
1598 if(seekerr != CURL_SEEKFUNC_OK) {
1599 curl_off_t passed = 0;
1600 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1601 failf(data, "Could not seek stream");
1602 return CURLE_FTP_COULDNT_USE_REST;
1604 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1606 size_t readthisamountnow =
1607 (data->state.resume_from - passed > data->set.buffer_size) ?
1608 (size_t)data->set.buffer_size :
1609 curlx_sotouz(data->state.resume_from - passed);
1611 size_t actuallyread =
1612 data->state.fread_func(data->state.buffer, 1, readthisamountnow,
1615 passed += actuallyread;
1616 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1617 /* this checks for greater-than only to make sure that the
1618 CURL_READFUNC_ABORT return code still aborts */
1619 failf(data, "Failed to read data");
1620 return CURLE_FTP_COULDNT_USE_REST;
1622 } while(passed < data->state.resume_from);
1624 /* now, decrease the size of the read */
1625 if(data->state.infilesize>0) {
1626 data->state.infilesize -= data->state.resume_from;
1628 if(data->state.infilesize <= 0) {
1629 infof(data, "File already completely uploaded\n");
1631 /* no data to transfer */
1632 Curl_setup_transfer(data, -1, -1, FALSE, -1);
1634 /* Set ->transfer so that we won't get any error in
1635 * ftp_done() because we didn't transfer anything! */
1636 ftp->transfer = FTPTRANSFER_NONE;
1638 state(conn, FTP_STOP);
1642 /* we've passed, proceed as normal */
1645 result = Curl_pp_sendf(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
1648 state(conn, FTP_STOR);
1653 static CURLcode ftp_state_quote(struct connectdata *conn,
1657 CURLcode result = CURLE_OK;
1658 struct Curl_easy *data = conn->data;
1659 struct FTP *ftp = data->req.protop;
1660 struct ftp_conn *ftpc = &conn->proto.ftpc;
1662 struct curl_slist *item;
1667 item = data->set.quote;
1669 case FTP_RETR_PREQUOTE:
1670 case FTP_STOR_PREQUOTE:
1671 item = data->set.prequote;
1674 item = data->set.postquote;
1680 * 'count1' to iterate over the commands to send
1681 * 'count2' to store whether to allow commands to fail
1692 /* Skip count1 items in the linked list */
1693 while((i< ftpc->count1) && item) {
1698 char *cmd = item->data;
1701 ftpc->count2 = 1; /* the sent command is allowed to fail */
1704 ftpc->count2 = 0; /* failure means cancel operation */
1706 result = Curl_pp_sendf(&ftpc->pp, "%s", cmd);
1709 state(conn, instate);
1715 /* No more quote to send, continue to ... */
1719 result = ftp_state_cwd(conn);
1721 case FTP_RETR_PREQUOTE:
1722 if(ftp->transfer != FTPTRANSFER_BODY)
1723 state(conn, FTP_STOP);
1725 if(ftpc->known_filesize != -1) {
1726 Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
1727 result = ftp_state_retr(conn, ftpc->known_filesize);
1730 if(data->set.ignorecl) {
1731 /* This code is to support download of growing files. It prevents
1732 the state machine from requesting the file size from the
1733 server. With an unknown file size the download continues until
1734 the server terminates it, otherwise the client stops if the
1735 received byte count exceeds the reported file size. Set option
1736 CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this behavior.*/
1737 result = Curl_pp_sendf(&ftpc->pp, "RETR %s", ftpc->file);
1739 state(conn, FTP_RETR);
1742 result = Curl_pp_sendf(&ftpc->pp, "SIZE %s", ftpc->file);
1744 state(conn, FTP_RETR_SIZE);
1749 case FTP_STOR_PREQUOTE:
1750 result = ftp_state_ul_setup(conn, FALSE);
1760 /* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
1762 static CURLcode ftp_epsv_disable(struct connectdata *conn)
1764 CURLcode result = CURLE_OK;
1767 #ifndef CURL_DISABLE_PROXY
1768 && !(conn->bits.tunnel_proxy || conn->bits.socksproxy)
1771 /* We can't disable EPSV when doing IPv6, so this is instead a fail */
1772 failf(conn->data, "Failed EPSV attempt, exiting\n");
1773 return CURLE_WEIRD_SERVER_REPLY;
1776 infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
1777 /* disable it for next transfer */
1778 conn->bits.ftp_use_epsv = FALSE;
1779 conn->data->state.errorbuf = FALSE; /* allow error message to get
1781 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "PASV");
1783 conn->proto.ftpc.count1++;
1784 /* remain in/go to the FTP_PASV state */
1785 state(conn, FTP_PASV);
1791 static char *control_address(struct connectdata *conn)
1793 /* Returns the control connection IP address.
1794 If a proxy tunnel is used, returns the original host name instead, because
1795 the effective control connection address is the proxy address,
1796 not the ftp host. */
1797 #ifndef CURL_DISABLE_PROXY
1798 if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
1799 return conn->host.name;
1801 return conn->ip_addr_str;
1804 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1807 struct ftp_conn *ftpc = &conn->proto.ftpc;
1809 struct Curl_easy *data = conn->data;
1810 struct Curl_dns_entry *addr = NULL;
1812 unsigned short connectport; /* the local port connect() should use! */
1813 char *str = &data->state.buffer[4]; /* start on the first letter */
1815 /* if we come here again, make sure the former name is cleared */
1816 Curl_safefree(ftpc->newhost);
1818 if((ftpc->count1 == 0) &&
1820 /* positive EPSV response */
1821 char *ptr = strchr(str, '(');
1826 if(5 == sscanf(ptr, "%c%c%c%u%c",
1832 const char sep1 = separator[0];
1835 /* The four separators should be identical, or else this is an oddly
1836 formatted reply and we bail out immediately. */
1837 for(i = 1; i<4; i++) {
1838 if(separator[i] != sep1) {
1839 ptr = NULL; /* set to NULL to signal error */
1844 failf(data, "Illegal port number in EPSV reply");
1845 return CURLE_FTP_WEIRD_PASV_REPLY;
1848 ftpc->newport = (unsigned short)(num & 0xffff);
1849 ftpc->newhost = strdup(control_address(conn));
1851 return CURLE_OUT_OF_MEMORY;
1858 failf(data, "Weirdly formatted EPSV reply");
1859 return CURLE_FTP_WEIRD_PASV_REPLY;
1862 else if((ftpc->count1 == 1) &&
1864 /* positive PASV response */
1865 unsigned int ip[4] = {0, 0, 0, 0};
1866 unsigned int port[2] = {0, 0};
1869 * Scan for a sequence of six comma-separated numbers and use them as
1870 * IP+port indicators.
1872 * Found reply-strings include:
1873 * "227 Entering Passive Mode (127,0,0,1,4,51)"
1874 * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1875 * "227 Entering passive mode. 127,0,0,1,4,51"
1878 if(6 == sscanf(str, "%u,%u,%u,%u,%u,%u",
1879 &ip[0], &ip[1], &ip[2], &ip[3],
1880 &port[0], &port[1]))
1885 if(!*str || (ip[0] > 255) || (ip[1] > 255) || (ip[2] > 255) ||
1886 (ip[3] > 255) || (port[0] > 255) || (port[1] > 255) ) {
1887 failf(data, "Couldn't interpret the 227-response");
1888 return CURLE_FTP_WEIRD_227_FORMAT;
1891 /* we got OK from server */
1892 if(data->set.ftp_skip_ip) {
1893 /* told to ignore the remotely given IP but instead use the host we used
1894 for the control connection */
1895 infof(data, "Skip %u.%u.%u.%u for data connection, re-use %s instead\n",
1896 ip[0], ip[1], ip[2], ip[3],
1898 ftpc->newhost = strdup(control_address(conn));
1901 ftpc->newhost = aprintf("%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
1904 return CURLE_OUT_OF_MEMORY;
1906 ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
1908 else if(ftpc->count1 == 0) {
1909 /* EPSV failed, move on to PASV */
1910 return ftp_epsv_disable(conn);
1913 failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
1914 return CURLE_FTP_WEIRD_PASV_REPLY;
1917 #ifndef CURL_DISABLE_PROXY
1918 if(conn->bits.proxy) {
1920 * This connection uses a proxy and we need to connect to the proxy again
1921 * here. We don't want to rely on a former host lookup that might've
1922 * expired now, instead we remake the lookup here and now!
1924 const char * const host_name = conn->bits.socksproxy ?
1925 conn->socks_proxy.host.name : conn->http_proxy.host.name;
1926 rc = Curl_resolv(conn, host_name, (int)conn->port, FALSE, &addr);
1927 if(rc == CURLRESOLV_PENDING)
1928 /* BLOCKING, ignores the return code but 'addr' will be NULL in
1930 (void)Curl_resolver_wait_resolv(conn, &addr);
1933 (unsigned short)conn->port; /* we connect to the proxy's port */
1936 failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport);
1937 return CURLE_COULDNT_RESOLVE_PROXY;
1943 /* normal, direct, ftp connection */
1944 rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, FALSE, &addr);
1945 if(rc == CURLRESOLV_PENDING)
1947 (void)Curl_resolver_wait_resolv(conn, &addr);
1949 connectport = ftpc->newport; /* we connect to the remote port */
1952 failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
1953 return CURLE_FTP_CANT_GET_HOST;
1957 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
1958 result = Curl_connecthost(conn, addr);
1961 Curl_resolv_unlock(data, addr); /* we're done using this address */
1962 if(ftpc->count1 == 0 && ftpcode == 229)
1963 return ftp_epsv_disable(conn);
1970 * When this is used from the multi interface, this might've returned with
1971 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
1972 * connect to connect.
1975 if(data->set.verbose)
1976 /* this just dumps information about this second connection */
1977 ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport);
1979 Curl_resolv_unlock(data, addr); /* we're done using this address */
1981 Curl_safefree(conn->secondaryhostname);
1982 conn->secondary_port = ftpc->newport;
1983 conn->secondaryhostname = strdup(ftpc->newhost);
1984 if(!conn->secondaryhostname)
1985 return CURLE_OUT_OF_MEMORY;
1987 conn->bits.do_more = TRUE;
1988 state(conn, FTP_STOP); /* this phase is completed */
1993 static CURLcode ftp_state_port_resp(struct connectdata *conn,
1996 struct Curl_easy *data = conn->data;
1997 struct ftp_conn *ftpc = &conn->proto.ftpc;
1998 ftpport fcmd = (ftpport)ftpc->count1;
1999 CURLcode result = CURLE_OK;
2001 /* The FTP spec tells a positive response should have code 200.
2002 Be more permissive here to tolerate deviant servers. */
2003 if(ftpcode / 100 != 2) {
2004 /* the command failed */
2007 infof(data, "disabling EPRT usage\n");
2008 conn->bits.ftp_use_eprt = FALSE;
2013 failf(data, "Failed to do PORT");
2014 result = CURLE_FTP_PORT_FAILED;
2018 result = ftp_state_use_port(conn, fcmd);
2021 infof(data, "Connect data stream actively\n");
2022 state(conn, FTP_STOP); /* end of DO phase */
2023 result = ftp_dophase_done(conn, FALSE);
2029 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
2032 CURLcode result = CURLE_OK;
2033 struct Curl_easy *data = conn->data;
2034 struct FTP *ftp = data->req.protop;
2035 struct ftp_conn *ftpc = &conn->proto.ftpc;
2040 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
2041 last .sss part is optional and means fractions of a second */
2042 int year, month, day, hour, minute, second;
2043 if(6 == sscanf(&data->state.buffer[4], "%04d%02d%02d%02d%02d%02d",
2044 &year, &month, &day, &hour, &minute, &second)) {
2045 /* we have a time, reformat it */
2047 msnprintf(timebuf, sizeof(timebuf),
2048 "%04d%02d%02d %02d:%02d:%02d GMT",
2049 year, month, day, hour, minute, second);
2050 /* now, convert this into a time() value: */
2051 data->info.filetime = Curl_getdate_capped(timebuf);
2054 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2055 /* If we asked for a time of the file and we actually got one as well,
2056 we "emulate" a HTTP-style header in our output. */
2058 if(data->set.opt_no_body &&
2060 data->set.get_filetime &&
2061 (data->info.filetime >= 0) ) {
2062 char headerbuf[128];
2063 time_t filetime = data->info.filetime;
2065 const struct tm *tm = &buffer;
2067 result = Curl_gmtime(filetime, &buffer);
2071 /* format: "Tue, 15 Nov 1994 12:45:26" */
2072 msnprintf(headerbuf, sizeof(headerbuf),
2073 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
2074 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2076 Curl_month[tm->tm_mon],
2081 result = Curl_client_write(conn, CLIENTWRITE_BOTH, headerbuf, 0);
2084 } /* end of a ridiculous amount of conditionals */
2089 infof(data, "unsupported MDTM reply format\n");
2091 case 550: /* "No such file or directory" */
2092 failf(data, "Given file does not exist");
2093 result = CURLE_REMOTE_FILE_NOT_FOUND;
2097 if(data->set.timecondition) {
2098 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2099 switch(data->set.timecondition) {
2100 case CURL_TIMECOND_IFMODSINCE:
2102 if(data->info.filetime <= data->set.timevalue) {
2103 infof(data, "The requested document is not new enough\n");
2104 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2105 data->info.timecond = TRUE;
2106 state(conn, FTP_STOP);
2110 case CURL_TIMECOND_IFUNMODSINCE:
2111 if(data->info.filetime > data->set.timevalue) {
2112 infof(data, "The requested document is not old enough\n");
2113 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2114 data->info.timecond = TRUE;
2115 state(conn, FTP_STOP);
2122 infof(data, "Skipping time comparison\n");
2127 result = ftp_state_type(conn);
2132 static CURLcode ftp_state_type_resp(struct connectdata *conn,
2136 CURLcode result = CURLE_OK;
2137 struct Curl_easy *data = conn->data;
2139 if(ftpcode/100 != 2) {
2140 /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
2141 successful 'TYPE I'. While that is not as RFC959 says, it is still a
2142 positive response code and we allow that. */
2143 failf(data, "Couldn't set desired mode");
2144 return CURLE_FTP_COULDNT_SET_TYPE;
2147 infof(data, "Got a %03d response code instead of the assumed 200\n",
2150 if(instate == FTP_TYPE)
2151 result = ftp_state_size(conn);
2152 else if(instate == FTP_LIST_TYPE)
2153 result = ftp_state_list(conn);
2154 else if(instate == FTP_RETR_TYPE)
2155 result = ftp_state_retr_prequote(conn);
2156 else if(instate == FTP_STOR_TYPE)
2157 result = ftp_state_stor_prequote(conn);
2162 static CURLcode ftp_state_retr(struct connectdata *conn,
2163 curl_off_t filesize)
2165 CURLcode result = CURLE_OK;
2166 struct Curl_easy *data = conn->data;
2167 struct FTP *ftp = data->req.protop;
2168 struct ftp_conn *ftpc = &conn->proto.ftpc;
2170 if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
2171 failf(data, "Maximum file size exceeded");
2172 return CURLE_FILESIZE_EXCEEDED;
2174 ftp->downloadsize = filesize;
2176 if(data->state.resume_from) {
2177 /* We always (attempt to) get the size of downloads, so it is done before
2178 this even when not doing resumes. */
2179 if(filesize == -1) {
2180 infof(data, "ftp server doesn't support SIZE\n");
2181 /* We couldn't get the size and therefore we can't know if there really
2182 is a part of the file left to get, although the server will just
2183 close the connection when we start the connection so it won't cause
2184 us any harm, just not make us exit as nicely. */
2187 /* We got a file size report, so we check that there actually is a
2188 part of the file left to get, or else we go home. */
2189 if(data->state.resume_from< 0) {
2190 /* We're supposed to download the last abs(from) bytes */
2191 if(filesize < -data->state.resume_from) {
2192 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2193 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2194 data->state.resume_from, filesize);
2195 return CURLE_BAD_DOWNLOAD_RESUME;
2197 /* convert to size to download */
2198 ftp->downloadsize = -data->state.resume_from;
2199 /* download from where? */
2200 data->state.resume_from = filesize - ftp->downloadsize;
2203 if(filesize < data->state.resume_from) {
2204 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2205 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2206 data->state.resume_from, filesize);
2207 return CURLE_BAD_DOWNLOAD_RESUME;
2209 /* Now store the number of bytes we are expected to download */
2210 ftp->downloadsize = filesize-data->state.resume_from;
2214 if(ftp->downloadsize == 0) {
2215 /* no data to transfer */
2216 Curl_setup_transfer(data, -1, -1, FALSE, -1);
2217 infof(data, "File already completely downloaded\n");
2219 /* Set ->transfer so that we won't get any error in ftp_done()
2220 * because we didn't transfer the any file */
2221 ftp->transfer = FTPTRANSFER_NONE;
2222 state(conn, FTP_STOP);
2226 /* Set resume file transfer offset */
2227 infof(data, "Instructs server to resume from offset %"
2228 CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
2230 result = Curl_pp_sendf(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
2231 data->state.resume_from);
2233 state(conn, FTP_RETR_REST);
2237 result = Curl_pp_sendf(&ftpc->pp, "RETR %s", ftpc->file);
2239 state(conn, FTP_RETR);
2245 static CURLcode ftp_state_size_resp(struct connectdata *conn,
2249 CURLcode result = CURLE_OK;
2250 struct Curl_easy *data = conn->data;
2251 curl_off_t filesize = -1;
2252 char *buf = data->state.buffer;
2254 /* get the size from the ascii string: */
2255 if(ftpcode == 213) {
2256 /* To allow servers to prepend "rubbish" in the response string, we scan
2257 for all the digits at the end of the response and parse only those as a
2259 char *start = &buf[4];
2260 char *fdigit = strchr(start, '\r');
2264 while(ISDIGIT(*fdigit) && (fdigit > start));
2265 if(!ISDIGIT(*fdigit))
2270 /* ignores parsing errors, which will make the size remain unknown */
2271 (void)curlx_strtoofft(fdigit, NULL, 0, &filesize);
2274 else if(ftpcode == 550) { /* "No such file or directory" */
2275 failf(data, "The file does not exist");
2276 return CURLE_REMOTE_FILE_NOT_FOUND;
2279 if(instate == FTP_SIZE) {
2280 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2281 if(-1 != filesize) {
2283 msnprintf(clbuf, sizeof(clbuf),
2284 "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
2285 result = Curl_client_write(conn, CLIENTWRITE_BOTH, clbuf, 0);
2290 Curl_pgrsSetDownloadSize(data, filesize);
2291 result = ftp_state_rest(conn);
2293 else if(instate == FTP_RETR_SIZE) {
2294 Curl_pgrsSetDownloadSize(data, filesize);
2295 result = ftp_state_retr(conn, filesize);
2297 else if(instate == FTP_STOR_SIZE) {
2298 data->state.resume_from = filesize;
2299 result = ftp_state_ul_setup(conn, TRUE);
2305 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
2309 CURLcode result = CURLE_OK;
2310 struct ftp_conn *ftpc = &conn->proto.ftpc;
2315 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2316 if(ftpcode == 350) {
2317 char buffer[24]= { "Accept-ranges: bytes\r\n" };
2318 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
2323 result = ftp_state_prepare_transfer(conn);
2327 if(ftpcode != 350) {
2328 failf(conn->data, "Couldn't use REST");
2329 result = CURLE_FTP_COULDNT_USE_REST;
2332 result = Curl_pp_sendf(&ftpc->pp, "RETR %s", ftpc->file);
2334 state(conn, FTP_RETR);
2342 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
2343 int ftpcode, ftpstate instate)
2345 CURLcode result = CURLE_OK;
2346 struct Curl_easy *data = conn->data;
2348 if(ftpcode >= 400) {
2349 failf(data, "Failed FTP upload: %0d", ftpcode);
2350 state(conn, FTP_STOP);
2351 /* oops, we never close the sockets! */
2352 return CURLE_UPLOAD_FAILED;
2355 conn->proto.ftpc.state_saved = instate;
2357 /* PORT means we are now awaiting the server to connect to us. */
2358 if(data->set.ftp_use_port) {
2361 state(conn, FTP_STOP); /* no longer in STOR state */
2363 result = AllowServerConnect(conn, &connected);
2368 struct ftp_conn *ftpc = &conn->proto.ftpc;
2369 infof(data, "Data conn was not available immediately\n");
2370 ftpc->wait_data_conn = TRUE;
2375 return InitiateTransfer(conn);
2378 /* for LIST and RETR responses */
2379 static CURLcode ftp_state_get_resp(struct connectdata *conn,
2383 CURLcode result = CURLE_OK;
2384 struct Curl_easy *data = conn->data;
2385 struct FTP *ftp = data->req.protop;
2387 if((ftpcode == 150) || (ftpcode == 125)) {
2391 150 Opening BINARY mode data connection for /etc/passwd (2241
2392 bytes). (ok, the file is being transferred)
2395 150 Opening ASCII mode data connection for /bin/ls
2398 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2401 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
2404 125 Data connection already open; Transfer starting. */
2406 curl_off_t size = -1; /* default unknown size */
2410 * It appears that there are FTP-servers that return size 0 for files when
2411 * SIZE is used on the file while being in BINARY mode. To work around
2412 * that (stupid) behavior, we attempt to parse the RETR response even if
2413 * the SIZE returned size zero.
2415 * Debugging help from Salvatore Sorrentino on February 26, 2003.
2418 if((instate != FTP_LIST) &&
2419 !data->set.prefer_ascii &&
2420 (ftp->downloadsize < 1)) {
2422 * It seems directory listings either don't show the size or very
2423 * often uses size 0 anyway. ASCII transfers may very well turn out
2424 * that the transferred amount of data is not the same as this line
2425 * tells, why using this number in those cases only confuses us.
2427 * Example D above makes this parsing a little tricky */
2429 char *buf = data->state.buffer;
2430 bytes = strstr(buf, " bytes");
2432 long in = (long)(--bytes-buf);
2433 /* this is a hint there is size information in there! ;-) */
2435 /* scan for the left parenthesis and break there */
2438 /* skip only digits */
2439 if(!ISDIGIT(*bytes)) {
2443 /* one more estep backwards */
2446 /* if we have nothing but digits: */
2448 /* get the number! */
2449 (void)curlx_strtoofft(bytes, NULL, 0, &size);
2453 else if(ftp->downloadsize > -1)
2454 size = ftp->downloadsize;
2456 if(size > data->req.maxdownload && data->req.maxdownload > 0)
2457 size = data->req.size = data->req.maxdownload;
2458 else if((instate != FTP_LIST) && (data->set.prefer_ascii))
2459 size = -1; /* kludge for servers that understate ASCII mode file size */
2461 infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
2462 data->req.maxdownload);
2464 if(instate != FTP_LIST)
2465 infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n",
2469 conn->proto.ftpc.state_saved = instate;
2470 conn->proto.ftpc.retr_size_saved = size;
2472 if(data->set.ftp_use_port) {
2475 result = AllowServerConnect(conn, &connected);
2480 struct ftp_conn *ftpc = &conn->proto.ftpc;
2481 infof(data, "Data conn was not available immediately\n");
2482 state(conn, FTP_STOP);
2483 ftpc->wait_data_conn = TRUE;
2487 return InitiateTransfer(conn);
2490 if((instate == FTP_LIST) && (ftpcode == 450)) {
2491 /* simply no matching files in the dir listing */
2492 ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
2493 state(conn, FTP_STOP); /* this phase is over */
2496 failf(data, "RETR response: %03d", ftpcode);
2497 return instate == FTP_RETR && ftpcode == 550?
2498 CURLE_REMOTE_FILE_NOT_FOUND:
2499 CURLE_FTP_COULDNT_RETR_FILE;
2506 /* after USER, PASS and ACCT */
2507 static CURLcode ftp_state_loggedin(struct connectdata *conn)
2509 CURLcode result = CURLE_OK;
2511 if(conn->bits.ftp_use_control_ssl) {
2512 /* PBSZ = PROTECTION BUFFER SIZE.
2514 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2516 Specifically, the PROT command MUST be preceded by a PBSZ
2517 command and a PBSZ command MUST be preceded by a successful
2518 security data exchange (the TLS negotiation in this case)
2520 ... (and on page 8):
2522 Thus the PBSZ command must still be issued, but must have a
2523 parameter of '0' to indicate that no buffering is taking place
2524 and the data connection should not be encapsulated.
2526 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "PBSZ %d", 0);
2528 state(conn, FTP_PBSZ);
2531 result = ftp_state_pwd(conn);
2536 /* for USER and PASS responses */
2537 static CURLcode ftp_state_user_resp(struct connectdata *conn,
2541 CURLcode result = CURLE_OK;
2542 struct Curl_easy *data = conn->data;
2543 struct ftp_conn *ftpc = &conn->proto.ftpc;
2544 (void)instate; /* no use for this yet */
2546 /* some need password anyway, and others just return 2xx ignored */
2547 if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2548 /* 331 Password required for ...
2549 (the server requires to send the user's password too) */
2550 result = Curl_pp_sendf(&ftpc->pp, "PASS %s", conn->passwd?conn->passwd:"");
2552 state(conn, FTP_PASS);
2554 else if(ftpcode/100 == 2) {
2555 /* 230 User ... logged in.
2556 (the user logged in with or without password) */
2557 result = ftp_state_loggedin(conn);
2559 else if(ftpcode == 332) {
2560 if(data->set.str[STRING_FTP_ACCOUNT]) {
2561 result = Curl_pp_sendf(&ftpc->pp, "ACCT %s",
2562 data->set.str[STRING_FTP_ACCOUNT]);
2564 state(conn, FTP_ACCT);
2567 failf(data, "ACCT requested but none available");
2568 result = CURLE_LOGIN_DENIED;
2572 /* All other response codes, like:
2574 530 User ... access denied
2575 (the server denies to log the specified user) */
2577 if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2578 !conn->data->state.ftp_trying_alternative) {
2579 /* Ok, USER failed. Let's try the supplied command. */
2581 Curl_pp_sendf(&ftpc->pp, "%s",
2582 conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2584 conn->data->state.ftp_trying_alternative = TRUE;
2585 state(conn, FTP_USER);
2589 failf(data, "Access denied: %03d", ftpcode);
2590 result = CURLE_LOGIN_DENIED;
2596 /* for ACCT response */
2597 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
2600 CURLcode result = CURLE_OK;
2601 struct Curl_easy *data = conn->data;
2602 if(ftpcode != 230) {
2603 failf(data, "ACCT rejected by server: %03d", ftpcode);
2604 result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2607 result = ftp_state_loggedin(conn);
2613 static CURLcode ftp_statemach_act(struct connectdata *conn)
2616 curl_socket_t sock = conn->sock[FIRSTSOCKET];
2617 struct Curl_easy *data = conn->data;
2619 struct ftp_conn *ftpc = &conn->proto.ftpc;
2620 struct pingpong *pp = &ftpc->pp;
2621 static const char ftpauth[][4] = { "SSL", "TLS" };
2625 return Curl_pp_flushsend(pp);
2627 result = ftp_readresp(sock, pp, &ftpcode, &nread);
2632 /* we have now received a full FTP server response */
2633 switch(ftpc->state) {
2636 /* 230 User logged in - already! */
2637 return ftp_state_user_resp(conn, ftpcode, ftpc->state);
2638 else if(ftpcode != 220) {
2639 failf(data, "Got a %03d ftp-server response when 220 was expected",
2641 return CURLE_WEIRD_SERVER_REPLY;
2644 /* We have received a 220 response fine, now we proceed. */
2647 /* If not anonymous login, try a secure login. Note that this
2648 procedure is still BLOCKING. */
2650 Curl_sec_request_prot(conn, "private");
2651 /* We set private first as default, in case the line below fails to
2652 set a valid level */
2653 Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2655 if(Curl_sec_login(conn))
2656 infof(data, "Logging in with password in cleartext!\n");
2658 infof(data, "Authentication successful\n");
2662 if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) {
2663 /* We don't have a SSL/TLS control connection yet, but FTPS is
2664 requested. Try a FTPS connection now */
2667 switch(data->set.ftpsslauth) {
2668 case CURLFTPAUTH_DEFAULT:
2669 case CURLFTPAUTH_SSL:
2670 ftpc->count2 = 1; /* add one to get next */
2673 case CURLFTPAUTH_TLS:
2674 ftpc->count2 = -1; /* subtract one to get next */
2678 failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2679 (int)data->set.ftpsslauth);
2680 return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
2682 result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2684 state(conn, FTP_AUTH);
2687 result = ftp_state_user(conn);
2691 /* we have gotten the response to a previous AUTH command */
2693 /* RFC2228 (page 5) says:
2695 * If the server is willing to accept the named security mechanism,
2696 * and does not require any security data, it must respond with
2697 * reply code 234/334.
2700 if((ftpcode == 234) || (ftpcode == 334)) {
2701 /* Curl_ssl_connect is BLOCKING */
2702 result = Curl_ssl_connect(conn, FIRSTSOCKET);
2704 conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */
2705 conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */
2706 result = ftp_state_user(conn);
2709 else if(ftpc->count3 < 1) {
2711 ftpc->count1 += ftpc->count2; /* get next attempt */
2712 result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2713 /* remain in this same state */
2716 if(data->set.use_ssl > CURLUSESSL_TRY)
2717 /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2718 result = CURLE_USE_SSL_FAILED;
2720 /* ignore the failure and continue */
2721 result = ftp_state_user(conn);
2727 result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
2731 result = ftp_state_acct_resp(conn, ftpcode);
2736 Curl_pp_sendf(&ftpc->pp, "PROT %c",
2737 data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2739 state(conn, FTP_PROT);
2743 if(ftpcode/100 == 2)
2744 /* We have enabled SSL for the data connection! */
2745 conn->bits.ftp_use_data_ssl =
2746 (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
2747 /* FTP servers typically responds with 500 if they decide to reject
2749 else if(data->set.use_ssl > CURLUSESSL_CONTROL)
2750 /* we failed and bails out */
2751 return CURLE_USE_SSL_FAILED;
2753 if(data->set.ftp_ccc) {
2754 /* CCC - Clear Command Channel
2756 result = Curl_pp_sendf(&ftpc->pp, "%s", "CCC");
2758 state(conn, FTP_CCC);
2761 result = ftp_state_pwd(conn);
2766 /* First shut down the SSL layer (note: this call will block) */
2767 result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
2770 failf(conn->data, "Failed to clear the command channel (CCC)");
2773 /* Then continue as normal */
2774 result = ftp_state_pwd(conn);
2778 if(ftpcode == 257) {
2779 char *ptr = &data->state.buffer[4]; /* start on the first letter */
2780 const size_t buf_size = data->set.buffer_size;
2782 bool entry_extracted = FALSE;
2784 dir = malloc(nread + 1);
2786 return CURLE_OUT_OF_MEMORY;
2788 /* Reply format is like
2789 257<space>[rubbish]"<directory-name>"<space><commentary> and the
2792 The directory name can contain any character; embedded
2793 double-quotes should be escaped by double-quotes (the
2794 "quote-doubling" convention).
2797 /* scan for the first double-quote for non-standard responses */
2798 while(ptr < &data->state.buffer[buf_size]
2799 && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
2803 /* it started good */
2806 for(store = dir; *ptr;) {
2808 if('\"' == ptr[1]) {
2809 /* "quote-doubling" */
2815 entry_extracted = TRUE;
2816 break; /* get out of this loop */
2824 *store = '\0'; /* null-terminate */
2826 if(entry_extracted) {
2827 /* If the path name does not look like an absolute path (i.e.: it
2828 does not start with a '/'), we probably need some server-dependent
2829 adjustments. For example, this is the case when connecting to
2830 an OS400 FTP server: this server supports two name syntaxes,
2831 the default one being incompatible with standard paths. In
2832 addition, this server switches automatically to the regular path
2833 syntax when one is encountered in a command: this results in
2834 having an entrypath in the wrong syntax when later used in CWD.
2835 The method used here is to check the server OS: we do it only
2836 if the path name looks strange to minimize overhead on other
2839 if(!ftpc->server_os && dir[0] != '/') {
2840 result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
2845 Curl_safefree(ftpc->entrypath);
2846 ftpc->entrypath = dir; /* remember this */
2847 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2848 /* also save it where getinfo can access it: */
2849 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2850 state(conn, FTP_SYST);
2854 Curl_safefree(ftpc->entrypath);
2855 ftpc->entrypath = dir; /* remember this */
2856 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2857 /* also save it where getinfo can access it: */
2858 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2861 /* couldn't get the path */
2863 infof(data, "Failed to figure out path\n");
2866 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2867 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2871 if(ftpcode == 215) {
2872 char *ptr = &data->state.buffer[4]; /* start on the first letter */
2876 os = malloc(nread + 1);
2878 return CURLE_OUT_OF_MEMORY;
2880 /* Reply format is like
2881 215<space><OS-name><space><commentary>
2885 for(store = os; *ptr && *ptr != ' ';)
2887 *store = '\0'; /* null-terminate */
2889 /* Check for special servers here. */
2891 if(strcasecompare(os, "OS/400")) {
2892 /* Force OS400 name format 1. */
2893 result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
2898 /* remember target server OS */
2899 Curl_safefree(ftpc->server_os);
2900 ftpc->server_os = os;
2901 state(conn, FTP_NAMEFMT);
2904 /* Nothing special for the target server. */
2905 /* remember target server OS */
2906 Curl_safefree(ftpc->server_os);
2907 ftpc->server_os = os;
2910 /* Cannot identify server OS. Continue anyway and cross fingers. */
2913 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2914 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2918 if(ftpcode == 250) {
2919 /* Name format change successful: reload initial path. */
2920 ftp_state_pwd(conn);
2924 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2925 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2930 case FTP_RETR_PREQUOTE:
2931 case FTP_STOR_PREQUOTE:
2932 if((ftpcode >= 400) && !ftpc->count2) {
2933 /* failure response code, and not allowed to fail */
2934 failf(conn->data, "QUOT command failed with %03d", ftpcode);
2935 result = CURLE_QUOTE_ERROR;
2938 result = ftp_state_quote(conn, FALSE, ftpc->state);
2942 if(ftpcode/100 != 2) {
2943 /* failure to CWD there */
2944 if(conn->data->set.ftp_create_missing_dirs &&
2945 ftpc->cwdcount && !ftpc->count2) {
2947 ftpc->count2++; /* counter to prevent CWD-MKD loops */
2948 result = Curl_pp_sendf(&ftpc->pp, "MKD %s",
2949 ftpc->dirs[ftpc->cwdcount - 1]);
2951 state(conn, FTP_MKD);
2954 /* return failure */
2955 failf(data, "Server denied you to change to the given directory");
2956 ftpc->cwdfail = TRUE; /* don't remember this path as we failed
2958 result = CURLE_REMOTE_ACCESS_DENIED;
2964 if(++ftpc->cwdcount <= ftpc->dirdepth)
2966 result = Curl_pp_sendf(&ftpc->pp, "CWD %s",
2967 ftpc->dirs[ftpc->cwdcount - 1]);
2969 result = ftp_state_mdtm(conn);
2974 if((ftpcode/100 != 2) && !ftpc->count3--) {
2975 /* failure to MKD the dir */
2976 failf(data, "Failed to MKD dir: %03d", ftpcode);
2977 result = CURLE_REMOTE_ACCESS_DENIED;
2980 state(conn, FTP_CWD);
2982 result = Curl_pp_sendf(&ftpc->pp, "CWD %s",
2983 ftpc->dirs[ftpc->cwdcount - 1]);
2988 result = ftp_state_mdtm_resp(conn, ftpcode);
2995 result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
3001 result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
3006 result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
3010 if(ftpcode != 200) {
3011 /* there only is this one standard OK return code. */
3012 failf(data, "PRET command not accepted: %03d", ftpcode);
3013 return CURLE_FTP_PRET_FAILED;
3015 result = ftp_state_use_pasv(conn);
3019 result = ftp_state_pasv_resp(conn, ftpcode);
3023 result = ftp_state_port_resp(conn, ftpcode);
3028 result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
3032 result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
3036 /* fallthrough, just stop! */
3038 /* internal error */
3039 state(conn, FTP_STOP);
3048 /* called repeatedly until done from multi.c */
3049 static CURLcode ftp_multi_statemach(struct connectdata *conn,
3052 struct ftp_conn *ftpc = &conn->proto.ftpc;
3053 CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE, FALSE);
3055 /* Check for the state outside of the Curl_socket_check() return code checks
3056 since at times we are in fact already in this state when this function
3058 *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
3063 static CURLcode ftp_block_statemach(struct connectdata *conn)
3065 struct ftp_conn *ftpc = &conn->proto.ftpc;
3066 struct pingpong *pp = &ftpc->pp;
3067 CURLcode result = CURLE_OK;
3069 while(ftpc->state != FTP_STOP) {
3070 result = Curl_pp_statemach(pp, TRUE, TRUE /* disconnecting */);
3079 * ftp_connect() should do everything that is to be considered a part of
3080 * the connection phase.
3082 * The variable 'done' points to will be TRUE if the protocol-layer connect
3083 * phase is done when this function returns, or FALSE if not.
3086 static CURLcode ftp_connect(struct connectdata *conn,
3087 bool *done) /* see description above */
3090 struct ftp_conn *ftpc = &conn->proto.ftpc;
3091 struct pingpong *pp = &ftpc->pp;
3093 *done = FALSE; /* default to not done yet */
3095 /* We always support persistent connections on ftp */
3096 connkeep(conn, "FTP default");
3098 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
3099 pp->statemach_act = ftp_statemach_act;
3100 pp->endofresp = ftp_endofresp;
3103 if(conn->handler->flags & PROTOPT_SSL) {
3105 result = Curl_ssl_connect(conn, FIRSTSOCKET);
3108 conn->bits.ftp_use_control_ssl = TRUE;
3111 Curl_pp_setup(pp); /* once per transfer */
3112 Curl_pp_init(pp); /* init the generic pingpong data */
3114 /* When we connect, we start in the state where we await the 220
3116 state(conn, FTP_WAIT220);
3118 result = ftp_multi_statemach(conn, done);
3123 /***********************************************************************
3127 * The DONE function. This does what needs to be done after a single DO has
3130 * Input argument is already checked for validity.
3132 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
3135 struct Curl_easy *data = conn->data;
3136 struct FTP *ftp = data->req.protop;
3137 struct ftp_conn *ftpc = &conn->proto.ftpc;
3138 struct pingpong *pp = &ftpc->pp;
3141 CURLcode result = CURLE_OK;
3142 char *rawPath = NULL;
3149 case CURLE_BAD_DOWNLOAD_RESUME:
3150 case CURLE_FTP_WEIRD_PASV_REPLY:
3151 case CURLE_FTP_PORT_FAILED:
3152 case CURLE_FTP_ACCEPT_FAILED:
3153 case CURLE_FTP_ACCEPT_TIMEOUT:
3154 case CURLE_FTP_COULDNT_SET_TYPE:
3155 case CURLE_FTP_COULDNT_RETR_FILE:
3156 case CURLE_PARTIAL_FILE:
3157 case CURLE_UPLOAD_FAILED:
3158 case CURLE_REMOTE_ACCESS_DENIED:
3159 case CURLE_FILESIZE_EXCEEDED:
3160 case CURLE_REMOTE_FILE_NOT_FOUND:
3161 case CURLE_WRITE_ERROR:
3162 /* the connection stays alive fine even though this happened */
3164 case CURLE_OK: /* doesn't affect the control connection's status */
3168 /* until we cope better with prematurely ended requests, let them
3169 * fallback as if in complete failure */
3171 default: /* by default, an error means the control connection is
3172 wedged and should not be used anymore */
3173 ftpc->ctl_valid = FALSE;
3174 ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3175 current path, as this connection is going */
3176 connclose(conn, "FTP ended with bad error code");
3177 result = status; /* use the already set error code */
3181 if(data->state.wildcardmatch) {
3182 if(data->set.chunk_end && ftpc->file) {
3183 Curl_set_in_callback(data, true);
3184 data->set.chunk_end(data->wildcard.customptr);
3185 Curl_set_in_callback(data, false);
3187 ftpc->known_filesize = -1;
3191 /* get the url-decoded "raw" path */
3192 result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen,
3195 /* We can limp along anyway (and should try to since we may already be in
3196 * the error path) */
3197 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3198 connclose(conn, "FTP: out of memory!"); /* mark for connection closure */
3199 free(ftpc->prevpath);
3200 ftpc->prevpath = NULL; /* no path remembering */
3202 else { /* remember working directory for connection reuse */
3203 if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/'))
3204 free(rawPath); /* full path => no CWDs happened => keep ftpc->prevpath */
3206 free(ftpc->prevpath);
3208 if(!ftpc->cwdfail) {
3209 if(data->set.ftp_filemethod == FTPFILE_NOCWD)
3210 pathLen = 0; /* relative path => working directory is FTP home */
3212 pathLen -= ftpc->file?strlen(ftpc->file):0; /* file is url-decoded */
3214 rawPath[pathLen] = '\0';
3215 ftpc->prevpath = rawPath;
3219 ftpc->prevpath = NULL; /* no path */
3224 infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
3227 /* free the dir tree and file parts */
3230 /* shut down the socket to inform the server we're done */
3233 shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */
3236 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3237 if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
3238 /* partial download completed */
3239 result = Curl_pp_sendf(pp, "%s", "ABOR");
3241 failf(data, "Failure sending ABOR command: %s",
3242 curl_easy_strerror(result));
3243 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3244 connclose(conn, "ABOR command failed"); /* connection closure */
3248 if(conn->ssl[SECONDARYSOCKET].use) {
3249 /* The secondary socket is using SSL so we must close down that part
3250 first before we close the socket for real */
3251 Curl_ssl_close(conn, SECONDARYSOCKET);
3253 /* Note that we keep "use" set to TRUE since that (next) connection is
3254 still requested to use SSL */
3256 close_secondarysocket(conn);
3259 if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
3260 pp->pending_resp && !premature) {
3262 * Let's see what the server says about the transfer we just performed,
3263 * but lower the timeout as sometimes this connection has died while the
3264 * data has been transferred. This happens when doing through NATs etc that
3265 * abandon old silent connections.
3267 timediff_t old_time = pp->response_time;
3269 pp->response_time = 60*1000; /* give it only a minute for now */
3270 pp->response = Curl_now(); /* timeout relative now */
3272 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3274 pp->response_time = old_time; /* set this back to previous value */
3276 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3277 failf(data, "control connection looks dead");
3278 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3279 connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
3285 if(ftpc->dont_check && data->req.maxdownload > 0) {
3286 /* we have just sent ABOR and there is no reliable way to check if it was
3287 * successful or not; we have to close the connection now */
3288 infof(data, "partial download completed, closing connection\n");
3289 connclose(conn, "Partial download with no ability to check");
3293 if(!ftpc->dont_check) {
3294 /* 226 Transfer complete, 250 Requested file action okay, completed. */
3300 failf(data, "Exceeded storage allocation");
3301 result = CURLE_REMOTE_DISK_FULL;
3304 failf(data, "server did not report OK, got %d", ftpcode);
3305 result = CURLE_PARTIAL_FILE;
3311 if(result || premature)
3312 /* the response code from the transfer showed an error already so no
3313 use checking further */
3315 else if(data->set.upload) {
3316 if((-1 != data->state.infilesize) &&
3317 (data->state.infilesize != data->req.writebytecount) &&
3319 (ftp->transfer == FTPTRANSFER_BODY)) {
3320 failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
3321 " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
3322 data->req.bytecount, data->state.infilesize);
3323 result = CURLE_PARTIAL_FILE;
3327 if((-1 != data->req.size) &&
3328 (data->req.size != data->req.bytecount) &&
3329 #ifdef CURL_DO_LINEEND_CONV
3330 /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3331 * we'll check to see if the discrepancy can be explained by the number
3332 * of CRLFs we've changed to LFs.
3334 ((data->req.size + data->state.crlf_conversions) !=
3335 data->req.bytecount) &&
3336 #endif /* CURL_DO_LINEEND_CONV */
3337 (data->req.maxdownload != data->req.bytecount)) {
3338 failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
3339 " bytes", data->req.bytecount);
3340 result = CURLE_PARTIAL_FILE;
3342 else if(!ftpc->dont_check &&
3343 !data->req.bytecount &&
3344 (data->req.size>0)) {
3345 failf(data, "No data was received!");
3346 result = CURLE_FTP_COULDNT_RETR_FILE;
3350 /* clear these for next connection */
3351 ftp->transfer = FTPTRANSFER_BODY;
3352 ftpc->dont_check = FALSE;
3354 /* Send any post-transfer QUOTE strings? */
3355 if(!status && !result && !premature && data->set.postquote)
3356 result = ftp_sendquote(conn, data->set.postquote);
3357 Curl_safefree(ftp->pathalloc);
3361 /***********************************************************************
3365 * Where a 'quote' means a list of custom commands to send to the server.
3366 * The quote list is passed as an argument.
3372 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
3374 struct curl_slist *item;
3375 struct ftp_conn *ftpc = &conn->proto.ftpc;
3376 struct pingpong *pp = &ftpc->pp;
3382 char *cmd = item->data;
3383 bool acceptfail = FALSE;
3387 /* if a command starts with an asterisk, which a legal FTP command never
3388 can, the command will be allowed to fail without it causing any
3389 aborts or cancels etc. It will cause libcurl to act as if the command
3390 is successful, whatever the server reponds. */
3397 result = Curl_pp_sendf(&ftpc->pp, "%s", cmd);
3399 pp->response = Curl_now(); /* timeout relative now */
3400 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3405 if(!acceptfail && (ftpcode >= 400)) {
3406 failf(conn->data, "QUOT string not accepted: %s", cmd);
3407 return CURLE_QUOTE_ERROR;
3417 /***********************************************************************
3421 * Returns TRUE if we in the current situation should send TYPE
3423 static int ftp_need_type(struct connectdata *conn,
3426 return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3429 /***********************************************************************
3433 * Set TYPE. We only deal with ASCII or BINARY so this function
3435 * If the transfer type is not sent, simulate on OK response in newstate
3437 static CURLcode ftp_nb_type(struct connectdata *conn,
3438 bool ascii, ftpstate newstate)
3440 struct ftp_conn *ftpc = &conn->proto.ftpc;
3442 char want = (char)(ascii?'A':'I');
3444 if(ftpc->transfertype == want) {
3445 state(conn, newstate);
3446 return ftp_state_type_resp(conn, 200, newstate);
3449 result = Curl_pp_sendf(&ftpc->pp, "TYPE %c", want);
3451 state(conn, newstate);
3453 /* keep track of our current transfer type */
3454 ftpc->transfertype = want;
3459 /***************************************************************************
3461 * ftp_pasv_verbose()
3463 * This function only outputs some informationals about this second connection
3464 * when we've issued a PASV command before and thus we have connected to a
3465 * possibly new IP address.
3468 #ifndef CURL_DISABLE_VERBOSE_STRINGS
3470 ftp_pasv_verbose(struct connectdata *conn,
3471 struct Curl_addrinfo *ai,
3472 char *newhost, /* ascii version */
3476 Curl_printable_address(ai, buf, sizeof(buf));
3477 infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3484 * This function shall be called when the second FTP (data) connection is
3487 * 'complete' can return 0 for incomplete, 1 for done and -1 for go back
3488 * (which basically is only for when PASV is being sent to retry a failed
3492 static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
3494 struct Curl_easy *data = conn->data;
3495 struct ftp_conn *ftpc = &conn->proto.ftpc;
3496 CURLcode result = CURLE_OK;
3497 bool connected = FALSE;
3498 bool complete = FALSE;
3500 /* the ftp struct is inited in ftp_connect() */
3501 struct FTP *ftp = data->req.protop;
3503 /* if the second connection isn't done yet, wait for it */
3504 if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
3505 if(Curl_connect_ongoing(conn)) {
3506 /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
3507 aren't used so we blank their arguments. */
3508 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
3513 result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
3515 /* Ready to do more? */
3517 DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
3520 if(result && (ftpc->count1 == 0)) {
3521 *completep = -1; /* go back to DOING please */
3522 /* this is a EPSV connect failing, try PASV instead */
3523 return ftp_epsv_disable(conn);
3529 #ifndef CURL_DISABLE_PROXY
3530 result = Curl_proxy_connect(conn, SECONDARYSOCKET);
3534 if(CONNECT_SECONDARYSOCKET_PROXY_SSL())
3537 if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
3538 Curl_connect_ongoing(conn))
3543 /* already in a state so skip the initial commands.
3544 They are only done to kickstart the do_more state */
3545 result = ftp_multi_statemach(conn, &complete);
3547 *completep = (int)complete;
3549 /* if we got an error or if we don't wait for a data connection return
3551 if(result || !ftpc->wait_data_conn)
3554 /* if we reach the end of the FTP state machine here, *complete will be
3555 TRUE but so is ftpc->wait_data_conn, which says we need to wait for the
3556 data connection and therefore we're not actually complete */
3560 if(ftp->transfer <= FTPTRANSFER_INFO) {
3561 /* a transfer is about to take place, or if not a file name was given
3562 so we'll do a SIZE on it later and then we need the right TYPE first */
3564 if(ftpc->wait_data_conn == TRUE) {
3567 result = ReceivedServerConnect(conn, &serv_conned);
3569 return result; /* Failed to accept data connection */
3572 /* It looks data connection is established */
3573 result = AcceptServerConnect(conn);
3574 ftpc->wait_data_conn = FALSE;
3576 result = InitiateTransfer(conn);
3581 *completep = 1; /* this state is now complete when the server has
3582 connected back to us */
3585 else if(data->set.upload) {
3586 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
3590 result = ftp_multi_statemach(conn, &complete);
3591 /* ftpc->wait_data_conn is always false here */
3592 *completep = (int)complete;
3596 ftp->downloadsize = -1; /* unknown as of yet */
3598 result = Curl_range(conn);
3600 if(result == CURLE_OK && data->req.maxdownload >= 0) {
3601 /* Don't check for successful transfer */
3602 ftpc->dont_check = TRUE;
3607 else if(data->set.ftp_list_only || !ftpc->file) {
3608 /* The specified path ends with a slash, and therefore we think this
3609 is a directory that is requested, use LIST. But before that we
3610 need to set ASCII transfer mode. */
3612 /* But only if a body transfer was requested. */
3613 if(ftp->transfer == FTPTRANSFER_BODY) {
3614 result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
3618 /* otherwise just fall through */
3621 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
3626 result = ftp_multi_statemach(conn, &complete);
3627 *completep = (int)complete;
3632 /* no data to transfer */
3633 Curl_setup_transfer(data, -1, -1, FALSE, -1);
3635 if(!ftpc->wait_data_conn) {
3636 /* no waiting for the data connection so this is now complete */
3638 DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
3646 /***********************************************************************
3650 * This is the actual DO function for FTP. Get a file/directory according to
3651 * the options previously setup.
3655 CURLcode ftp_perform(struct connectdata *conn,
3656 bool *connected, /* connect status after PASV / PORT */
3659 /* this is FTP and no proxy */
3660 CURLcode result = CURLE_OK;
3662 DEBUGF(infof(conn->data, "DO phase starts\n"));
3664 if(conn->data->set.opt_no_body) {
3665 /* requested no body means no transfer... */
3666 struct FTP *ftp = conn->data->req.protop;
3667 ftp->transfer = FTPTRANSFER_INFO;
3670 *dophase_done = FALSE; /* not done yet */
3672 /* start the first command in the DO phase */
3673 result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
3677 /* run the state-machine */
3678 result = ftp_multi_statemach(conn, dophase_done);
3680 *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
3682 infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected);
3685 DEBUGF(infof(conn->data, "DO phase is complete1\n"));
3690 static void wc_data_dtor(void *ptr)
3692 struct ftp_wc *ftpwc = ptr;
3693 if(ftpwc && ftpwc->parser)
3694 Curl_ftp_parselist_data_free(&ftpwc->parser);
3698 static CURLcode init_wc_data(struct connectdata *conn)
3701 struct FTP *ftp = conn->data->req.protop;
3702 char *path = ftp->path;
3703 struct WildcardData *wildcard = &(conn->data->wildcard);
3704 CURLcode result = CURLE_OK;
3705 struct ftp_wc *ftpwc = NULL;
3707 last_slash = strrchr(ftp->path, '/');
3710 if(last_slash[0] == '\0') {
3711 wildcard->state = CURLWC_CLEAN;
3712 result = ftp_parse_url_path(conn);
3715 wildcard->pattern = strdup(last_slash);
3716 if(!wildcard->pattern)
3717 return CURLE_OUT_OF_MEMORY;
3718 last_slash[0] = '\0'; /* cut file from path */
3720 else { /* there is only 'wildcard pattern' or nothing */
3722 wildcard->pattern = strdup(path);
3723 if(!wildcard->pattern)
3724 return CURLE_OUT_OF_MEMORY;
3727 else { /* only list */
3728 wildcard->state = CURLWC_CLEAN;
3729 result = ftp_parse_url_path(conn);
3734 /* program continues only if URL is not ending with slash, allocate needed
3735 resources for wildcard transfer */
3737 /* allocate ftp protocol specific wildcard data */
3738 ftpwc = calloc(1, sizeof(struct ftp_wc));
3740 result = CURLE_OUT_OF_MEMORY;
3744 /* INITIALIZE parselist structure */
3745 ftpwc->parser = Curl_ftp_parselist_data_alloc();
3746 if(!ftpwc->parser) {
3747 result = CURLE_OUT_OF_MEMORY;
3751 wildcard->protdata = ftpwc; /* put it to the WildcardData tmp pointer */
3752 wildcard->dtor = wc_data_dtor;
3754 /* wildcard does not support NOCWD option (assert it?) */
3755 if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
3756 conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
3758 /* try to parse ftp url */
3759 result = ftp_parse_url_path(conn);
3764 wildcard->path = strdup(ftp->path);
3765 if(!wildcard->path) {
3766 result = CURLE_OUT_OF_MEMORY;
3770 /* backup old write_function */
3771 ftpwc->backup.write_function = conn->data->set.fwrite_func;
3772 /* parsing write function */
3773 conn->data->set.fwrite_func = Curl_ftp_parselist;
3774 /* backup old file descriptor */
3775 ftpwc->backup.file_descriptor = conn->data->set.out;
3776 /* let the writefunc callback know what curl pointer is working with */
3777 conn->data->set.out = conn;
3779 infof(conn->data, "Wildcard - Parsing started\n");
3784 Curl_ftp_parselist_data_free(&ftpwc->parser);
3787 Curl_safefree(wildcard->pattern);
3788 wildcard->dtor = ZERO_NULL;
3789 wildcard->protdata = NULL;
3793 /* This is called recursively */
3794 static CURLcode wc_statemach(struct connectdata *conn)
3796 struct WildcardData * const wildcard = &(conn->data->wildcard);
3797 CURLcode result = CURLE_OK;
3799 switch(wildcard->state) {
3801 result = init_wc_data(conn);
3802 if(wildcard->state == CURLWC_CLEAN)
3805 wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
3808 case CURLWC_MATCHING: {
3809 /* In this state is LIST response successfully parsed, so lets restore
3810 previous WRITEFUNCTION callback and WRITEDATA pointer */
3811 struct ftp_wc *ftpwc = wildcard->protdata;
3812 conn->data->set.fwrite_func = ftpwc->backup.write_function;
3813 conn->data->set.out = ftpwc->backup.file_descriptor;
3814 ftpwc->backup.write_function = ZERO_NULL;
3815 ftpwc->backup.file_descriptor = NULL;
3816 wildcard->state = CURLWC_DOWNLOADING;
3818 if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
3819 /* error found in LIST parsing */
3820 wildcard->state = CURLWC_CLEAN;
3821 return wc_statemach(conn);
3823 if(wildcard->filelist.size == 0) {
3824 /* no corresponding file */
3825 wildcard->state = CURLWC_CLEAN;
3826 return CURLE_REMOTE_FILE_NOT_FOUND;
3828 return wc_statemach(conn);
3831 case CURLWC_DOWNLOADING: {
3832 /* filelist has at least one file, lets get first one */
3833 struct ftp_conn *ftpc = &conn->proto.ftpc;
3834 struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
3835 struct FTP *ftp = conn->data->req.protop;
3837 char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
3839 return CURLE_OUT_OF_MEMORY;
3841 /* switch default ftp->path and tmp_path */
3842 free(ftp->pathalloc);
3843 ftp->pathalloc = ftp->path = tmp_path;
3845 infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
3846 if(conn->data->set.chunk_bgn) {
3848 Curl_set_in_callback(conn->data, true);
3849 userresponse = conn->data->set.chunk_bgn(
3850 finfo, wildcard->customptr, (int)wildcard->filelist.size);
3851 Curl_set_in_callback(conn->data, false);
3852 switch(userresponse) {
3853 case CURL_CHUNK_BGN_FUNC_SKIP:
3854 infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
3856 wildcard->state = CURLWC_SKIP;
3857 return wc_statemach(conn);
3858 case CURL_CHUNK_BGN_FUNC_FAIL:
3859 return CURLE_CHUNK_FAILED;
3863 if(finfo->filetype != CURLFILETYPE_FILE) {
3864 wildcard->state = CURLWC_SKIP;
3865 return wc_statemach(conn);
3868 if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
3869 ftpc->known_filesize = finfo->size;
3871 result = ftp_parse_url_path(conn);
3875 /* we don't need the Curl_fileinfo of first file anymore */
3876 Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
3878 if(wildcard->filelist.size == 0) { /* remains only one file to down. */
3879 wildcard->state = CURLWC_CLEAN;
3880 /* after that will be ftp_do called once again and no transfer
3881 will be done because of CURLWC_CLEAN state */
3887 if(conn->data->set.chunk_end) {
3888 Curl_set_in_callback(conn->data, true);
3889 conn->data->set.chunk_end(conn->data->wildcard.customptr);
3890 Curl_set_in_callback(conn->data, false);
3892 Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
3893 wildcard->state = (wildcard->filelist.size == 0) ?
3894 CURLWC_CLEAN : CURLWC_DOWNLOADING;
3895 return wc_statemach(conn);
3898 case CURLWC_CLEAN: {
3899 struct ftp_wc *ftpwc = wildcard->protdata;
3902 result = Curl_ftp_parselist_geterror(ftpwc->parser);
3904 wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
3911 wildcard->dtor(wildcard->protdata);
3918 /***********************************************************************
3922 * This function is registered as 'curl_do' function. It decodes the path
3923 * parts etc as a wrapper to the actual DO function (ftp_perform).
3925 * The input argument is already checked for validity.
3927 static CURLcode ftp_do(struct connectdata *conn, bool *done)
3929 CURLcode result = CURLE_OK;
3930 struct ftp_conn *ftpc = &conn->proto.ftpc;
3932 *done = FALSE; /* default to false */
3933 ftpc->wait_data_conn = FALSE; /* default to no such wait */
3935 if(conn->data->state.wildcardmatch) {
3936 result = wc_statemach(conn);
3937 if(conn->data->wildcard.state == CURLWC_SKIP ||
3938 conn->data->wildcard.state == CURLWC_DONE) {
3939 /* do not call ftp_regular_transfer */
3942 if(result) /* error, loop or skipping the file */
3945 else { /* no wildcard FSM needed */
3946 result = ftp_parse_url_path(conn);
3951 result = ftp_regular_transfer(conn, done);
3956 /***********************************************************************
3960 * This should be called before calling sclose() on an ftp control connection
3961 * (not data connections). We should then wait for the response from the
3962 * server before returning. The calling code should then try to close the
3966 static CURLcode ftp_quit(struct connectdata *conn)
3968 CURLcode result = CURLE_OK;
3970 if(conn->proto.ftpc.ctl_valid) {
3971 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT");
3973 failf(conn->data, "Failure sending QUIT command: %s",
3974 curl_easy_strerror(result));
3975 conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
3976 connclose(conn, "QUIT command failed"); /* mark for connection closure */
3977 state(conn, FTP_STOP);
3981 state(conn, FTP_QUIT);
3983 result = ftp_block_statemach(conn);
3989 /***********************************************************************
3993 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
3994 * resources. BLOCKING.
3996 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
3998 struct ftp_conn *ftpc = &conn->proto.ftpc;
3999 struct pingpong *pp = &ftpc->pp;
4001 /* We cannot send quit unconditionally. If this connection is stale or
4002 bad in any way, sending quit and waiting around here will make the
4003 disconnect wait in vain and cause more problems than we need to.
4005 ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
4006 will try to send the QUIT command, otherwise it will just return.
4009 ftpc->ctl_valid = FALSE;
4011 /* The FTP session may or may not have been allocated/setup at this point! */
4012 (void)ftp_quit(conn); /* ignore errors on the QUIT */
4014 if(ftpc->entrypath) {
4015 struct Curl_easy *data = conn->data;
4016 if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
4017 data->state.most_recent_ftp_entrypath = NULL;
4019 Curl_safefree(ftpc->entrypath);
4023 Curl_safefree(ftpc->prevpath);
4024 Curl_safefree(ftpc->server_os);
4025 Curl_pp_disconnect(pp);
4030 /***********************************************************************
4032 * ftp_parse_url_path()
4034 * Parse the URL path into separate path components.
4038 CURLcode ftp_parse_url_path(struct connectdata *conn)
4040 struct Curl_easy *data = conn->data;
4041 /* the ftp struct is already inited in ftp_connect() */
4042 struct FTP *ftp = data->req.protop;
4043 struct ftp_conn *ftpc = &conn->proto.ftpc;
4044 const char *slashPos = NULL;
4045 const char *fileName = NULL;
4046 CURLcode result = CURLE_OK;
4047 char *rawPath = NULL; /* url-decoded "raw" path */
4050 ftpc->ctl_valid = FALSE;
4051 ftpc->cwdfail = FALSE;
4053 /* url-decode ftp path before further evaluation */
4054 result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen, REJECT_CTRL);
4058 switch(data->set.ftp_filemethod) {
4059 case FTPFILE_NOCWD: /* fastest, but less standard-compliant */
4061 if((pathLen > 0) && (rawPath[pathLen - 1] != '/'))
4062 fileName = rawPath; /* this is a full file path */
4064 else: ftpc->file is not used anywhere other than for operations on
4065 a file. In other words, never for directory operations.
4066 So we can safely leave filename as NULL here and use it as a
4067 argument in dir/file decisions.
4071 case FTPFILE_SINGLECWD:
4072 slashPos = strrchr(rawPath, '/');
4074 /* get path before last slash, except for / */
4075 size_t dirlen = slashPos - rawPath;
4079 ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
4082 return CURLE_OUT_OF_MEMORY;
4085 ftpc->dirs[0] = calloc(1, dirlen + 1);
4086 if(!ftpc->dirs[0]) {
4088 return CURLE_OUT_OF_MEMORY;
4091 strncpy(ftpc->dirs[0], rawPath, dirlen);
4092 ftpc->dirdepth = 1; /* we consider it to be a single dir */
4093 fileName = slashPos + 1; /* rest is file name */
4096 fileName = rawPath; /* file name only (or empty) */
4099 default: /* allow pretty much anything */
4100 case FTPFILE_MULTICWD: {
4101 /* current position: begin of next path component */
4102 const char *curPos = rawPath;
4104 int dirAlloc = 0; /* number of entries allocated for the 'dirs' array */
4105 const char *str = rawPath;
4106 for(; *str != 0; ++str)
4111 ftpc->dirs = calloc(dirAlloc, sizeof(ftpc->dirs[0]));
4114 return CURLE_OUT_OF_MEMORY;
4117 /* parse the URL path into separate path components */
4118 while((slashPos = strchr(curPos, '/')) != NULL) {
4119 size_t compLen = slashPos - curPos;
4121 /* path starts with a slash: add that as a directory */
4122 if((compLen == 0) && (ftpc->dirdepth == 0))
4125 /* we skip empty path components, like "x//y" since the FTP command
4126 CWD requires a parameter and a non-existent parameter a) doesn't
4127 work on many servers and b) has no effect on the others. */
4129 char *comp = calloc(1, compLen + 1);
4132 return CURLE_OUT_OF_MEMORY;
4134 strncpy(comp, curPos, compLen);
4135 ftpc->dirs[ftpc->dirdepth++] = comp;
4137 curPos = slashPos + 1;
4140 DEBUGASSERT(ftpc->dirdepth <= dirAlloc);
4141 fileName = curPos; /* the rest is the file name (or empty) */
4146 if(fileName && *fileName)
4147 ftpc->file = strdup(fileName);
4149 ftpc->file = NULL; /* instead of point to a zero byte,
4150 we make it a NULL pointer */
4152 if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
4153 /* We need a file name when uploading. Return error! */
4154 failf(data, "Uploading to a URL without a file name!");
4156 return CURLE_URL_MALFORMAT;
4159 ftpc->cwddone = FALSE; /* default to not done */
4161 if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/'))
4162 ftpc->cwddone = TRUE; /* skip CWD for absolute paths */
4163 else { /* newly created FTP connections are already in entry path */
4164 const char *oldPath = conn->bits.reuse ? ftpc->prevpath : "";
4167 if(data->set.ftp_filemethod == FTPFILE_NOCWD)
4168 n = 0; /* CWD to entry for relative paths */
4170 n -= ftpc->file?strlen(ftpc->file):0;
4172 if((strlen(oldPath) == n) && !strncmp(rawPath, oldPath, n)) {
4173 infof(data, "Request has same path as previous transfer\n");
4174 ftpc->cwddone = TRUE;
4183 /* call this when the DO phase has completed */
4184 static CURLcode ftp_dophase_done(struct connectdata *conn,
4187 struct FTP *ftp = conn->data->req.protop;
4188 struct ftp_conn *ftpc = &conn->proto.ftpc;
4192 CURLcode result = ftp_do_more(conn, &completed);
4195 close_secondarysocket(conn);
4200 if(ftp->transfer != FTPTRANSFER_BODY)
4201 /* no data to transfer */
4202 Curl_setup_transfer(conn->data, -1, -1, FALSE, -1);
4204 /* since we didn't connect now, we want do_more to get called */
4205 conn->bits.do_more = TRUE;
4207 ftpc->ctl_valid = TRUE; /* seems good */
4212 /* called from multi.c while DOing */
4213 static CURLcode ftp_doing(struct connectdata *conn,
4216 CURLcode result = ftp_multi_statemach(conn, dophase_done);
4219 DEBUGF(infof(conn->data, "DO phase failed\n"));
4220 else if(*dophase_done) {
4221 result = ftp_dophase_done(conn, FALSE /* not connected */);
4223 DEBUGF(infof(conn->data, "DO phase is complete2\n"));
4228 /***********************************************************************
4230 * ftp_regular_transfer()
4232 * The input argument is already checked for validity.
4234 * Performs all commands done before a regular transfer between a local and a
4237 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
4238 * ftp_done() function without finding any major problem.
4241 CURLcode ftp_regular_transfer(struct connectdata *conn,
4244 CURLcode result = CURLE_OK;
4245 bool connected = FALSE;
4246 struct Curl_easy *data = conn->data;
4247 struct ftp_conn *ftpc = &conn->proto.ftpc;
4248 data->req.size = -1; /* make sure this is unknown at this point */
4250 Curl_pgrsSetUploadCounter(data, 0);
4251 Curl_pgrsSetDownloadCounter(data, 0);
4252 Curl_pgrsSetUploadSize(data, -1);
4253 Curl_pgrsSetDownloadSize(data, -1);
4255 ftpc->ctl_valid = TRUE; /* starts good */
4257 result = ftp_perform(conn,
4258 &connected, /* have we connected after PASV/PORT */
4259 dophase_done); /* all commands in the DO-phase done? */
4264 /* the DO phase has not completed yet */
4267 result = ftp_dophase_done(conn, connected);
4278 static CURLcode ftp_setup_connection(struct connectdata *conn)
4280 struct Curl_easy *data = conn->data;
4284 conn->data->req.protop = ftp = calloc(sizeof(struct FTP), 1);
4286 return CURLE_OUT_OF_MEMORY;
4288 ftp->path = &data->state.up.path[1]; /* don't include the initial slash */
4290 /* FTP URLs support an extension like ";type=<typecode>" that
4291 * we'll try to get now! */
4292 type = strstr(ftp->path, ";type=");
4295 type = strstr(conn->host.rawalloc, ";type=");
4299 *type = 0; /* it was in the middle of the hostname */
4300 command = Curl_raw_toupper(type[6]);
4303 case 'A': /* ASCII mode */
4304 data->set.prefer_ascii = TRUE;
4307 case 'D': /* directory mode */
4308 data->set.ftp_list_only = TRUE;
4311 case 'I': /* binary mode */
4313 /* switch off ASCII */
4314 data->set.prefer_ascii = FALSE;
4319 /* get some initial data into the ftp struct */
4320 ftp->transfer = FTPTRANSFER_BODY;
4321 ftp->downloadsize = 0;
4322 conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
4327 #endif /* CURL_DISABLE_FTP */