1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2022, 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.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"
80 /* The last 3 #include files should be in this order */
81 #include "curl_printf.h"
82 #include "curl_memory.h"
86 #define NI_MAXHOST 1025
88 #ifndef INET_ADDRSTRLEN
89 #define INET_ADDRSTRLEN 16
92 #ifdef CURL_DISABLE_VERBOSE_STRINGS
93 #define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt
96 /* Local API functions */
98 static void _state(struct Curl_easy *data,
100 #define state(x,y) _state(x,y)
102 static void _state(struct Curl_easy *data,
105 #define state(x,y) _state(x,y,__LINE__)
108 static CURLcode ftp_sendquote(struct Curl_easy *data,
109 struct connectdata *conn,
110 struct curl_slist *quote);
111 static CURLcode ftp_quit(struct Curl_easy *data, struct connectdata *conn);
112 static CURLcode ftp_parse_url_path(struct Curl_easy *data);
113 static CURLcode ftp_regular_transfer(struct Curl_easy *data, bool *done);
114 #ifndef CURL_DISABLE_VERBOSE_STRINGS
115 static void ftp_pasv_verbose(struct Curl_easy *data,
116 struct Curl_addrinfo *ai,
117 char *newhost, /* ascii version */
120 static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data);
121 static CURLcode ftp_state_mdtm(struct Curl_easy *data);
122 static CURLcode ftp_state_quote(struct Curl_easy *data,
123 bool init, ftpstate instate);
124 static CURLcode ftp_nb_type(struct Curl_easy *data,
125 struct connectdata *conn,
126 bool ascii, ftpstate newstate);
127 static int ftp_need_type(struct connectdata *conn,
129 static CURLcode ftp_do(struct Curl_easy *data, bool *done);
130 static CURLcode ftp_done(struct Curl_easy *data,
131 CURLcode, bool premature);
132 static CURLcode ftp_connect(struct Curl_easy *data, bool *done);
133 static CURLcode ftp_disconnect(struct Curl_easy *data,
134 struct connectdata *conn, bool dead_connection);
135 static CURLcode ftp_do_more(struct Curl_easy *data, int *completed);
136 static CURLcode ftp_multi_statemach(struct Curl_easy *data, bool *done);
137 static int ftp_getsock(struct Curl_easy *data, struct connectdata *conn,
138 curl_socket_t *socks);
139 static int ftp_domore_getsock(struct Curl_easy *data,
140 struct connectdata *conn, curl_socket_t *socks);
141 static CURLcode ftp_doing(struct Curl_easy *data,
143 static CURLcode ftp_setup_connection(struct Curl_easy *data,
144 struct connectdata *conn);
145 static CURLcode init_wc_data(struct Curl_easy *data);
146 static CURLcode wc_statemach(struct Curl_easy *data);
147 static void wc_data_dtor(void *ptr);
148 static CURLcode ftp_state_retr(struct Curl_easy *data, curl_off_t filesize);
149 static CURLcode ftp_readresp(struct Curl_easy *data,
150 curl_socket_t sockfd,
154 static CURLcode ftp_dophase_done(struct Curl_easy *data,
158 * FTP protocol handler.
161 const struct Curl_handler Curl_handler_ftp = {
163 ftp_setup_connection, /* setup_connection */
166 ftp_do_more, /* do_more */
167 ftp_connect, /* connect_it */
168 ftp_multi_statemach, /* connecting */
169 ftp_doing, /* doing */
170 ftp_getsock, /* proto_getsock */
171 ftp_getsock, /* doing_getsock */
172 ftp_domore_getsock, /* domore_getsock */
173 ZERO_NULL, /* perform_getsock */
174 ftp_disconnect, /* disconnect */
175 ZERO_NULL, /* readwrite */
176 ZERO_NULL, /* connection_check */
177 ZERO_NULL, /* attach connection */
178 PORT_FTP, /* defport */
179 CURLPROTO_FTP, /* protocol */
180 CURLPROTO_FTP, /* family */
181 PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD |
182 PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP |
183 PROTOPT_WILDCARD /* flags */
189 * FTPS protocol handler.
192 const struct Curl_handler Curl_handler_ftps = {
194 ftp_setup_connection, /* setup_connection */
197 ftp_do_more, /* do_more */
198 ftp_connect, /* connect_it */
199 ftp_multi_statemach, /* connecting */
200 ftp_doing, /* doing */
201 ftp_getsock, /* proto_getsock */
202 ftp_getsock, /* doing_getsock */
203 ftp_domore_getsock, /* domore_getsock */
204 ZERO_NULL, /* perform_getsock */
205 ftp_disconnect, /* disconnect */
206 ZERO_NULL, /* readwrite */
207 ZERO_NULL, /* connection_check */
208 ZERO_NULL, /* attach connection */
209 PORT_FTPS, /* defport */
210 CURLPROTO_FTPS, /* protocol */
211 CURLPROTO_FTP, /* family */
212 PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
213 PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_WILDCARD /* flags */
217 static void close_secondarysocket(struct Curl_easy *data,
218 struct connectdata *conn)
220 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
221 Curl_closesocket(data, conn, conn->sock[SECONDARYSOCKET]);
222 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
224 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
225 #ifndef CURL_DISABLE_PROXY
226 conn->bits.proxy_ssl_connected[SECONDARYSOCKET] = FALSE;
231 * NOTE: back in the old days, we added code in the FTP code that made NOBODY
232 * requests on files respond with headers passed to the client/stdout that
233 * looked like HTTP ones.
235 * This approach is not very elegant, it causes confusion and is error-prone.
236 * It is subject for removal at the next (or at least a future) soname bump.
237 * Until then you can test the effects of the removal by undefining the
238 * following define named CURL_FTP_HTTPSTYLE_HEAD.
240 #define CURL_FTP_HTTPSTYLE_HEAD 1
242 static void freedirs(struct ftp_conn *ftpc)
246 for(i = 0; i < ftpc->dirdepth; i++) {
248 ftpc->dirs[i] = NULL;
254 Curl_safefree(ftpc->file);
256 /* no longer of any use */
257 Curl_safefree(ftpc->newhost);
260 /***********************************************************************
262 * AcceptServerConnect()
264 * After connection request is received from the server this function is
265 * called to accept the connection and close the listening socket
268 static CURLcode AcceptServerConnect(struct Curl_easy *data)
270 struct connectdata *conn = data->conn;
271 curl_socket_t sock = conn->sock[SECONDARYSOCKET];
272 curl_socket_t s = CURL_SOCKET_BAD;
274 struct Curl_sockaddr_storage add;
276 struct sockaddr_in add;
278 curl_socklen_t size = (curl_socklen_t) sizeof(add);
280 if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
283 s = accept(sock, (struct sockaddr *) &add, &size);
285 Curl_closesocket(data, conn, sock); /* close the first socket */
287 if(CURL_SOCKET_BAD == s) {
288 failf(data, "Error accept()ing server connect");
289 return CURLE_FTP_PORT_FAILED;
291 infof(data, "Connection accepted from server");
292 /* when this happens within the DO state it is important that we mark us as
293 not needing DO_MORE anymore */
294 conn->bits.do_more = FALSE;
296 conn->sock[SECONDARYSOCKET] = s;
297 (void)curlx_nonblock(s, TRUE); /* enable non-blocking */
298 conn->bits.sock_accepted = TRUE;
300 if(data->set.fsockopt) {
303 /* activate callback for setting socket options */
304 Curl_set_in_callback(data, true);
305 error = data->set.fsockopt(data->set.sockopt_client,
307 CURLSOCKTYPE_ACCEPT);
308 Curl_set_in_callback(data, false);
311 close_secondarysocket(data, conn);
312 return CURLE_ABORTED_BY_CALLBACK;
321 * ftp_timeleft_accept() returns the amount of milliseconds left allowed for
322 * waiting server to connect. If the value is negative, the timeout time has
325 * The start time is stored in progress.t_acceptdata - as set with
326 * Curl_pgrsTime(..., TIMER_STARTACCEPT);
329 static timediff_t ftp_timeleft_accept(struct Curl_easy *data)
331 timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
335 if(data->set.accepttimeout > 0)
336 timeout_ms = data->set.accepttimeout;
340 /* check if the generic timeout possibly is set shorter */
341 other = Curl_timeleft(data, &now, FALSE);
342 if(other && (other < timeout_ms))
343 /* note that this also works fine for when other happens to be negative
344 due to it already having elapsed */
347 /* subtract elapsed time */
348 timeout_ms -= Curl_timediff(now, data->progress.t_acceptdata);
350 /* avoid returning 0 as that means no timeout! */
358 /***********************************************************************
360 * ReceivedServerConnect()
362 * After allowing server to connect to us from data port, this function
363 * checks both data connection for connection establishment and ctrl
364 * connection for a negative response regarding a failure in connecting
367 static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
369 struct connectdata *conn = data->conn;
370 curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
371 curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
372 struct ftp_conn *ftpc = &conn->proto.ftpc;
373 struct pingpong *pp = &ftpc->pp;
375 timediff_t timeout_ms;
381 timeout_ms = ftp_timeleft_accept(data);
382 infof(data, "Checking for server connect");
384 /* if a timeout was already reached, bail out */
385 failf(data, "Accept timeout occurred while waiting server connect");
386 return CURLE_FTP_ACCEPT_TIMEOUT;
389 /* First check whether there is a cached response from server */
390 if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
391 /* Data connection could not be established, let's return */
392 infof(data, "There is negative response in cache while serv connect");
393 (void)Curl_GetFTPResponse(data, &nread, &ftpcode);
394 return CURLE_FTP_ACCEPT_FAILED;
397 result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
399 /* see if the connection request is already here */
403 failf(data, "Error while waiting for server connect");
404 return CURLE_FTP_ACCEPT_FAILED;
405 case 0: /* Server connect is not received yet */
409 if(result & CURL_CSELECT_IN2) {
410 infof(data, "Ready to accept data connection from server");
413 else if(result & CURL_CSELECT_IN) {
414 infof(data, "Ctrl conn has data while waiting for data conn");
415 (void)Curl_GetFTPResponse(data, &nread, &ftpcode);
418 return CURLE_FTP_ACCEPT_FAILED;
420 return CURLE_WEIRD_SERVER_REPLY;
430 /***********************************************************************
434 * After connection from server is accepted this function is called to
435 * setup transfer parameters and initiate the data transfer.
438 static CURLcode InitiateTransfer(struct Curl_easy *data)
440 CURLcode result = CURLE_OK;
441 struct connectdata *conn = data->conn;
443 if(conn->bits.ftp_use_data_ssl) {
444 /* since we only have a plaintext TCP connection here, we must now
445 * do the TLS stuff */
446 infof(data, "Doing the SSL/TLS handshake on the data stream");
447 result = Curl_ssl_connect(data, conn, SECONDARYSOCKET);
452 if(conn->proto.ftpc.state_saved == FTP_STOR) {
453 /* When we know we're uploading a specified file, we can get the file
454 size prior to the actual upload. */
455 Curl_pgrsSetUploadSize(data, data->state.infilesize);
457 /* set the SO_SNDBUF for the secondary socket for those who need it */
458 Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
460 Curl_setup_transfer(data, -1, -1, FALSE, SECONDARYSOCKET);
464 Curl_setup_transfer(data, SECONDARYSOCKET,
465 conn->proto.ftpc.retr_size_saved, FALSE, -1);
468 conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
469 state(data, FTP_STOP);
474 /***********************************************************************
476 * AllowServerConnect()
478 * When we've issue the PORT command, we have told the server to connect to
479 * us. This function checks whether data connection is established if so it is
483 static CURLcode AllowServerConnect(struct Curl_easy *data, bool *connected)
485 timediff_t timeout_ms;
486 CURLcode result = CURLE_OK;
489 infof(data, "Preparing for accepting server on data port");
491 /* Save the time we start accepting server connect */
492 Curl_pgrsTime(data, TIMER_STARTACCEPT);
494 timeout_ms = ftp_timeleft_accept(data);
496 /* if a timeout was already reached, bail out */
497 failf(data, "Accept timeout occurred while waiting server connect");
498 return CURLE_FTP_ACCEPT_TIMEOUT;
501 /* see if the connection request is already here */
502 result = ReceivedServerConnect(data, connected);
507 result = AcceptServerConnect(data);
511 result = InitiateTransfer(data);
516 /* Add timeout to multi handle and break out of the loop */
517 if(*connected == FALSE) {
518 Curl_expire(data, data->set.accepttimeout > 0 ?
519 data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, 0);
526 /* macro to check for a three-digit ftp status code at the start of the
528 #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
531 /* macro to check for the last line in an FTP server response */
532 #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
534 static bool ftp_endofresp(struct Curl_easy *data, struct connectdata *conn,
535 char *line, size_t len, int *code)
540 if((len > 3) && LASTLINE(line)) {
541 *code = curlx_sltosi(strtol(line, NULL, 10));
548 static CURLcode ftp_readresp(struct Curl_easy *data,
549 curl_socket_t sockfd,
551 int *ftpcode, /* return the ftp-code if done */
552 size_t *size) /* size of the response */
555 CURLcode result = Curl_pp_readresp(data, sockfd, pp, &code, size);
559 struct connectdata *conn = data->conn;
560 char * const buf = data->state.buffer;
562 /* handle the security-oriented responses 6xx ***/
565 code = Curl_sec_read_msg(data, conn, buf, PROT_SAFE);
568 code = Curl_sec_read_msg(data, conn, buf, PROT_PRIVATE);
571 code = Curl_sec_read_msg(data, conn, buf, PROT_CONFIDENTIAL);
574 /* normal ftp stuff we pass through! */
580 /* store the latest code for later retrieval */
581 data->info.httpcode = code;
587 /* 421 means "Service not available, closing control connection." and FTP
588 * servers use it to signal that idle session timeout has been exceeded.
589 * If we ignored the response, it could end up hanging in some cases.
591 * This response code can come at any point so having it treated
592 * generically is a good idea.
594 infof(data, "We got a 421 - timeout");
595 state(data, FTP_STOP);
596 return CURLE_OPERATION_TIMEDOUT;
602 /* --- parse FTP server responses --- */
605 * Curl_GetFTPResponse() is a BLOCKING function to read the full response
606 * from a server after a command.
610 CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
611 ssize_t *nreadp, /* return number of bytes read */
612 int *ftpcode) /* return the ftp-code */
615 * We cannot read just one byte per read() and then go back to select() as
616 * the OpenSSL read() doesn't grok that properly.
618 * Alas, read as much as possible, split up into lines, use the ending
619 * line in a response or continue reading. */
621 struct connectdata *conn = data->conn;
622 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
623 CURLcode result = CURLE_OK;
624 struct ftp_conn *ftpc = &conn->proto.ftpc;
625 struct pingpong *pp = &ftpc->pp;
628 int value_to_be_ignored = 0;
631 *ftpcode = 0; /* 0 for errors */
633 /* make the pointer point to something for the rest of this function */
634 ftpcode = &value_to_be_ignored;
638 while(!*ftpcode && !result) {
639 /* check and reset timeout value every lap */
640 timediff_t timeout = Curl_pp_state_timeout(data, pp, FALSE);
641 timediff_t interval_ms;
644 failf(data, "FTP response timeout");
645 return CURLE_OPERATION_TIMEDOUT; /* already too little time */
648 interval_ms = 1000; /* use 1 second timeout intervals */
649 if(timeout < interval_ms)
650 interval_ms = timeout;
653 * Since this function is blocking, we need to wait here for input on the
654 * connection and only then we call the response reading function. We do
655 * timeout at least every second to make the timeout check run.
657 * A caution here is that the ftp_readresp() function has a cache that may
658 * contain pieces of a response from the previous invoke and we need to
659 * make sure we don't just wait for input while there is unhandled data in
660 * that cache. But also, if the cache is there, we call ftp_readresp() and
661 * the cache wasn't good enough to continue we must not just busy-loop
662 * around this function.
666 if(pp->cache && (cache_skip < 2)) {
668 * There's a cache left since before. We then skipping the wait for
669 * socket action, unless this is the same cache like the previous round
670 * as then the cache was deemed not enough to act on and we then need to
671 * wait for more data anyway.
674 else if(!Curl_conn_data_pending(conn, FIRSTSOCKET)) {
675 switch(SOCKET_READABLE(sockfd, interval_ms)) {
676 case -1: /* select() error, stop reading */
677 failf(data, "FTP response aborted due to select/poll error: %d",
679 return CURLE_RECV_ERROR;
681 case 0: /* timeout */
682 if(Curl_pgrsUpdate(data))
683 return CURLE_ABORTED_BY_CALLBACK;
684 continue; /* just continue in our loop for the timeout duration */
686 default: /* for clarity */
690 result = ftp_readresp(data, sockfd, pp, ftpcode, &nread);
694 if(!nread && pp->cache)
695 /* bump cache skip counter as on repeated skips we must wait for more
699 /* when we got data or there is no cache left, we reset the cache skip
705 } /* while there's buffer left and loop is requested */
707 pp->pending_resp = FALSE;
712 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
713 /* for debug purposes */
714 static const char * const ftp_state_names[]={
753 /* This is the ONLY way to change FTP state! */
754 static void _state(struct Curl_easy *data,
761 struct connectdata *conn = data->conn;
762 struct ftp_conn *ftpc = &conn->proto.ftpc;
764 #if defined(DEBUGBUILD)
766 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
769 if(ftpc->state != newstate)
770 infof(data, "FTP %p (line %d) state change from %s to %s",
771 (void *)ftpc, lineno, ftp_state_names[ftpc->state],
772 ftp_state_names[newstate]);
776 ftpc->state = newstate;
779 static CURLcode ftp_state_user(struct Curl_easy *data,
780 struct connectdata *conn)
782 CURLcode result = Curl_pp_sendf(data,
783 &conn->proto.ftpc.pp, "USER %s",
784 conn->user?conn->user:"");
786 state(data, FTP_USER);
787 data->state.ftp_trying_alternative = FALSE;
792 static CURLcode ftp_state_pwd(struct Curl_easy *data,
793 struct connectdata *conn)
795 CURLcode result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "PWD");
797 state(data, FTP_PWD);
802 /* For the FTP "protocol connect" and "doing" phases only */
803 static int ftp_getsock(struct Curl_easy *data,
804 struct connectdata *conn,
805 curl_socket_t *socks)
807 return Curl_pp_getsock(data, &conn->proto.ftpc.pp, socks);
810 /* For the FTP "DO_MORE" phase only */
811 static int ftp_domore_getsock(struct Curl_easy *data,
812 struct connectdata *conn, curl_socket_t *socks)
814 struct ftp_conn *ftpc = &conn->proto.ftpc;
817 /* When in DO_MORE state, we could be either waiting for us to connect to a
818 * remote site, or we could wait for that site to connect to us. Or just
819 * handle ordinary commands.
822 if(SOCKS_STATE(conn->cnnct.state))
823 return Curl_SOCKS_getsock(conn, socks, SECONDARYSOCKET);
825 if(FTP_STOP == ftpc->state) {
826 int bits = GETSOCK_READSOCK(0);
829 /* if stopped and still in this state, then we're also waiting for a
830 connect on the secondary connection */
831 socks[0] = conn->sock[FIRSTSOCKET];
833 if(!data->set.ftp_use_port) {
836 /* PORT is used to tell the server to connect to us, and during that we
837 don't do happy eyeballs, but we do if we connect to the server */
838 for(s = 1, i = 0; i<2; i++) {
839 if(conn->tempsock[i] != CURL_SOCKET_BAD) {
840 socks[s] = conn->tempsock[i];
841 bits |= GETSOCK_WRITESOCK(s++);
847 socks[1] = conn->sock[SECONDARYSOCKET];
848 bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1);
853 return Curl_pp_getsock(data, &conn->proto.ftpc.pp, socks);
856 /* This is called after the FTP_QUOTE state is passed.
858 ftp_state_cwd() sends the range of CWD commands to the server to change to
859 the correct directory. It may also need to send MKD commands to create
860 missing ones, if that option is enabled.
862 static CURLcode ftp_state_cwd(struct Curl_easy *data,
863 struct connectdata *conn)
865 CURLcode result = CURLE_OK;
866 struct ftp_conn *ftpc = &conn->proto.ftpc;
869 /* already done and fine */
870 result = ftp_state_mdtm(data);
872 /* FTPFILE_NOCWD with full path: expect ftpc->cwddone! */
873 DEBUGASSERT((data->set.ftp_filemethod != FTPFILE_NOCWD) ||
874 !(ftpc->dirdepth && ftpc->dirs[0][0] == '/'));
876 ftpc->count2 = 0; /* count2 counts failed CWDs */
878 if(conn->bits.reuse && ftpc->entrypath &&
879 /* no need to go to entrypath when we have an absolute path */
880 !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')) {
881 /* This is a re-used connection. Since we change directory to where the
882 transfer is taking place, we must first get back to the original dir
883 where we ended up after login: */
884 ftpc->cwdcount = 0; /* we count this as the first path, then we add one
885 for all upcoming ones in the ftp->dirs[] array */
886 result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", ftpc->entrypath);
888 state(data, FTP_CWD);
893 /* issue the first CWD, the rest is sent when the CWD responses are
895 result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s",
896 ftpc->dirs[ftpc->cwdcount -1]);
898 state(data, FTP_CWD);
901 /* No CWD necessary */
902 result = ftp_state_mdtm(data);
915 static CURLcode ftp_state_use_port(struct Curl_easy *data,
916 ftpport fcmd) /* start with this */
918 CURLcode result = CURLE_OK;
919 struct connectdata *conn = data->conn;
920 struct ftp_conn *ftpc = &conn->proto.ftpc;
921 curl_socket_t portsock = CURL_SOCKET_BAD;
922 char myhost[MAX_IPADR_LEN + 1] = "";
924 struct Curl_sockaddr_storage ss;
925 struct Curl_addrinfo *res, *ai;
926 curl_socklen_t sslen;
927 char hbuf[NI_MAXHOST];
928 struct sockaddr *sa = (struct sockaddr *)&ss;
929 struct sockaddr_in * const sa4 = (void *)sa;
931 struct sockaddr_in6 * const sa6 = (void *)sa;
933 static const char mode[][5] = { "EPRT", "PORT" };
937 char *string_ftpport = data->set.str[STRING_FTPPORT];
938 struct Curl_dns_entry *h = NULL;
939 unsigned short port_min = 0;
940 unsigned short port_max = 0;
942 bool possibly_non_local = TRUE;
943 char buffer[STRERROR_LEN];
946 /* Step 1, figure out what is requested,
948 * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
951 if(data->set.str[STRING_FTPPORT] &&
952 (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
955 size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
956 INET6_ADDRSTRLEN : strlen(string_ftpport);
958 size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
959 INET_ADDRSTRLEN : strlen(string_ftpport);
961 char *ip_start = string_ftpport;
963 char *port_start = NULL;
964 char *port_sep = NULL;
966 addr = calloc(addrlen + 1, 1);
968 return CURLE_OUT_OF_MEMORY;
971 if(*string_ftpport == '[') {
972 /* [ipv6]:port(-range) */
973 ip_start = string_ftpport + 1;
974 ip_end = strchr(string_ftpport, ']');
976 strncpy(addr, ip_start, ip_end - ip_start);
980 if(*string_ftpport == ':') {
982 ip_end = string_ftpport;
985 ip_end = strchr(string_ftpport, ':');
987 /* either ipv6 or (ipv4|domain|interface):port(-range) */
989 if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
991 port_min = port_max = 0;
992 strcpy(addr, string_ftpport);
993 ip_end = NULL; /* this got no port ! */
997 /* (ipv4|domain|interface):port(-range) */
998 strncpy(addr, string_ftpport, ip_end - ip_start);
1001 /* ipv4|interface */
1002 strcpy(addr, string_ftpport);
1005 /* parse the port */
1007 port_start = strchr(ip_end, ':');
1009 port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10));
1010 port_sep = strchr(port_start, '-');
1012 port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
1015 port_max = port_min;
1019 /* correct errors like:
1021 * :-4711, in this case port_min is (unsigned)-1,
1022 * therefore port_min > port_max for all cases
1023 * but port_max = (unsigned)-1
1025 if(port_min > port_max)
1026 port_min = port_max = 0;
1030 /* attempt to get the address of the given interface name */
1031 switch(Curl_if2ip(conn->ip_addr->ai_family,
1033 Curl_ipv6_scope(conn->ip_addr->ai_addr),
1036 addr, hbuf, sizeof(hbuf))) {
1037 case IF2IP_NOT_FOUND:
1038 /* not an interface, use the given string as host name instead */
1041 case IF2IP_AF_NOT_SUPPORTED:
1042 return CURLE_FTP_PORT_FAILED;
1044 host = hbuf; /* use the hbuf for host name */
1048 /* there was only a port(-range) given, default the host */
1050 } /* data->set.ftpport */
1054 /* not an interface and not a host name, get default by extracting
1055 the IP from the control connection */
1057 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1058 failf(data, "getsockname() failed: %s",
1059 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1061 return CURLE_FTP_PORT_FAILED;
1063 switch(sa->sa_family) {
1066 r = Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
1070 r = Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
1074 return CURLE_FTP_PORT_FAILED;
1075 host = hbuf; /* use this host name */
1076 possibly_non_local = FALSE; /* we know it is local now */
1079 /* resolv ip/host to ip */
1080 rc = Curl_resolv(data, host, 0, FALSE, &h);
1081 if(rc == CURLRESOLV_PENDING)
1082 (void)Curl_resolver_wait_resolv(data, &h);
1085 /* when we return from this function, we can forget about this entry
1086 to we can unlock it now already */
1087 Curl_resolv_unlock(data, h);
1090 res = NULL; /* failure! */
1093 failf(data, "failed to resolve the address provided to PORT: %s", host);
1095 return CURLE_FTP_PORT_FAILED;
1101 /* step 2, create a socket for the requested address */
1103 portsock = CURL_SOCKET_BAD;
1105 for(ai = res; ai; ai = ai->ai_next) {
1106 result = Curl_socket(data, ai, NULL, &portsock);
1114 failf(data, "socket failure: %s",
1115 Curl_strerror(error, buffer, sizeof(buffer)));
1116 return CURLE_FTP_PORT_FAILED;
1119 /* step 3, bind to a suitable local address */
1121 memcpy(sa, ai->ai_addr, ai->ai_addrlen);
1122 sslen = ai->ai_addrlen;
1124 for(port = port_min; port <= port_max;) {
1125 if(sa->sa_family == AF_INET)
1126 sa4->sin_port = htons(port);
1129 sa6->sin6_port = htons(port);
1131 /* Try binding the given address. */
1132 if(bind(portsock, sa, sslen) ) {
1135 if(possibly_non_local && (error == EADDRNOTAVAIL)) {
1136 /* The requested bind address is not local. Use the address used for
1137 * the control connection instead and restart the port loop
1139 infof(data, "bind(port=%hu) on non-local address failed: %s", port,
1140 Curl_strerror(error, buffer, sizeof(buffer)));
1143 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1144 failf(data, "getsockname() failed: %s",
1145 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1146 Curl_closesocket(data, conn, portsock);
1147 return CURLE_FTP_PORT_FAILED;
1150 possibly_non_local = FALSE; /* don't try this again */
1153 if(error != EADDRINUSE && error != EACCES) {
1154 failf(data, "bind(port=%hu) failed: %s", port,
1155 Curl_strerror(error, buffer, sizeof(buffer)));
1156 Curl_closesocket(data, conn, portsock);
1157 return CURLE_FTP_PORT_FAILED;
1166 /* maybe all ports were in use already*/
1167 if(port > port_max) {
1168 failf(data, "bind() failed, we ran out of ports");
1169 Curl_closesocket(data, conn, portsock);
1170 return CURLE_FTP_PORT_FAILED;
1173 /* get the name again after the bind() so that we can extract the
1174 port number it uses now */
1176 if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
1177 failf(data, "getsockname() failed: %s",
1178 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1179 Curl_closesocket(data, conn, portsock);
1180 return CURLE_FTP_PORT_FAILED;
1183 /* step 4, listen on the socket */
1185 if(listen(portsock, 1)) {
1186 failf(data, "socket failure: %s",
1187 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1188 Curl_closesocket(data, conn, portsock);
1189 return CURLE_FTP_PORT_FAILED;
1192 /* step 5, send the proper FTP command */
1194 /* get a plain printable version of the numerical address to work with
1196 Curl_printable_address(ai, myhost, sizeof(myhost));
1199 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
1200 /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
1201 request and enable EPRT again! */
1202 conn->bits.ftp_use_eprt = TRUE;
1205 for(; fcmd != DONE; fcmd++) {
1207 if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
1208 /* if disabled, goto next */
1211 if((PORT == fcmd) && sa->sa_family != AF_INET)
1212 /* PORT is IPv4 only */
1215 switch(sa->sa_family) {
1217 port = ntohs(sa4->sin_port);
1221 port = ntohs(sa6->sin6_port);
1225 continue; /* might as well skip this */
1230 * Two fine examples from RFC2428;
1232 * EPRT |1|132.235.1.2|6275|
1234 * EPRT |2|1080::8:800:200C:417A|5282|
1237 result = Curl_pp_sendf(data, &ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
1238 sa->sa_family == AF_INET?1:2,
1241 failf(data, "Failure sending EPRT command: %s",
1242 curl_easy_strerror(result));
1243 Curl_closesocket(data, conn, portsock);
1244 /* don't retry using PORT */
1245 ftpc->count1 = PORT;
1247 state(data, FTP_STOP);
1253 /* large enough for [IP address],[num],[num] */
1254 char target[sizeof(myhost) + 20];
1255 char *source = myhost;
1256 char *dest = target;
1258 /* translate x.x.x.x to x,x,x,x */
1259 while(source && *source) {
1268 msnprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
1270 result = Curl_pp_sendf(data, &ftpc->pp, "%s %s", mode[fcmd], target);
1272 failf(data, "Failure sending PORT command: %s",
1273 curl_easy_strerror(result));
1274 Curl_closesocket(data, conn, portsock);
1276 state(data, FTP_STOP);
1283 /* store which command was sent */
1284 ftpc->count1 = fcmd;
1286 close_secondarysocket(data, conn);
1288 /* we set the secondary socket variable to this for now, it is only so that
1289 the cleanup function will close it in case we fail before the true
1290 secondary stuff is made */
1291 conn->sock[SECONDARYSOCKET] = portsock;
1293 /* this tcpconnect assignment below is a hackish work-around to make the
1294 multi interface with active FTP work - as it will not wait for a
1295 (passive) connect in Curl_is_connected().
1297 The *proper* fix is to make sure that the active connection from the
1298 server is done in a non-blocking way. Currently, it is still BLOCKING.
1300 conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
1302 state(data, FTP_PORT);
1306 static CURLcode ftp_state_use_pasv(struct Curl_easy *data,
1307 struct connectdata *conn)
1309 struct ftp_conn *ftpc = &conn->proto.ftpc;
1310 CURLcode result = CURLE_OK;
1312 Here's the executive summary on what to do:
1314 PASV is RFC959, expect:
1315 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1317 LPSV is RFC1639, expect:
1318 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1320 EPSV is RFC2428, expect:
1321 229 Entering Extended Passive Mode (|||port|)
1325 static const char mode[][5] = { "EPSV", "PASV" };
1329 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
1330 /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1331 request and enable EPSV again! */
1332 conn->bits.ftp_use_epsv = TRUE;
1335 modeoff = conn->bits.ftp_use_epsv?0:1;
1337 result = Curl_pp_sendf(data, &ftpc->pp, "%s", mode[modeoff]);
1339 ftpc->count1 = modeoff;
1340 state(data, FTP_PASV);
1341 infof(data, "Connect data stream passively");
1347 * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc.
1349 * REST is the last command in the chain of commands when a "head"-like
1350 * request is made. Thus, if an actual transfer is to be made this is where we
1351 * take off for real.
1353 static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data)
1355 CURLcode result = CURLE_OK;
1356 struct FTP *ftp = data->req.p.ftp;
1357 struct connectdata *conn = data->conn;
1359 if(ftp->transfer != PPTRANSFER_BODY) {
1360 /* doesn't transfer any data */
1362 /* still possibly do PRE QUOTE jobs */
1363 state(data, FTP_RETR_PREQUOTE);
1364 result = ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE);
1366 else if(data->set.ftp_use_port) {
1367 /* We have chosen to use the PORT (or similar) command */
1368 result = ftp_state_use_port(data, EPRT);
1371 /* We have chosen (this is default) to use the PASV (or similar) command */
1372 if(data->set.ftp_use_pret) {
1373 /* The user has requested that we send a PRET command
1374 to prepare the server for the upcoming PASV */
1375 struct ftp_conn *ftpc = &conn->proto.ftpc;
1376 if(!conn->proto.ftpc.file)
1377 result = Curl_pp_sendf(data, &ftpc->pp, "PRET %s",
1378 data->set.str[STRING_CUSTOMREQUEST]?
1379 data->set.str[STRING_CUSTOMREQUEST]:
1380 (data->state.list_only?"NLST":"LIST"));
1381 else if(data->set.upload)
1382 result = Curl_pp_sendf(data, &ftpc->pp, "PRET STOR %s",
1383 conn->proto.ftpc.file);
1385 result = Curl_pp_sendf(data, &ftpc->pp, "PRET RETR %s",
1386 conn->proto.ftpc.file);
1388 state(data, FTP_PRET);
1391 result = ftp_state_use_pasv(data, conn);
1396 static CURLcode ftp_state_rest(struct Curl_easy *data,
1397 struct connectdata *conn)
1399 CURLcode result = CURLE_OK;
1400 struct FTP *ftp = data->req.p.ftp;
1401 struct ftp_conn *ftpc = &conn->proto.ftpc;
1403 if((ftp->transfer != PPTRANSFER_BODY) && ftpc->file) {
1404 /* if a "head"-like request is being made (on a file) */
1406 /* Determine if server can respond to REST command and therefore
1407 whether it supports range */
1408 result = Curl_pp_sendf(data, &ftpc->pp, "REST %d", 0);
1410 state(data, FTP_REST);
1413 result = ftp_state_prepare_transfer(data);
1418 static CURLcode ftp_state_size(struct Curl_easy *data,
1419 struct connectdata *conn)
1421 CURLcode result = CURLE_OK;
1422 struct FTP *ftp = data->req.p.ftp;
1423 struct ftp_conn *ftpc = &conn->proto.ftpc;
1425 if((ftp->transfer == PPTRANSFER_INFO) && ftpc->file) {
1426 /* if a "head"-like request is being made (on a file) */
1428 /* we know ftpc->file is a valid pointer to a file name */
1429 result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
1431 state(data, FTP_SIZE);
1434 result = ftp_state_rest(data, conn);
1439 static CURLcode ftp_state_list(struct Curl_easy *data)
1441 CURLcode result = CURLE_OK;
1442 struct FTP *ftp = data->req.p.ftp;
1443 struct connectdata *conn = data->conn;
1445 /* If this output is to be machine-parsed, the NLST command might be better
1446 to use, since the LIST command output is not specified or standard in any
1447 way. It has turned out that the NLST list output is not the same on all
1448 servers either... */
1451 if FTPFILE_NOCWD was specified, we should add the path
1452 as argument for the LIST / NLST / or custom command.
1453 Whether the server will support this, is uncertain.
1455 The other ftp_filemethods will CWD into dir/dir/ first and
1456 then just do LIST (in that case: nothing to do here)
1458 char *lstArg = NULL;
1461 if((data->set.ftp_filemethod == FTPFILE_NOCWD) && ftp->path) {
1462 /* url-decode before evaluation: e.g. paths starting/ending with %2f */
1463 const char *slashPos = NULL;
1464 char *rawPath = NULL;
1465 result = Curl_urldecode(ftp->path, 0, &rawPath, NULL, REJECT_CTRL);
1469 slashPos = strrchr(rawPath, '/');
1471 /* chop off the file part if format is dir/file otherwise remove
1472 the trailing slash for dir/dir/ except for absolute path / */
1473 size_t n = slashPos - rawPath;
1484 cmd = aprintf("%s%s%s",
1485 data->set.str[STRING_CUSTOMREQUEST]?
1486 data->set.str[STRING_CUSTOMREQUEST]:
1487 (data->state.list_only?"NLST":"LIST"),
1489 lstArg? lstArg: "");
1493 return CURLE_OUT_OF_MEMORY;
1495 result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", cmd);
1499 state(data, FTP_LIST);
1504 static CURLcode ftp_state_retr_prequote(struct Curl_easy *data)
1506 /* We've sent the TYPE, now we must send the list of prequote strings */
1507 return ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE);
1510 static CURLcode ftp_state_stor_prequote(struct Curl_easy *data)
1512 /* We've sent the TYPE, now we must send the list of prequote strings */
1513 return ftp_state_quote(data, TRUE, FTP_STOR_PREQUOTE);
1516 static CURLcode ftp_state_type(struct Curl_easy *data)
1518 CURLcode result = CURLE_OK;
1519 struct FTP *ftp = data->req.p.ftp;
1520 struct connectdata *conn = data->conn;
1521 struct ftp_conn *ftpc = &conn->proto.ftpc;
1523 /* If we have selected NOBODY and HEADER, it means that we only want file
1524 information. Which in FTP can't be much more than the file size and
1526 if(data->set.opt_no_body && ftpc->file &&
1527 ftp_need_type(conn, data->state.prefer_ascii)) {
1528 /* The SIZE command is _not_ RFC 959 specified, and therefore many servers
1529 may not support it! It is however the only way we have to get a file's
1532 ftp->transfer = PPTRANSFER_INFO;
1533 /* this means no actual transfer will be made */
1535 /* Some servers return different sizes for different modes, and thus we
1536 must set the proper type before we check the size */
1537 result = ftp_nb_type(data, conn, data->state.prefer_ascii, FTP_TYPE);
1542 result = ftp_state_size(data, conn);
1547 /* This is called after the CWD commands have been done in the beginning of
1549 static CURLcode ftp_state_mdtm(struct Curl_easy *data)
1551 CURLcode result = CURLE_OK;
1552 struct connectdata *conn = data->conn;
1553 struct ftp_conn *ftpc = &conn->proto.ftpc;
1555 /* Requested time of file or time-depended transfer? */
1556 if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
1558 /* we have requested to get the modified-time of the file, this is a white
1559 spot as the MDTM is not mentioned in RFC959 */
1560 result = Curl_pp_sendf(data, &ftpc->pp, "MDTM %s", ftpc->file);
1563 state(data, FTP_MDTM);
1566 result = ftp_state_type(data);
1572 /* This is called after the TYPE and possible quote commands have been sent */
1573 static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
1576 CURLcode result = CURLE_OK;
1577 struct connectdata *conn = data->conn;
1578 struct FTP *ftp = data->req.p.ftp;
1579 struct ftp_conn *ftpc = &conn->proto.ftpc;
1580 bool append = data->set.remote_append;
1582 if((data->state.resume_from && !sizechecked) ||
1583 ((data->state.resume_from > 0) && sizechecked)) {
1584 /* we're about to continue the uploading of a file */
1585 /* 1. get already existing file's size. We use the SIZE command for this
1586 which may not exist in the server! The SIZE command is not in
1589 /* 2. This used to set REST. But since we can do append, we
1590 don't another ftp command. We just skip the source file
1591 offset and then we APPEND the rest on the file instead */
1593 /* 3. pass file-size number of bytes in the source file */
1594 /* 4. lower the infilesize counter */
1595 /* => transfer as usual */
1596 int seekerr = CURL_SEEKFUNC_OK;
1598 if(data->state.resume_from < 0) {
1599 /* Got no given size to start from, figure it out */
1600 result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
1602 state(data, FTP_STOR_SIZE);
1609 /* Let's read off the proper amount of bytes from the input. */
1610 if(conn->seek_func) {
1611 Curl_set_in_callback(data, true);
1612 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1614 Curl_set_in_callback(data, false);
1617 if(seekerr != CURL_SEEKFUNC_OK) {
1618 curl_off_t passed = 0;
1619 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1620 failf(data, "Could not seek stream");
1621 return CURLE_FTP_COULDNT_USE_REST;
1623 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1625 size_t readthisamountnow =
1626 (data->state.resume_from - passed > data->set.buffer_size) ?
1627 (size_t)data->set.buffer_size :
1628 curlx_sotouz(data->state.resume_from - passed);
1630 size_t actuallyread =
1631 data->state.fread_func(data->state.buffer, 1, readthisamountnow,
1634 passed += actuallyread;
1635 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1636 /* this checks for greater-than only to make sure that the
1637 CURL_READFUNC_ABORT return code still aborts */
1638 failf(data, "Failed to read data");
1639 return CURLE_FTP_COULDNT_USE_REST;
1641 } while(passed < data->state.resume_from);
1643 /* now, decrease the size of the read */
1644 if(data->state.infilesize>0) {
1645 data->state.infilesize -= data->state.resume_from;
1647 if(data->state.infilesize <= 0) {
1648 infof(data, "File already completely uploaded");
1650 /* no data to transfer */
1651 Curl_setup_transfer(data, -1, -1, FALSE, -1);
1653 /* Set ->transfer so that we won't get any error in
1654 * ftp_done() because we didn't transfer anything! */
1655 ftp->transfer = PPTRANSFER_NONE;
1657 state(data, FTP_STOP);
1661 /* we've passed, proceed as normal */
1664 result = Curl_pp_sendf(data, &ftpc->pp, append?"APPE %s":"STOR %s",
1667 state(data, FTP_STOR);
1672 static CURLcode ftp_state_quote(struct Curl_easy *data,
1676 CURLcode result = CURLE_OK;
1677 struct FTP *ftp = data->req.p.ftp;
1678 struct connectdata *conn = data->conn;
1679 struct ftp_conn *ftpc = &conn->proto.ftpc;
1681 struct curl_slist *item;
1686 item = data->set.quote;
1688 case FTP_RETR_PREQUOTE:
1689 case FTP_STOR_PREQUOTE:
1690 item = data->set.prequote;
1693 item = data->set.postquote;
1699 * 'count1' to iterate over the commands to send
1700 * 'count2' to store whether to allow commands to fail
1711 /* Skip count1 items in the linked list */
1712 while((i< ftpc->count1) && item) {
1717 char *cmd = item->data;
1720 ftpc->count2 = 1; /* the sent command is allowed to fail */
1723 ftpc->count2 = 0; /* failure means cancel operation */
1725 result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd);
1728 state(data, instate);
1734 /* No more quote to send, continue to ... */
1738 result = ftp_state_cwd(data, conn);
1740 case FTP_RETR_PREQUOTE:
1741 if(ftp->transfer != PPTRANSFER_BODY)
1742 state(data, FTP_STOP);
1744 if(ftpc->known_filesize != -1) {
1745 Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
1746 result = ftp_state_retr(data, ftpc->known_filesize);
1749 if(data->set.ignorecl || data->state.prefer_ascii) {
1750 /* 'ignorecl' is used to support download of growing files. It
1751 prevents the state machine from requesting the file size from
1752 the server. With an unknown file size the download continues
1753 until the server terminates it, otherwise the client stops if
1754 the received byte count exceeds the reported file size. Set
1755 option CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this
1758 In addition: asking for the size for 'TYPE A' transfers is not
1759 constructive since servers don't report the converted size. So
1762 result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
1764 state(data, FTP_RETR);
1767 result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
1769 state(data, FTP_RETR_SIZE);
1774 case FTP_STOR_PREQUOTE:
1775 result = ftp_state_ul_setup(data, FALSE);
1785 /* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
1787 static CURLcode ftp_epsv_disable(struct Curl_easy *data,
1788 struct connectdata *conn)
1790 CURLcode result = CURLE_OK;
1793 #ifndef CURL_DISABLE_PROXY
1794 && !(conn->bits.tunnel_proxy || conn->bits.socksproxy)
1797 /* We can't disable EPSV when doing IPv6, so this is instead a fail */
1798 failf(data, "Failed EPSV attempt, exiting");
1799 return CURLE_WEIRD_SERVER_REPLY;
1802 infof(data, "Failed EPSV attempt. Disabling EPSV");
1803 /* disable it for next transfer */
1804 conn->bits.ftp_use_epsv = FALSE;
1805 data->state.errorbuf = FALSE; /* allow error message to get
1807 result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "PASV");
1809 conn->proto.ftpc.count1++;
1810 /* remain in/go to the FTP_PASV state */
1811 state(data, FTP_PASV);
1817 static char *control_address(struct connectdata *conn)
1819 /* Returns the control connection IP address.
1820 If a proxy tunnel is used, returns the original host name instead, because
1821 the effective control connection address is the proxy address,
1822 not the ftp host. */
1823 #ifndef CURL_DISABLE_PROXY
1824 if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
1825 return conn->host.name;
1827 return conn->primary_ip;
1830 static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
1833 struct connectdata *conn = data->conn;
1834 struct ftp_conn *ftpc = &conn->proto.ftpc;
1836 struct Curl_dns_entry *addr = NULL;
1838 unsigned short connectport; /* the local port connect() should use! */
1839 char *str = &data->state.buffer[4]; /* start on the first letter */
1841 /* if we come here again, make sure the former name is cleared */
1842 Curl_safefree(ftpc->newhost);
1844 if((ftpc->count1 == 0) &&
1846 /* positive EPSV response */
1847 char *ptr = strchr(str, '(');
1852 if(5 == sscanf(ptr, "%c%c%c%u%c",
1858 const char sep1 = separator[0];
1861 /* The four separators should be identical, or else this is an oddly
1862 formatted reply and we bail out immediately. */
1863 for(i = 1; i<4; i++) {
1864 if(separator[i] != sep1) {
1865 ptr = NULL; /* set to NULL to signal error */
1870 failf(data, "Illegal port number in EPSV reply");
1871 return CURLE_FTP_WEIRD_PASV_REPLY;
1874 ftpc->newport = (unsigned short)(num & 0xffff);
1875 ftpc->newhost = strdup(control_address(conn));
1877 return CURLE_OUT_OF_MEMORY;
1884 failf(data, "Weirdly formatted EPSV reply");
1885 return CURLE_FTP_WEIRD_PASV_REPLY;
1888 else if((ftpc->count1 == 1) &&
1890 /* positive PASV response */
1891 unsigned int ip[4] = {0, 0, 0, 0};
1892 unsigned int port[2] = {0, 0};
1895 * Scan for a sequence of six comma-separated numbers and use them as
1896 * IP+port indicators.
1898 * Found reply-strings include:
1899 * "227 Entering Passive Mode (127,0,0,1,4,51)"
1900 * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1901 * "227 Entering passive mode. 127,0,0,1,4,51"
1904 if(6 == sscanf(str, "%u,%u,%u,%u,%u,%u",
1905 &ip[0], &ip[1], &ip[2], &ip[3],
1906 &port[0], &port[1]))
1911 if(!*str || (ip[0] > 255) || (ip[1] > 255) || (ip[2] > 255) ||
1912 (ip[3] > 255) || (port[0] > 255) || (port[1] > 255) ) {
1913 failf(data, "Couldn't interpret the 227-response");
1914 return CURLE_FTP_WEIRD_227_FORMAT;
1917 /* we got OK from server */
1918 if(data->set.ftp_skip_ip) {
1919 /* told to ignore the remotely given IP but instead use the host we used
1920 for the control connection */
1921 infof(data, "Skip %u.%u.%u.%u for data connection, re-use %s instead",
1922 ip[0], ip[1], ip[2], ip[3],
1924 ftpc->newhost = strdup(control_address(conn));
1927 ftpc->newhost = aprintf("%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
1930 return CURLE_OUT_OF_MEMORY;
1932 ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
1934 else if(ftpc->count1 == 0) {
1935 /* EPSV failed, move on to PASV */
1936 return ftp_epsv_disable(data, conn);
1939 failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
1940 return CURLE_FTP_WEIRD_PASV_REPLY;
1943 #ifndef CURL_DISABLE_PROXY
1944 if(conn->bits.proxy) {
1946 * This connection uses a proxy and we need to connect to the proxy again
1947 * here. We don't want to rely on a former host lookup that might've
1948 * expired now, instead we remake the lookup here and now!
1950 const char * const host_name = conn->bits.socksproxy ?
1951 conn->socks_proxy.host.name : conn->http_proxy.host.name;
1952 rc = Curl_resolv(data, host_name, (int)conn->port, FALSE, &addr);
1953 if(rc == CURLRESOLV_PENDING)
1954 /* BLOCKING, ignores the return code but 'addr' will be NULL in
1956 (void)Curl_resolver_wait_resolv(data, &addr);
1959 (unsigned short)conn->port; /* we connect to the proxy's port */
1962 failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport);
1963 return CURLE_COULDNT_RESOLVE_PROXY;
1969 /* normal, direct, ftp connection */
1970 DEBUGASSERT(ftpc->newhost);
1972 /* postponed address resolution in case of tcp fastopen */
1973 if(conn->bits.tcp_fastopen && !conn->bits.reuse && !ftpc->newhost[0]) {
1974 Curl_conninfo_remote(data, conn, conn->sock[FIRSTSOCKET]);
1975 Curl_safefree(ftpc->newhost);
1976 ftpc->newhost = strdup(control_address(conn));
1978 return CURLE_OUT_OF_MEMORY;
1981 rc = Curl_resolv(data, ftpc->newhost, ftpc->newport, FALSE, &addr);
1982 if(rc == CURLRESOLV_PENDING)
1984 (void)Curl_resolver_wait_resolv(data, &addr);
1986 connectport = ftpc->newport; /* we connect to the remote port */
1989 failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
1990 return CURLE_FTP_CANT_GET_HOST;
1994 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
1995 result = Curl_connecthost(data, conn, addr);
1998 Curl_resolv_unlock(data, addr); /* we're done using this address */
1999 if(ftpc->count1 == 0 && ftpcode == 229)
2000 return ftp_epsv_disable(data, conn);
2007 * When this is used from the multi interface, this might've returned with
2008 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
2009 * connect to connect.
2012 if(data->set.verbose)
2013 /* this just dumps information about this second connection */
2014 ftp_pasv_verbose(data, addr->addr, ftpc->newhost, connectport);
2016 Curl_resolv_unlock(data, addr); /* we're done using this address */
2018 Curl_safefree(conn->secondaryhostname);
2019 conn->secondary_port = ftpc->newport;
2020 conn->secondaryhostname = strdup(ftpc->newhost);
2021 if(!conn->secondaryhostname)
2022 return CURLE_OUT_OF_MEMORY;
2024 conn->bits.do_more = TRUE;
2025 state(data, FTP_STOP); /* this phase is completed */
2030 static CURLcode ftp_state_port_resp(struct Curl_easy *data,
2033 struct connectdata *conn = data->conn;
2034 struct ftp_conn *ftpc = &conn->proto.ftpc;
2035 ftpport fcmd = (ftpport)ftpc->count1;
2036 CURLcode result = CURLE_OK;
2038 /* The FTP spec tells a positive response should have code 200.
2039 Be more permissive here to tolerate deviant servers. */
2040 if(ftpcode / 100 != 2) {
2041 /* the command failed */
2044 infof(data, "disabling EPRT usage");
2045 conn->bits.ftp_use_eprt = FALSE;
2050 failf(data, "Failed to do PORT");
2051 result = CURLE_FTP_PORT_FAILED;
2055 result = ftp_state_use_port(data, fcmd);
2058 infof(data, "Connect data stream actively");
2059 state(data, FTP_STOP); /* end of DO phase */
2060 result = ftp_dophase_done(data, FALSE);
2066 static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
2069 CURLcode result = CURLE_OK;
2070 struct FTP *ftp = data->req.p.ftp;
2071 struct connectdata *conn = data->conn;
2072 struct ftp_conn *ftpc = &conn->proto.ftpc;
2077 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
2078 last .sss part is optional and means fractions of a second */
2079 int year, month, day, hour, minute, second;
2080 if(6 == sscanf(&data->state.buffer[4], "%04d%02d%02d%02d%02d%02d",
2081 &year, &month, &day, &hour, &minute, &second)) {
2082 /* we have a time, reformat it */
2084 msnprintf(timebuf, sizeof(timebuf),
2085 "%04d%02d%02d %02d:%02d:%02d GMT",
2086 year, month, day, hour, minute, second);
2087 /* now, convert this into a time() value: */
2088 data->info.filetime = Curl_getdate_capped(timebuf);
2091 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2092 /* If we asked for a time of the file and we actually got one as well,
2093 we "emulate" a HTTP-style header in our output. */
2095 if(data->set.opt_no_body &&
2097 data->set.get_filetime &&
2098 (data->info.filetime >= 0) ) {
2099 char headerbuf[128];
2101 time_t filetime = data->info.filetime;
2103 const struct tm *tm = &buffer;
2105 result = Curl_gmtime(filetime, &buffer);
2109 /* format: "Tue, 15 Nov 1994 12:45:26" */
2110 headerbuflen = msnprintf(headerbuf, sizeof(headerbuf),
2111 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
2112 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2114 Curl_month[tm->tm_mon],
2119 result = Curl_client_write(data, CLIENTWRITE_BOTH, headerbuf,
2123 } /* end of a ridiculous amount of conditionals */
2128 infof(data, "unsupported MDTM reply format");
2130 case 550: /* "No such file or directory" */
2131 failf(data, "Given file does not exist");
2132 result = CURLE_REMOTE_FILE_NOT_FOUND;
2136 if(data->set.timecondition) {
2137 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2138 switch(data->set.timecondition) {
2139 case CURL_TIMECOND_IFMODSINCE:
2141 if(data->info.filetime <= data->set.timevalue) {
2142 infof(data, "The requested document is not new enough");
2143 ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */
2144 data->info.timecond = TRUE;
2145 state(data, FTP_STOP);
2149 case CURL_TIMECOND_IFUNMODSINCE:
2150 if(data->info.filetime > data->set.timevalue) {
2151 infof(data, "The requested document is not old enough");
2152 ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */
2153 data->info.timecond = TRUE;
2154 state(data, FTP_STOP);
2161 infof(data, "Skipping time comparison");
2166 result = ftp_state_type(data);
2171 static CURLcode ftp_state_type_resp(struct Curl_easy *data,
2175 CURLcode result = CURLE_OK;
2176 struct connectdata *conn = data->conn;
2178 if(ftpcode/100 != 2) {
2179 /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
2180 successful 'TYPE I'. While that is not as RFC959 says, it is still a
2181 positive response code and we allow that. */
2182 failf(data, "Couldn't set desired mode");
2183 return CURLE_FTP_COULDNT_SET_TYPE;
2186 infof(data, "Got a %03d response code instead of the assumed 200",
2189 if(instate == FTP_TYPE)
2190 result = ftp_state_size(data, conn);
2191 else if(instate == FTP_LIST_TYPE)
2192 result = ftp_state_list(data);
2193 else if(instate == FTP_RETR_TYPE)
2194 result = ftp_state_retr_prequote(data);
2195 else if(instate == FTP_STOR_TYPE)
2196 result = ftp_state_stor_prequote(data);
2201 static CURLcode ftp_state_retr(struct Curl_easy *data,
2202 curl_off_t filesize)
2204 CURLcode result = CURLE_OK;
2205 struct FTP *ftp = data->req.p.ftp;
2206 struct connectdata *conn = data->conn;
2207 struct ftp_conn *ftpc = &conn->proto.ftpc;
2209 if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
2210 failf(data, "Maximum file size exceeded");
2211 return CURLE_FILESIZE_EXCEEDED;
2213 ftp->downloadsize = filesize;
2215 if(data->state.resume_from) {
2216 /* We always (attempt to) get the size of downloads, so it is done before
2217 this even when not doing resumes. */
2218 if(filesize == -1) {
2219 infof(data, "ftp server doesn't support SIZE");
2220 /* We couldn't get the size and therefore we can't know if there really
2221 is a part of the file left to get, although the server will just
2222 close the connection when we start the connection so it won't cause
2223 us any harm, just not make us exit as nicely. */
2226 /* We got a file size report, so we check that there actually is a
2227 part of the file left to get, or else we go home. */
2228 if(data->state.resume_from< 0) {
2229 /* We're supposed to download the last abs(from) bytes */
2230 if(filesize < -data->state.resume_from) {
2231 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2232 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2233 data->state.resume_from, filesize);
2234 return CURLE_BAD_DOWNLOAD_RESUME;
2236 /* convert to size to download */
2237 ftp->downloadsize = -data->state.resume_from;
2238 /* download from where? */
2239 data->state.resume_from = filesize - ftp->downloadsize;
2242 if(filesize < data->state.resume_from) {
2243 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2244 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2245 data->state.resume_from, filesize);
2246 return CURLE_BAD_DOWNLOAD_RESUME;
2248 /* Now store the number of bytes we are expected to download */
2249 ftp->downloadsize = filesize-data->state.resume_from;
2253 if(ftp->downloadsize == 0) {
2254 /* no data to transfer */
2255 Curl_setup_transfer(data, -1, -1, FALSE, -1);
2256 infof(data, "File already completely downloaded");
2258 /* Set ->transfer so that we won't get any error in ftp_done()
2259 * because we didn't transfer the any file */
2260 ftp->transfer = PPTRANSFER_NONE;
2261 state(data, FTP_STOP);
2265 /* Set resume file transfer offset */
2266 infof(data, "Instructs server to resume from offset %"
2267 CURL_FORMAT_CURL_OFF_T, data->state.resume_from);
2269 result = Curl_pp_sendf(data, &ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
2270 data->state.resume_from);
2272 state(data, FTP_RETR_REST);
2276 result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
2278 state(data, FTP_RETR);
2284 static CURLcode ftp_state_size_resp(struct Curl_easy *data,
2288 CURLcode result = CURLE_OK;
2289 curl_off_t filesize = -1;
2290 char *buf = data->state.buffer;
2292 /* get the size from the ascii string: */
2293 if(ftpcode == 213) {
2294 /* To allow servers to prepend "rubbish" in the response string, we scan
2295 for all the digits at the end of the response and parse only those as a
2297 char *start = &buf[4];
2298 char *fdigit = strchr(start, '\r');
2302 while(ISDIGIT(*fdigit) && (fdigit > start));
2303 if(!ISDIGIT(*fdigit))
2308 /* ignores parsing errors, which will make the size remain unknown */
2309 (void)curlx_strtoofft(fdigit, NULL, 0, &filesize);
2312 else if(ftpcode == 550) { /* "No such file or directory" */
2313 /* allow a SIZE failure for (resumed) uploads, when probing what command
2315 if(instate != FTP_STOR_SIZE) {
2316 failf(data, "The file does not exist");
2317 return CURLE_REMOTE_FILE_NOT_FOUND;
2321 if(instate == FTP_SIZE) {
2322 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2323 if(-1 != filesize) {
2325 int clbuflen = msnprintf(clbuf, sizeof(clbuf),
2326 "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
2327 result = Curl_client_write(data, CLIENTWRITE_BOTH, clbuf, clbuflen);
2332 Curl_pgrsSetDownloadSize(data, filesize);
2333 result = ftp_state_rest(data, data->conn);
2335 else if(instate == FTP_RETR_SIZE) {
2336 Curl_pgrsSetDownloadSize(data, filesize);
2337 result = ftp_state_retr(data, filesize);
2339 else if(instate == FTP_STOR_SIZE) {
2340 data->state.resume_from = filesize;
2341 result = ftp_state_ul_setup(data, TRUE);
2347 static CURLcode ftp_state_rest_resp(struct Curl_easy *data,
2348 struct connectdata *conn,
2352 CURLcode result = CURLE_OK;
2353 struct ftp_conn *ftpc = &conn->proto.ftpc;
2358 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2359 if(ftpcode == 350) {
2360 char buffer[24]= { "Accept-ranges: bytes\r\n" };
2361 result = Curl_client_write(data, CLIENTWRITE_BOTH, buffer,
2367 result = ftp_state_prepare_transfer(data);
2371 if(ftpcode != 350) {
2372 failf(data, "Couldn't use REST");
2373 result = CURLE_FTP_COULDNT_USE_REST;
2376 result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
2378 state(data, FTP_RETR);
2386 static CURLcode ftp_state_stor_resp(struct Curl_easy *data,
2387 int ftpcode, ftpstate instate)
2389 CURLcode result = CURLE_OK;
2390 struct connectdata *conn = data->conn;
2392 if(ftpcode >= 400) {
2393 failf(data, "Failed FTP upload: %0d", ftpcode);
2394 state(data, FTP_STOP);
2395 /* oops, we never close the sockets! */
2396 return CURLE_UPLOAD_FAILED;
2399 conn->proto.ftpc.state_saved = instate;
2401 /* PORT means we are now awaiting the server to connect to us. */
2402 if(data->set.ftp_use_port) {
2405 state(data, FTP_STOP); /* no longer in STOR state */
2407 result = AllowServerConnect(data, &connected);
2412 struct ftp_conn *ftpc = &conn->proto.ftpc;
2413 infof(data, "Data conn was not available immediately");
2414 ftpc->wait_data_conn = TRUE;
2419 return InitiateTransfer(data);
2422 /* for LIST and RETR responses */
2423 static CURLcode ftp_state_get_resp(struct Curl_easy *data,
2427 CURLcode result = CURLE_OK;
2428 struct FTP *ftp = data->req.p.ftp;
2429 struct connectdata *conn = data->conn;
2431 if((ftpcode == 150) || (ftpcode == 125)) {
2435 150 Opening BINARY mode data connection for /etc/passwd (2241
2436 bytes). (ok, the file is being transferred)
2439 150 Opening ASCII mode data connection for /bin/ls
2442 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2445 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
2448 125 Data connection already open; Transfer starting. */
2450 curl_off_t size = -1; /* default unknown size */
2454 * It appears that there are FTP-servers that return size 0 for files when
2455 * SIZE is used on the file while being in BINARY mode. To work around
2456 * that (stupid) behavior, we attempt to parse the RETR response even if
2457 * the SIZE returned size zero.
2459 * Debugging help from Salvatore Sorrentino on February 26, 2003.
2462 if((instate != FTP_LIST) &&
2463 !data->state.prefer_ascii &&
2464 (ftp->downloadsize < 1)) {
2466 * It seems directory listings either don't show the size or very
2467 * often uses size 0 anyway. ASCII transfers may very well turn out
2468 * that the transferred amount of data is not the same as this line
2469 * tells, why using this number in those cases only confuses us.
2471 * Example D above makes this parsing a little tricky */
2473 char *buf = data->state.buffer;
2474 bytes = strstr(buf, " bytes");
2476 long in = (long)(--bytes-buf);
2477 /* this is a hint there is size information in there! ;-) */
2479 /* scan for the left parenthesis and break there */
2482 /* skip only digits */
2483 if(!ISDIGIT(*bytes)) {
2487 /* one more estep backwards */
2490 /* if we have nothing but digits: */
2493 /* get the number! */
2494 (void)curlx_strtoofft(bytes, NULL, 0, &size);
2498 else if(ftp->downloadsize > -1)
2499 size = ftp->downloadsize;
2501 if(size > data->req.maxdownload && data->req.maxdownload > 0)
2502 size = data->req.size = data->req.maxdownload;
2503 else if((instate != FTP_LIST) && (data->state.prefer_ascii))
2504 size = -1; /* kludge for servers that understate ASCII mode file size */
2506 infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T,
2507 data->req.maxdownload);
2509 if(instate != FTP_LIST)
2510 infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T,
2514 conn->proto.ftpc.state_saved = instate;
2515 conn->proto.ftpc.retr_size_saved = size;
2517 if(data->set.ftp_use_port) {
2520 result = AllowServerConnect(data, &connected);
2525 struct ftp_conn *ftpc = &conn->proto.ftpc;
2526 infof(data, "Data conn was not available immediately");
2527 state(data, FTP_STOP);
2528 ftpc->wait_data_conn = TRUE;
2532 return InitiateTransfer(data);
2535 if((instate == FTP_LIST) && (ftpcode == 450)) {
2536 /* simply no matching files in the dir listing */
2537 ftp->transfer = PPTRANSFER_NONE; /* don't download anything */
2538 state(data, FTP_STOP); /* this phase is over */
2541 failf(data, "RETR response: %03d", ftpcode);
2542 return instate == FTP_RETR && ftpcode == 550?
2543 CURLE_REMOTE_FILE_NOT_FOUND:
2544 CURLE_FTP_COULDNT_RETR_FILE;
2551 /* after USER, PASS and ACCT */
2552 static CURLcode ftp_state_loggedin(struct Curl_easy *data)
2554 CURLcode result = CURLE_OK;
2555 struct connectdata *conn = data->conn;
2557 if(conn->bits.ftp_use_control_ssl) {
2558 /* PBSZ = PROTECTION BUFFER SIZE.
2560 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2562 Specifically, the PROT command MUST be preceded by a PBSZ
2563 command and a PBSZ command MUST be preceded by a successful
2564 security data exchange (the TLS negotiation in this case)
2566 ... (and on page 8):
2568 Thus the PBSZ command must still be issued, but must have a
2569 parameter of '0' to indicate that no buffering is taking place
2570 and the data connection should not be encapsulated.
2572 result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "PBSZ %d", 0);
2574 state(data, FTP_PBSZ);
2577 result = ftp_state_pwd(data, conn);
2582 /* for USER and PASS responses */
2583 static CURLcode ftp_state_user_resp(struct Curl_easy *data,
2587 CURLcode result = CURLE_OK;
2588 struct connectdata *conn = data->conn;
2589 struct ftp_conn *ftpc = &conn->proto.ftpc;
2590 (void)instate; /* no use for this yet */
2592 /* some need password anyway, and others just return 2xx ignored */
2593 if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2594 /* 331 Password required for ...
2595 (the server requires to send the user's password too) */
2596 result = Curl_pp_sendf(data, &ftpc->pp, "PASS %s",
2597 conn->passwd?conn->passwd:"");
2599 state(data, FTP_PASS);
2601 else if(ftpcode/100 == 2) {
2602 /* 230 User ... logged in.
2603 (the user logged in with or without password) */
2604 result = ftp_state_loggedin(data);
2606 else if(ftpcode == 332) {
2607 if(data->set.str[STRING_FTP_ACCOUNT]) {
2608 result = Curl_pp_sendf(data, &ftpc->pp, "ACCT %s",
2609 data->set.str[STRING_FTP_ACCOUNT]);
2611 state(data, FTP_ACCT);
2614 failf(data, "ACCT requested but none available");
2615 result = CURLE_LOGIN_DENIED;
2619 /* All other response codes, like:
2621 530 User ... access denied
2622 (the server denies to log the specified user) */
2624 if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2625 !data->state.ftp_trying_alternative) {
2626 /* Ok, USER failed. Let's try the supplied command. */
2628 Curl_pp_sendf(data, &ftpc->pp, "%s",
2629 data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2631 data->state.ftp_trying_alternative = TRUE;
2632 state(data, FTP_USER);
2636 failf(data, "Access denied: %03d", ftpcode);
2637 result = CURLE_LOGIN_DENIED;
2643 /* for ACCT response */
2644 static CURLcode ftp_state_acct_resp(struct Curl_easy *data,
2647 CURLcode result = CURLE_OK;
2648 if(ftpcode != 230) {
2649 failf(data, "ACCT rejected by server: %03d", ftpcode);
2650 result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2653 result = ftp_state_loggedin(data);
2659 static CURLcode ftp_statemachine(struct Curl_easy *data,
2660 struct connectdata *conn)
2663 curl_socket_t sock = conn->sock[FIRSTSOCKET];
2665 struct ftp_conn *ftpc = &conn->proto.ftpc;
2666 struct pingpong *pp = &ftpc->pp;
2667 static const char ftpauth[][4] = { "SSL", "TLS" };
2671 return Curl_pp_flushsend(data, pp);
2673 result = ftp_readresp(data, sock, pp, &ftpcode, &nread);
2678 /* we have now received a full FTP server response */
2679 switch(ftpc->state) {
2681 if(ftpcode == 230) {
2682 /* 230 User logged in - already! Take as 220 if TLS required. */
2683 if(data->set.use_ssl <= CURLUSESSL_TRY ||
2684 conn->bits.ftp_use_control_ssl)
2685 return ftp_state_user_resp(data, ftpcode, ftpc->state);
2687 else if(ftpcode != 220) {
2688 failf(data, "Got a %03d ftp-server response when 220 was expected",
2690 return CURLE_WEIRD_SERVER_REPLY;
2693 /* We have received a 220 response fine, now we proceed. */
2696 /* If not anonymous login, try a secure login. Note that this
2697 procedure is still BLOCKING. */
2699 Curl_sec_request_prot(conn, "private");
2700 /* We set private first as default, in case the line below fails to
2701 set a valid level */
2702 Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2704 if(Curl_sec_login(data, conn))
2705 infof(data, "Logging in with password in cleartext");
2707 infof(data, "Authentication successful");
2711 if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) {
2712 /* We don't have a SSL/TLS control connection yet, but FTPS is
2713 requested. Try a FTPS connection now */
2716 switch(data->set.ftpsslauth) {
2717 case CURLFTPAUTH_DEFAULT:
2718 case CURLFTPAUTH_SSL:
2719 ftpc->count2 = 1; /* add one to get next */
2722 case CURLFTPAUTH_TLS:
2723 ftpc->count2 = -1; /* subtract one to get next */
2727 failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2728 (int)data->set.ftpsslauth);
2729 return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
2731 result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s",
2732 ftpauth[ftpc->count1]);
2734 state(data, FTP_AUTH);
2737 result = ftp_state_user(data, conn);
2741 /* we have gotten the response to a previous AUTH command */
2744 return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */
2746 /* RFC2228 (page 5) says:
2748 * If the server is willing to accept the named security mechanism,
2749 * and does not require any security data, it must respond with
2750 * reply code 234/334.
2753 if((ftpcode == 234) || (ftpcode == 334)) {
2754 /* Curl_ssl_connect is BLOCKING */
2755 result = Curl_ssl_connect(data, conn, FIRSTSOCKET);
2757 conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */
2758 conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */
2759 result = ftp_state_user(data, conn);
2762 else if(ftpc->count3 < 1) {
2764 ftpc->count1 += ftpc->count2; /* get next attempt */
2765 result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s",
2766 ftpauth[ftpc->count1]);
2767 /* remain in this same state */
2770 if(data->set.use_ssl > CURLUSESSL_TRY)
2771 /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2772 result = CURLE_USE_SSL_FAILED;
2774 /* ignore the failure and continue */
2775 result = ftp_state_user(data, conn);
2781 result = ftp_state_user_resp(data, ftpcode, ftpc->state);
2785 result = ftp_state_acct_resp(data, ftpcode);
2790 Curl_pp_sendf(data, &ftpc->pp, "PROT %c",
2791 data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2793 state(data, FTP_PROT);
2797 if(ftpcode/100 == 2)
2798 /* We have enabled SSL for the data connection! */
2799 conn->bits.ftp_use_data_ssl =
2800 (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
2801 /* FTP servers typically responds with 500 if they decide to reject
2803 else if(data->set.use_ssl > CURLUSESSL_CONTROL)
2804 /* we failed and bails out */
2805 return CURLE_USE_SSL_FAILED;
2807 if(data->set.ftp_ccc) {
2808 /* CCC - Clear Command Channel
2810 result = Curl_pp_sendf(data, &ftpc->pp, "%s", "CCC");
2812 state(data, FTP_CCC);
2815 result = ftp_state_pwd(data, conn);
2820 /* First shut down the SSL layer (note: this call will block) */
2821 result = Curl_ssl_shutdown(data, conn, FIRSTSOCKET);
2824 failf(data, "Failed to clear the command channel (CCC)");
2827 /* Then continue as normal */
2828 result = ftp_state_pwd(data, conn);
2832 if(ftpcode == 257) {
2833 char *ptr = &data->state.buffer[4]; /* start on the first letter */
2834 const size_t buf_size = data->set.buffer_size;
2836 bool entry_extracted = FALSE;
2838 dir = malloc(nread + 1);
2840 return CURLE_OUT_OF_MEMORY;
2842 /* Reply format is like
2843 257<space>[rubbish]"<directory-name>"<space><commentary> and the
2846 The directory name can contain any character; embedded
2847 double-quotes should be escaped by double-quotes (the
2848 "quote-doubling" convention).
2851 /* scan for the first double-quote for non-standard responses */
2852 while(ptr < &data->state.buffer[buf_size]
2853 && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
2857 /* it started good */
2860 for(store = dir; *ptr;) {
2862 if('\"' == ptr[1]) {
2863 /* "quote-doubling" */
2869 entry_extracted = TRUE;
2870 break; /* get out of this loop */
2878 *store = '\0'; /* null-terminate */
2880 if(entry_extracted) {
2881 /* If the path name does not look like an absolute path (i.e.: it
2882 does not start with a '/'), we probably need some server-dependent
2883 adjustments. For example, this is the case when connecting to
2884 an OS400 FTP server: this server supports two name syntaxes,
2885 the default one being incompatible with standard paths. In
2886 addition, this server switches automatically to the regular path
2887 syntax when one is encountered in a command: this results in
2888 having an entrypath in the wrong syntax when later used in CWD.
2889 The method used here is to check the server OS: we do it only
2890 if the path name looks strange to minimize overhead on other
2893 if(!ftpc->server_os && dir[0] != '/') {
2894 result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SYST");
2899 Curl_safefree(ftpc->entrypath);
2900 ftpc->entrypath = dir; /* remember this */
2901 infof(data, "Entry path is '%s'", ftpc->entrypath);
2902 /* also save it where getinfo can access it: */
2903 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2904 state(data, FTP_SYST);
2908 Curl_safefree(ftpc->entrypath);
2909 ftpc->entrypath = dir; /* remember this */
2910 infof(data, "Entry path is '%s'", ftpc->entrypath);
2911 /* also save it where getinfo can access it: */
2912 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2915 /* couldn't get the path */
2917 infof(data, "Failed to figure out path");
2920 state(data, FTP_STOP); /* we are done with the CONNECT phase! */
2921 DEBUGF(infof(data, "protocol connect phase DONE"));
2925 if(ftpcode == 215) {
2926 char *ptr = &data->state.buffer[4]; /* start on the first letter */
2930 os = malloc(nread + 1);
2932 return CURLE_OUT_OF_MEMORY;
2934 /* Reply format is like
2935 215<space><OS-name><space><commentary>
2939 for(store = os; *ptr && *ptr != ' ';)
2941 *store = '\0'; /* null-terminate */
2943 /* Check for special servers here. */
2945 if(strcasecompare(os, "OS/400")) {
2946 /* Force OS400 name format 1. */
2947 result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1");
2952 /* remember target server OS */
2953 Curl_safefree(ftpc->server_os);
2954 ftpc->server_os = os;
2955 state(data, FTP_NAMEFMT);
2958 /* Nothing special for the target server. */
2959 /* remember target server OS */
2960 Curl_safefree(ftpc->server_os);
2961 ftpc->server_os = os;
2964 /* Cannot identify server OS. Continue anyway and cross fingers. */
2967 state(data, FTP_STOP); /* we are done with the CONNECT phase! */
2968 DEBUGF(infof(data, "protocol connect phase DONE"));
2972 if(ftpcode == 250) {
2973 /* Name format change successful: reload initial path. */
2974 ftp_state_pwd(data, conn);
2978 state(data, FTP_STOP); /* we are done with the CONNECT phase! */
2979 DEBUGF(infof(data, "protocol connect phase DONE"));
2984 case FTP_RETR_PREQUOTE:
2985 case FTP_STOR_PREQUOTE:
2986 if((ftpcode >= 400) && !ftpc->count2) {
2987 /* failure response code, and not allowed to fail */
2988 failf(data, "QUOT command failed with %03d", ftpcode);
2989 result = CURLE_QUOTE_ERROR;
2992 result = ftp_state_quote(data, FALSE, ftpc->state);
2996 if(ftpcode/100 != 2) {
2997 /* failure to CWD there */
2998 if(data->set.ftp_create_missing_dirs &&
2999 ftpc->cwdcount && !ftpc->count2) {
3001 ftpc->count2++; /* counter to prevent CWD-MKD loops */
3003 /* count3 is set to allow MKD to fail once per dir. In the case when
3004 CWD fails and then MKD fails (due to another session raced it to
3005 create the dir) this then allows for a second try to CWD to it. */
3006 ftpc->count3 = (data->set.ftp_create_missing_dirs == 2) ? 1 : 0;
3008 result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s",
3009 ftpc->dirs[ftpc->cwdcount - 1]);
3011 state(data, FTP_MKD);
3014 /* return failure */
3015 failf(data, "Server denied you to change to the given directory");
3016 ftpc->cwdfail = TRUE; /* don't remember this path as we failed
3018 result = CURLE_REMOTE_ACCESS_DENIED;
3024 if(++ftpc->cwdcount <= ftpc->dirdepth)
3026 result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s",
3027 ftpc->dirs[ftpc->cwdcount - 1]);
3029 result = ftp_state_mdtm(data);
3034 if((ftpcode/100 != 2) && !ftpc->count3--) {
3035 /* failure to MKD the dir */
3036 failf(data, "Failed to MKD dir: %03d", ftpcode);
3037 result = CURLE_REMOTE_ACCESS_DENIED;
3040 state(data, FTP_CWD);
3042 result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s",
3043 ftpc->dirs[ftpc->cwdcount - 1]);
3048 result = ftp_state_mdtm_resp(data, ftpcode);
3055 result = ftp_state_type_resp(data, ftpcode, ftpc->state);
3061 result = ftp_state_size_resp(data, ftpcode, ftpc->state);
3066 result = ftp_state_rest_resp(data, conn, ftpcode, ftpc->state);
3070 if(ftpcode != 200) {
3071 /* there only is this one standard OK return code. */
3072 failf(data, "PRET command not accepted: %03d", ftpcode);
3073 return CURLE_FTP_PRET_FAILED;
3075 result = ftp_state_use_pasv(data, conn);
3079 result = ftp_state_pasv_resp(data, ftpcode);
3083 result = ftp_state_port_resp(data, ftpcode);
3088 result = ftp_state_get_resp(data, ftpcode, ftpc->state);
3092 result = ftp_state_stor_resp(data, ftpcode, ftpc->state);
3096 /* fallthrough, just stop! */
3098 /* internal error */
3099 state(data, FTP_STOP);
3108 /* called repeatedly until done from multi.c */
3109 static CURLcode ftp_multi_statemach(struct Curl_easy *data,
3112 struct connectdata *conn = data->conn;
3113 struct ftp_conn *ftpc = &conn->proto.ftpc;
3114 CURLcode result = Curl_pp_statemach(data, &ftpc->pp, FALSE, FALSE);
3116 /* Check for the state outside of the Curl_socket_check() return code checks
3117 since at times we are in fact already in this state when this function
3119 *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
3124 static CURLcode ftp_block_statemach(struct Curl_easy *data,
3125 struct connectdata *conn)
3127 struct ftp_conn *ftpc = &conn->proto.ftpc;
3128 struct pingpong *pp = &ftpc->pp;
3129 CURLcode result = CURLE_OK;
3131 while(ftpc->state != FTP_STOP) {
3132 result = Curl_pp_statemach(data, pp, TRUE, TRUE /* disconnecting */);
3141 * ftp_connect() should do everything that is to be considered a part of
3142 * the connection phase.
3144 * The variable 'done' points to will be TRUE if the protocol-layer connect
3145 * phase is done when this function returns, or FALSE if not.
3148 static CURLcode ftp_connect(struct Curl_easy *data,
3149 bool *done) /* see description above */
3152 struct connectdata *conn = data->conn;
3153 struct ftp_conn *ftpc = &conn->proto.ftpc;
3154 struct pingpong *pp = &ftpc->pp;
3156 *done = FALSE; /* default to not done yet */
3158 /* We always support persistent connections on ftp */
3159 connkeep(conn, "FTP default");
3161 PINGPONG_SETUP(pp, ftp_statemachine, ftp_endofresp);
3163 if(conn->handler->flags & PROTOPT_SSL) {
3165 result = Curl_ssl_connect(data, conn, FIRSTSOCKET);
3168 conn->bits.ftp_use_control_ssl = TRUE;
3171 Curl_pp_setup(pp); /* once per transfer */
3172 Curl_pp_init(data, pp); /* init the generic pingpong data */
3174 /* When we connect, we start in the state where we await the 220
3176 state(data, FTP_WAIT220);
3178 result = ftp_multi_statemach(data, done);
3183 /***********************************************************************
3187 * The DONE function. This does what needs to be done after a single DO has
3190 * Input argument is already checked for validity.
3192 static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
3195 struct connectdata *conn = data->conn;
3196 struct FTP *ftp = data->req.p.ftp;
3197 struct ftp_conn *ftpc = &conn->proto.ftpc;
3198 struct pingpong *pp = &ftpc->pp;
3201 CURLcode result = CURLE_OK;
3202 char *rawPath = NULL;
3209 case CURLE_BAD_DOWNLOAD_RESUME:
3210 case CURLE_FTP_WEIRD_PASV_REPLY:
3211 case CURLE_FTP_PORT_FAILED:
3212 case CURLE_FTP_ACCEPT_FAILED:
3213 case CURLE_FTP_ACCEPT_TIMEOUT:
3214 case CURLE_FTP_COULDNT_SET_TYPE:
3215 case CURLE_FTP_COULDNT_RETR_FILE:
3216 case CURLE_PARTIAL_FILE:
3217 case CURLE_UPLOAD_FAILED:
3218 case CURLE_REMOTE_ACCESS_DENIED:
3219 case CURLE_FILESIZE_EXCEEDED:
3220 case CURLE_REMOTE_FILE_NOT_FOUND:
3221 case CURLE_WRITE_ERROR:
3222 /* the connection stays alive fine even though this happened */
3224 case CURLE_OK: /* doesn't affect the control connection's status */
3228 /* until we cope better with prematurely ended requests, let them
3229 * fallback as if in complete failure */
3231 default: /* by default, an error means the control connection is
3232 wedged and should not be used anymore */
3233 ftpc->ctl_valid = FALSE;
3234 ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3235 current path, as this connection is going */
3236 connclose(conn, "FTP ended with bad error code");
3237 result = status; /* use the already set error code */
3241 if(data->state.wildcardmatch) {
3242 if(data->set.chunk_end && ftpc->file) {
3243 Curl_set_in_callback(data, true);
3244 data->set.chunk_end(data->wildcard.customptr);
3245 Curl_set_in_callback(data, false);
3247 ftpc->known_filesize = -1;
3251 /* get the url-decoded "raw" path */
3252 result = Curl_urldecode(ftp->path, 0, &rawPath, &pathLen,
3255 /* We can limp along anyway (and should try to since we may already be in
3256 * the error path) */
3257 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3258 connclose(conn, "FTP: out of memory!"); /* mark for connection closure */
3259 free(ftpc->prevpath);
3260 ftpc->prevpath = NULL; /* no path remembering */
3262 else { /* remember working directory for connection reuse */
3263 if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/'))
3264 free(rawPath); /* full path => no CWDs happened => keep ftpc->prevpath */
3266 free(ftpc->prevpath);
3268 if(!ftpc->cwdfail) {
3269 if(data->set.ftp_filemethod == FTPFILE_NOCWD)
3270 pathLen = 0; /* relative path => working directory is FTP home */
3272 pathLen -= ftpc->file?strlen(ftpc->file):0; /* file is url-decoded */
3274 rawPath[pathLen] = '\0';
3275 ftpc->prevpath = rawPath;
3279 ftpc->prevpath = NULL; /* no path */
3284 infof(data, "Remembering we are in dir \"%s\"", ftpc->prevpath);
3287 /* free the dir tree and file parts */
3290 /* shut down the socket to inform the server we're done */
3293 shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */
3296 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3297 if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
3298 /* partial download completed */
3299 result = Curl_pp_sendf(data, pp, "%s", "ABOR");
3301 failf(data, "Failure sending ABOR command: %s",
3302 curl_easy_strerror(result));
3303 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3304 connclose(conn, "ABOR command failed"); /* connection closure */
3308 if(conn->ssl[SECONDARYSOCKET].use) {
3309 /* The secondary socket is using SSL so we must close down that part
3310 first before we close the socket for real */
3311 Curl_ssl_close(data, conn, SECONDARYSOCKET);
3313 /* Note that we keep "use" set to TRUE since that (next) connection is
3314 still requested to use SSL */
3316 close_secondarysocket(data, conn);
3319 if(!result && (ftp->transfer == PPTRANSFER_BODY) && ftpc->ctl_valid &&
3320 pp->pending_resp && !premature) {
3322 * Let's see what the server says about the transfer we just performed,
3323 * but lower the timeout as sometimes this connection has died while the
3324 * data has been transferred. This happens when doing through NATs etc that
3325 * abandon old silent connections.
3327 timediff_t old_time = pp->response_time;
3329 pp->response_time = 60*1000; /* give it only a minute for now */
3330 pp->response = Curl_now(); /* timeout relative now */
3332 result = Curl_GetFTPResponse(data, &nread, &ftpcode);
3334 pp->response_time = old_time; /* set this back to previous value */
3336 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3337 failf(data, "control connection looks dead");
3338 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3339 connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
3343 Curl_safefree(ftp->pathalloc);
3347 if(ftpc->dont_check && data->req.maxdownload > 0) {
3348 /* we have just sent ABOR and there is no reliable way to check if it was
3349 * successful or not; we have to close the connection now */
3350 infof(data, "partial download completed, closing connection");
3351 connclose(conn, "Partial download with no ability to check");
3355 if(!ftpc->dont_check) {
3356 /* 226 Transfer complete, 250 Requested file action okay, completed. */
3362 failf(data, "Exceeded storage allocation");
3363 result = CURLE_REMOTE_DISK_FULL;
3366 failf(data, "server did not report OK, got %d", ftpcode);
3367 result = CURLE_PARTIAL_FILE;
3373 if(result || premature)
3374 /* the response code from the transfer showed an error already so no
3375 use checking further */
3377 else if(data->set.upload) {
3378 if((-1 != data->state.infilesize) &&
3379 (data->state.infilesize != data->req.writebytecount) &&
3381 (ftp->transfer == PPTRANSFER_BODY)) {
3382 failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
3383 " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
3384 data->req.writebytecount, data->state.infilesize);
3385 result = CURLE_PARTIAL_FILE;
3389 if((-1 != data->req.size) &&
3390 (data->req.size != data->req.bytecount) &&
3391 #ifdef CURL_DO_LINEEND_CONV
3392 /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3393 * we'll check to see if the discrepancy can be explained by the number
3394 * of CRLFs we've changed to LFs.
3396 ((data->req.size + data->state.crlf_conversions) !=
3397 data->req.bytecount) &&
3398 #endif /* CURL_DO_LINEEND_CONV */
3399 (data->req.maxdownload != data->req.bytecount)) {
3400 failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
3401 " bytes", data->req.bytecount);
3402 result = CURLE_PARTIAL_FILE;
3404 else if(!ftpc->dont_check &&
3405 !data->req.bytecount &&
3406 (data->req.size>0)) {
3407 failf(data, "No data was received");
3408 result = CURLE_FTP_COULDNT_RETR_FILE;
3412 /* clear these for next connection */
3413 ftp->transfer = PPTRANSFER_BODY;
3414 ftpc->dont_check = FALSE;
3416 /* Send any post-transfer QUOTE strings? */
3417 if(!status && !result && !premature && data->set.postquote)
3418 result = ftp_sendquote(data, conn, data->set.postquote);
3419 Curl_safefree(ftp->pathalloc);
3423 /***********************************************************************
3427 * Where a 'quote' means a list of custom commands to send to the server.
3428 * The quote list is passed as an argument.
3434 CURLcode ftp_sendquote(struct Curl_easy *data,
3435 struct connectdata *conn, struct curl_slist *quote)
3437 struct curl_slist *item;
3438 struct ftp_conn *ftpc = &conn->proto.ftpc;
3439 struct pingpong *pp = &ftpc->pp;
3445 char *cmd = item->data;
3446 bool acceptfail = FALSE;
3450 /* if a command starts with an asterisk, which a legal FTP command never
3451 can, the command will be allowed to fail without it causing any
3452 aborts or cancels etc. It will cause libcurl to act as if the command
3453 is successful, whatever the server reponds. */
3460 result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd);
3462 pp->response = Curl_now(); /* timeout relative now */
3463 result = Curl_GetFTPResponse(data, &nread, &ftpcode);
3468 if(!acceptfail && (ftpcode >= 400)) {
3469 failf(data, "QUOT string not accepted: %s", cmd);
3470 return CURLE_QUOTE_ERROR;
3480 /***********************************************************************
3484 * Returns TRUE if we in the current situation should send TYPE
3486 static int ftp_need_type(struct connectdata *conn,
3489 return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3492 /***********************************************************************
3496 * Set TYPE. We only deal with ASCII or BINARY so this function
3498 * If the transfer type is not sent, simulate on OK response in newstate
3500 static CURLcode ftp_nb_type(struct Curl_easy *data,
3501 struct connectdata *conn,
3502 bool ascii, ftpstate newstate)
3504 struct ftp_conn *ftpc = &conn->proto.ftpc;
3506 char want = (char)(ascii?'A':'I');
3508 if(ftpc->transfertype == want) {
3509 state(data, newstate);
3510 return ftp_state_type_resp(data, 200, newstate);
3513 result = Curl_pp_sendf(data, &ftpc->pp, "TYPE %c", want);
3515 state(data, newstate);
3517 /* keep track of our current transfer type */
3518 ftpc->transfertype = want;
3523 /***************************************************************************
3525 * ftp_pasv_verbose()
3527 * This function only outputs some informationals about this second connection
3528 * when we've issued a PASV command before and thus we have connected to a
3529 * possibly new IP address.
3532 #ifndef CURL_DISABLE_VERBOSE_STRINGS
3534 ftp_pasv_verbose(struct Curl_easy *data,
3535 struct Curl_addrinfo *ai,
3536 char *newhost, /* ascii version */
3540 Curl_printable_address(ai, buf, sizeof(buf));
3541 infof(data, "Connecting to %s (%s) port %d", newhost, buf, port);
3548 * This function shall be called when the second FTP (data) connection is
3551 * 'complete' can return 0 for incomplete, 1 for done and -1 for go back
3552 * (which basically is only for when PASV is being sent to retry a failed
3556 static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
3558 struct connectdata *conn = data->conn;
3559 struct ftp_conn *ftpc = &conn->proto.ftpc;
3560 CURLcode result = CURLE_OK;
3561 bool connected = FALSE;
3562 bool complete = FALSE;
3564 /* the ftp struct is inited in ftp_connect() */
3565 struct FTP *ftp = data->req.p.ftp;
3567 /* if the second connection isn't done yet, wait for it */
3568 if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
3569 if(Curl_connect_ongoing(conn)) {
3570 /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
3571 aren't used so we blank their arguments. */
3572 result = Curl_proxyCONNECT(data, SECONDARYSOCKET, NULL, 0);
3577 result = Curl_is_connected(data, conn, SECONDARYSOCKET, &connected);
3579 /* Ready to do more? */
3581 DEBUGF(infof(data, "DO-MORE connected phase starts"));
3584 if(result && (ftpc->count1 == 0)) {
3585 *completep = -1; /* go back to DOING please */
3586 /* this is a EPSV connect failing, try PASV instead */
3587 return ftp_epsv_disable(data, conn);
3593 #ifndef CURL_DISABLE_PROXY
3594 result = Curl_proxy_connect(data, SECONDARYSOCKET);
3598 if(CONNECT_SECONDARYSOCKET_PROXY_SSL())
3601 if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
3602 Curl_connect_ongoing(conn))
3607 /* already in a state so skip the initial commands.
3608 They are only done to kickstart the do_more state */
3609 result = ftp_multi_statemach(data, &complete);
3611 *completep = (int)complete;
3613 /* if we got an error or if we don't wait for a data connection return
3615 if(result || !ftpc->wait_data_conn)
3618 /* if we reach the end of the FTP state machine here, *complete will be
3619 TRUE but so is ftpc->wait_data_conn, which says we need to wait for the
3620 data connection and therefore we're not actually complete */
3624 if(ftp->transfer <= PPTRANSFER_INFO) {
3625 /* a transfer is about to take place, or if not a file name was given
3626 so we'll do a SIZE on it later and then we need the right TYPE first */
3628 if(ftpc->wait_data_conn == TRUE) {
3631 result = ReceivedServerConnect(data, &serv_conned);
3633 return result; /* Failed to accept data connection */
3636 /* It looks data connection is established */
3637 result = AcceptServerConnect(data);
3638 ftpc->wait_data_conn = FALSE;
3640 result = InitiateTransfer(data);
3645 *completep = 1; /* this state is now complete when the server has
3646 connected back to us */
3649 else if(data->set.upload) {
3650 result = ftp_nb_type(data, conn, data->state.prefer_ascii,
3655 result = ftp_multi_statemach(data, &complete);
3656 if(ftpc->wait_data_conn)
3657 /* if we reach the end of the FTP state machine here, *complete will be
3658 TRUE but so is ftpc->wait_data_conn, which says we need to wait for
3659 the data connection and therefore we're not actually complete */
3662 *completep = (int)complete;
3666 ftp->downloadsize = -1; /* unknown as of yet */
3668 result = Curl_range(data);
3670 if(result == CURLE_OK && data->req.maxdownload >= 0) {
3671 /* Don't check for successful transfer */
3672 ftpc->dont_check = TRUE;
3677 else if(data->state.list_only || !ftpc->file) {
3678 /* The specified path ends with a slash, and therefore we think this
3679 is a directory that is requested, use LIST. But before that we
3680 need to set ASCII transfer mode. */
3682 /* But only if a body transfer was requested. */
3683 if(ftp->transfer == PPTRANSFER_BODY) {
3684 result = ftp_nb_type(data, conn, TRUE, FTP_LIST_TYPE);
3688 /* otherwise just fall through */
3691 result = ftp_nb_type(data, conn, data->state.prefer_ascii,
3697 result = ftp_multi_statemach(data, &complete);
3698 *completep = (int)complete;
3703 /* no data to transfer */
3704 Curl_setup_transfer(data, -1, -1, FALSE, -1);
3706 if(!ftpc->wait_data_conn) {
3707 /* no waiting for the data connection so this is now complete */
3709 DEBUGF(infof(data, "DO-MORE phase ends with %d", (int)result));
3717 /***********************************************************************
3721 * This is the actual DO function for FTP. Get a file/directory according to
3722 * the options previously setup.
3726 CURLcode ftp_perform(struct Curl_easy *data,
3727 bool *connected, /* connect status after PASV / PORT */
3730 /* this is FTP and no proxy */
3731 CURLcode result = CURLE_OK;
3732 struct connectdata *conn = data->conn;
3734 DEBUGF(infof(data, "DO phase starts"));
3736 if(data->set.opt_no_body) {
3737 /* requested no body means no transfer... */
3738 struct FTP *ftp = data->req.p.ftp;
3739 ftp->transfer = PPTRANSFER_INFO;
3742 *dophase_done = FALSE; /* not done yet */
3744 /* start the first command in the DO phase */
3745 result = ftp_state_quote(data, TRUE, FTP_QUOTE);
3749 /* run the state-machine */
3750 result = ftp_multi_statemach(data, dophase_done);
3752 *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
3754 infof(data, "ftp_perform ends with SECONDARY: %d", *connected);
3757 DEBUGF(infof(data, "DO phase is complete1"));
3763 static void wc_data_dtor(void *ptr)
3765 struct ftp_wc *ftpwc = ptr;
3766 if(ftpwc && ftpwc->parser)
3767 Curl_ftp_parselist_data_free(&ftpwc->parser);
3771 static CURLcode init_wc_data(struct Curl_easy *data)
3774 struct FTP *ftp = data->req.p.ftp;
3775 char *path = ftp->path;
3776 struct WildcardData *wildcard = &(data->wildcard);
3777 CURLcode result = CURLE_OK;
3778 struct ftp_wc *ftpwc = NULL;
3780 last_slash = strrchr(ftp->path, '/');
3783 if(last_slash[0] == '\0') {
3784 wildcard->state = CURLWC_CLEAN;
3785 result = ftp_parse_url_path(data);
3788 wildcard->pattern = strdup(last_slash);
3789 if(!wildcard->pattern)
3790 return CURLE_OUT_OF_MEMORY;
3791 last_slash[0] = '\0'; /* cut file from path */
3793 else { /* there is only 'wildcard pattern' or nothing */
3795 wildcard->pattern = strdup(path);
3796 if(!wildcard->pattern)
3797 return CURLE_OUT_OF_MEMORY;
3800 else { /* only list */
3801 wildcard->state = CURLWC_CLEAN;
3802 result = ftp_parse_url_path(data);
3807 /* program continues only if URL is not ending with slash, allocate needed
3808 resources for wildcard transfer */
3810 /* allocate ftp protocol specific wildcard data */
3811 ftpwc = calloc(1, sizeof(struct ftp_wc));
3813 result = CURLE_OUT_OF_MEMORY;
3817 /* INITIALIZE parselist structure */
3818 ftpwc->parser = Curl_ftp_parselist_data_alloc();
3819 if(!ftpwc->parser) {
3820 result = CURLE_OUT_OF_MEMORY;
3824 wildcard->protdata = ftpwc; /* put it to the WildcardData tmp pointer */
3825 wildcard->dtor = wc_data_dtor;
3827 /* wildcard does not support NOCWD option (assert it?) */
3828 if(data->set.ftp_filemethod == FTPFILE_NOCWD)
3829 data->set.ftp_filemethod = FTPFILE_MULTICWD;
3831 /* try to parse ftp url */
3832 result = ftp_parse_url_path(data);
3837 wildcard->path = strdup(ftp->path);
3838 if(!wildcard->path) {
3839 result = CURLE_OUT_OF_MEMORY;
3843 /* backup old write_function */
3844 ftpwc->backup.write_function = data->set.fwrite_func;
3845 /* parsing write function */
3846 data->set.fwrite_func = Curl_ftp_parselist;
3847 /* backup old file descriptor */
3848 ftpwc->backup.file_descriptor = data->set.out;
3849 /* let the writefunc callback know the transfer */
3850 data->set.out = data;
3852 infof(data, "Wildcard - Parsing started");
3857 Curl_ftp_parselist_data_free(&ftpwc->parser);
3860 Curl_safefree(wildcard->pattern);
3861 wildcard->dtor = ZERO_NULL;
3862 wildcard->protdata = NULL;
3866 static CURLcode wc_statemach(struct Curl_easy *data)
3868 struct WildcardData * const wildcard = &(data->wildcard);
3869 struct connectdata *conn = data->conn;
3870 CURLcode result = CURLE_OK;
3873 switch(wildcard->state) {
3875 result = init_wc_data(data);
3876 if(wildcard->state == CURLWC_CLEAN)
3879 wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
3882 case CURLWC_MATCHING: {
3883 /* In this state is LIST response successfully parsed, so lets restore
3884 previous WRITEFUNCTION callback and WRITEDATA pointer */
3885 struct ftp_wc *ftpwc = wildcard->protdata;
3886 data->set.fwrite_func = ftpwc->backup.write_function;
3887 data->set.out = ftpwc->backup.file_descriptor;
3888 ftpwc->backup.write_function = ZERO_NULL;
3889 ftpwc->backup.file_descriptor = NULL;
3890 wildcard->state = CURLWC_DOWNLOADING;
3892 if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
3893 /* error found in LIST parsing */
3894 wildcard->state = CURLWC_CLEAN;
3897 if(wildcard->filelist.size == 0) {
3898 /* no corresponding file */
3899 wildcard->state = CURLWC_CLEAN;
3900 return CURLE_REMOTE_FILE_NOT_FOUND;
3905 case CURLWC_DOWNLOADING: {
3906 /* filelist has at least one file, lets get first one */
3907 struct ftp_conn *ftpc = &conn->proto.ftpc;
3908 struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
3909 struct FTP *ftp = data->req.p.ftp;
3911 char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
3913 return CURLE_OUT_OF_MEMORY;
3915 /* switch default ftp->path and tmp_path */
3916 free(ftp->pathalloc);
3917 ftp->pathalloc = ftp->path = tmp_path;
3919 infof(data, "Wildcard - START of \"%s\"", finfo->filename);
3920 if(data->set.chunk_bgn) {
3922 Curl_set_in_callback(data, true);
3923 userresponse = data->set.chunk_bgn(
3924 finfo, wildcard->customptr, (int)wildcard->filelist.size);
3925 Curl_set_in_callback(data, false);
3926 switch(userresponse) {
3927 case CURL_CHUNK_BGN_FUNC_SKIP:
3928 infof(data, "Wildcard - \"%s\" skipped by user",
3930 wildcard->state = CURLWC_SKIP;
3932 case CURL_CHUNK_BGN_FUNC_FAIL:
3933 return CURLE_CHUNK_FAILED;
3937 if(finfo->filetype != CURLFILETYPE_FILE) {
3938 wildcard->state = CURLWC_SKIP;
3942 if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
3943 ftpc->known_filesize = finfo->size;
3945 result = ftp_parse_url_path(data);
3949 /* we don't need the Curl_fileinfo of first file anymore */
3950 Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
3952 if(wildcard->filelist.size == 0) { /* remains only one file to down. */
3953 wildcard->state = CURLWC_CLEAN;
3954 /* after that will be ftp_do called once again and no transfer
3955 will be done because of CURLWC_CLEAN state */
3962 if(data->set.chunk_end) {
3963 Curl_set_in_callback(data, true);
3964 data->set.chunk_end(data->wildcard.customptr);
3965 Curl_set_in_callback(data, false);
3967 Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
3968 wildcard->state = (wildcard->filelist.size == 0) ?
3969 CURLWC_CLEAN : CURLWC_DOWNLOADING;
3973 case CURLWC_CLEAN: {
3974 struct ftp_wc *ftpwc = wildcard->protdata;
3977 result = Curl_ftp_parselist_geterror(ftpwc->parser);
3979 wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
3987 wildcard->dtor(wildcard->protdata);
3994 /***********************************************************************
3998 * This function is registered as 'curl_do' function. It decodes the path
3999 * parts etc as a wrapper to the actual DO function (ftp_perform).
4001 * The input argument is already checked for validity.
4003 static CURLcode ftp_do(struct Curl_easy *data, bool *done)
4005 CURLcode result = CURLE_OK;
4006 struct connectdata *conn = data->conn;
4007 struct ftp_conn *ftpc = &conn->proto.ftpc;
4009 *done = FALSE; /* default to false */
4010 ftpc->wait_data_conn = FALSE; /* default to no such wait */
4012 if(data->state.wildcardmatch) {
4013 result = wc_statemach(data);
4014 if(data->wildcard.state == CURLWC_SKIP ||
4015 data->wildcard.state == CURLWC_DONE) {
4016 /* do not call ftp_regular_transfer */
4019 if(result) /* error, loop or skipping the file */
4022 else { /* no wildcard FSM needed */
4023 result = ftp_parse_url_path(data);
4028 result = ftp_regular_transfer(data, done);
4033 /***********************************************************************
4037 * This should be called before calling sclose() on an ftp control connection
4038 * (not data connections). We should then wait for the response from the
4039 * server before returning. The calling code should then try to close the
4043 static CURLcode ftp_quit(struct Curl_easy *data, struct connectdata *conn)
4045 CURLcode result = CURLE_OK;
4047 if(conn->proto.ftpc.ctl_valid) {
4048 result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "QUIT");
4050 failf(data, "Failure sending QUIT command: %s",
4051 curl_easy_strerror(result));
4052 conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
4053 connclose(conn, "QUIT command failed"); /* mark for connection closure */
4054 state(data, FTP_STOP);
4058 state(data, FTP_QUIT);
4060 result = ftp_block_statemach(data, conn);
4066 /***********************************************************************
4070 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
4071 * resources. BLOCKING.
4073 static CURLcode ftp_disconnect(struct Curl_easy *data,
4074 struct connectdata *conn,
4075 bool dead_connection)
4077 struct ftp_conn *ftpc = &conn->proto.ftpc;
4078 struct pingpong *pp = &ftpc->pp;
4080 /* We cannot send quit unconditionally. If this connection is stale or
4081 bad in any way, sending quit and waiting around here will make the
4082 disconnect wait in vain and cause more problems than we need to.
4084 ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
4085 will try to send the QUIT command, otherwise it will just return.
4088 ftpc->ctl_valid = FALSE;
4090 /* The FTP session may or may not have been allocated/setup at this point! */
4091 (void)ftp_quit(data, conn); /* ignore errors on the QUIT */
4093 if(ftpc->entrypath) {
4094 if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
4095 data->state.most_recent_ftp_entrypath = NULL;
4097 Curl_safefree(ftpc->entrypath);
4101 Curl_safefree(ftpc->prevpath);
4102 Curl_safefree(ftpc->server_os);
4103 Curl_pp_disconnect(pp);
4109 /* warning C4706: assignment within conditional expression */
4110 #pragma warning(disable:4706)
4113 /***********************************************************************
4115 * ftp_parse_url_path()
4117 * Parse the URL path into separate path components.
4121 CURLcode ftp_parse_url_path(struct Curl_easy *data)
4123 /* the ftp struct is already inited in ftp_connect() */
4124 struct FTP *ftp = data->req.p.ftp;
4125 struct connectdata *conn = data->conn;
4126 struct ftp_conn *ftpc = &conn->proto.ftpc;
4127 const char *slashPos = NULL;
4128 const char *fileName = NULL;
4129 CURLcode result = CURLE_OK;
4130 char *rawPath = NULL; /* url-decoded "raw" path */
4133 ftpc->ctl_valid = FALSE;
4134 ftpc->cwdfail = FALSE;
4136 /* url-decode ftp path before further evaluation */
4137 result = Curl_urldecode(ftp->path, 0, &rawPath, &pathLen, REJECT_CTRL);
4139 failf(data, "path contains control characters");
4143 switch(data->set.ftp_filemethod) {
4144 case FTPFILE_NOCWD: /* fastest, but less standard-compliant */
4146 if((pathLen > 0) && (rawPath[pathLen - 1] != '/'))
4147 fileName = rawPath; /* this is a full file path */
4149 else: ftpc->file is not used anywhere other than for operations on
4150 a file. In other words, never for directory operations.
4151 So we can safely leave filename as NULL here and use it as a
4152 argument in dir/file decisions.
4156 case FTPFILE_SINGLECWD:
4157 slashPos = strrchr(rawPath, '/');
4159 /* get path before last slash, except for / */
4160 size_t dirlen = slashPos - rawPath;
4164 ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
4167 return CURLE_OUT_OF_MEMORY;
4170 ftpc->dirs[0] = calloc(1, dirlen + 1);
4171 if(!ftpc->dirs[0]) {
4173 return CURLE_OUT_OF_MEMORY;
4176 strncpy(ftpc->dirs[0], rawPath, dirlen);
4177 ftpc->dirdepth = 1; /* we consider it to be a single dir */
4178 fileName = slashPos + 1; /* rest is file name */
4181 fileName = rawPath; /* file name only (or empty) */
4184 default: /* allow pretty much anything */
4185 case FTPFILE_MULTICWD: {
4186 /* current position: begin of next path component */
4187 const char *curPos = rawPath;
4189 int dirAlloc = 0; /* number of entries allocated for the 'dirs' array */
4190 const char *str = rawPath;
4191 for(; *str != 0; ++str)
4196 ftpc->dirs = calloc(dirAlloc, sizeof(ftpc->dirs[0]));
4199 return CURLE_OUT_OF_MEMORY;
4202 /* parse the URL path into separate path components */
4203 while((slashPos = strchr(curPos, '/'))) {
4204 size_t compLen = slashPos - curPos;
4206 /* path starts with a slash: add that as a directory */
4207 if((compLen == 0) && (ftpc->dirdepth == 0))
4210 /* we skip empty path components, like "x//y" since the FTP command
4211 CWD requires a parameter and a non-existent parameter a) doesn't
4212 work on many servers and b) has no effect on the others. */
4214 char *comp = calloc(1, compLen + 1);
4217 return CURLE_OUT_OF_MEMORY;
4219 strncpy(comp, curPos, compLen);
4220 ftpc->dirs[ftpc->dirdepth++] = comp;
4222 curPos = slashPos + 1;
4225 DEBUGASSERT(ftpc->dirdepth <= dirAlloc);
4226 fileName = curPos; /* the rest is the file name (or empty) */
4231 if(fileName && *fileName)
4232 ftpc->file = strdup(fileName);
4234 ftpc->file = NULL; /* instead of point to a zero byte,
4235 we make it a NULL pointer */
4237 if(data->set.upload && !ftpc->file && (ftp->transfer == PPTRANSFER_BODY)) {
4238 /* We need a file name when uploading. Return error! */
4239 failf(data, "Uploading to a URL without a file name");
4241 return CURLE_URL_MALFORMAT;
4244 ftpc->cwddone = FALSE; /* default to not done */
4246 if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/'))
4247 ftpc->cwddone = TRUE; /* skip CWD for absolute paths */
4248 else { /* newly created FTP connections are already in entry path */
4249 const char *oldPath = conn->bits.reuse ? ftpc->prevpath : "";
4252 if(data->set.ftp_filemethod == FTPFILE_NOCWD)
4253 n = 0; /* CWD to entry for relative paths */
4255 n -= ftpc->file?strlen(ftpc->file):0;
4257 if((strlen(oldPath) == n) && !strncmp(rawPath, oldPath, n)) {
4258 infof(data, "Request has same path as previous transfer");
4259 ftpc->cwddone = TRUE;
4268 /* call this when the DO phase has completed */
4269 static CURLcode ftp_dophase_done(struct Curl_easy *data, bool connected)
4271 struct connectdata *conn = data->conn;
4272 struct FTP *ftp = data->req.p.ftp;
4273 struct ftp_conn *ftpc = &conn->proto.ftpc;
4277 CURLcode result = ftp_do_more(data, &completed);
4280 close_secondarysocket(data, conn);
4285 if(ftp->transfer != PPTRANSFER_BODY)
4286 /* no data to transfer */
4287 Curl_setup_transfer(data, -1, -1, FALSE, -1);
4289 /* since we didn't connect now, we want do_more to get called */
4290 conn->bits.do_more = TRUE;
4292 ftpc->ctl_valid = TRUE; /* seems good */
4297 /* called from multi.c while DOing */
4298 static CURLcode ftp_doing(struct Curl_easy *data,
4301 CURLcode result = ftp_multi_statemach(data, dophase_done);
4304 DEBUGF(infof(data, "DO phase failed"));
4305 else if(*dophase_done) {
4306 result = ftp_dophase_done(data, FALSE /* not connected */);
4308 DEBUGF(infof(data, "DO phase is complete2"));
4313 /***********************************************************************
4315 * ftp_regular_transfer()
4317 * The input argument is already checked for validity.
4319 * Performs all commands done before a regular transfer between a local and a
4322 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
4323 * ftp_done() function without finding any major problem.
4326 CURLcode ftp_regular_transfer(struct Curl_easy *data,
4329 CURLcode result = CURLE_OK;
4330 bool connected = FALSE;
4331 struct connectdata *conn = data->conn;
4332 struct ftp_conn *ftpc = &conn->proto.ftpc;
4333 data->req.size = -1; /* make sure this is unknown at this point */
4335 Curl_pgrsSetUploadCounter(data, 0);
4336 Curl_pgrsSetDownloadCounter(data, 0);
4337 Curl_pgrsSetUploadSize(data, -1);
4338 Curl_pgrsSetDownloadSize(data, -1);
4340 ftpc->ctl_valid = TRUE; /* starts good */
4342 result = ftp_perform(data,
4343 &connected, /* have we connected after PASV/PORT */
4344 dophase_done); /* all commands in the DO-phase done? */
4349 /* the DO phase has not completed yet */
4352 result = ftp_dophase_done(data, connected);
4363 static CURLcode ftp_setup_connection(struct Curl_easy *data,
4364 struct connectdata *conn)
4369 data->req.p.ftp = ftp = calloc(sizeof(struct FTP), 1);
4371 return CURLE_OUT_OF_MEMORY;
4373 ftp->path = &data->state.up.path[1]; /* don't include the initial slash */
4375 /* FTP URLs support an extension like ";type=<typecode>" that
4376 * we'll try to get now! */
4377 type = strstr(ftp->path, ";type=");
4380 type = strstr(conn->host.rawalloc, ";type=");
4384 *type = 0; /* it was in the middle of the hostname */
4385 command = Curl_raw_toupper(type[6]);
4388 case 'A': /* ASCII mode */
4389 data->state.prefer_ascii = TRUE;
4392 case 'D': /* directory mode */
4393 data->state.list_only = TRUE;
4396 case 'I': /* binary mode */
4398 /* switch off ASCII */
4399 data->state.prefer_ascii = FALSE;
4404 /* get some initial data into the ftp struct */
4405 ftp->transfer = PPTRANSFER_BODY;
4406 ftp->downloadsize = 0;
4407 conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
4412 #endif /* CURL_DISABLE_FTP */