1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 #include "curl_setup.h"
25 #ifndef CURL_DISABLE_FTP
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h>
30 #ifdef HAVE_ARPA_INET_H
31 #include <arpa/inet.h>
34 #include <sys/utsname.h>
44 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
46 #define in_addr_t unsigned long
49 #include <curl/curl.h>
57 #include "http.h" /* for HTTP proxy tunnel stuff */
61 #include "ftplistparser.h"
63 #include "strtoofft.h"
65 #include "vtls/vtls.h"
68 #include "inet_ntop.h"
69 #include "inet_pton.h"
71 #include "parsedate.h" /* for the week day and month names */
72 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
76 #include "speedcheck.h"
78 #include "http_proxy.h"
79 #include "non-ascii.h"
81 #define _MPRINTF_REPLACE /* use our functions only */
82 #include <curl/mprintf.h>
84 #include "curl_memory.h"
85 /* The last #include file should be: */
89 #define NI_MAXHOST 1025
91 #ifndef INET_ADDRSTRLEN
92 #define INET_ADDRSTRLEN 16
95 #ifdef CURL_DISABLE_VERBOSE_STRINGS
96 #define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt
99 /* Local API functions */
101 static void _state(struct connectdata *conn,
103 #define state(x,y) _state(x,y)
105 static void _state(struct connectdata *conn,
108 #define state(x,y) _state(x,y,__LINE__)
111 static CURLcode ftp_sendquote(struct connectdata *conn,
112 struct curl_slist *quote);
113 static CURLcode ftp_quit(struct connectdata *conn);
114 static CURLcode ftp_parse_url_path(struct connectdata *conn);
115 static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
116 #ifndef CURL_DISABLE_VERBOSE_STRINGS
117 static void ftp_pasv_verbose(struct connectdata *conn,
119 char *newhost, /* ascii version */
122 static CURLcode ftp_state_prepare_transfer(struct connectdata *conn);
123 static CURLcode ftp_state_mdtm(struct connectdata *conn);
124 static CURLcode ftp_state_quote(struct connectdata *conn,
125 bool init, ftpstate instate);
126 static CURLcode ftp_nb_type(struct connectdata *conn,
127 bool ascii, ftpstate newstate);
128 static int ftp_need_type(struct connectdata *conn,
130 static CURLcode ftp_do(struct connectdata *conn, bool *done);
131 static CURLcode ftp_done(struct connectdata *conn,
132 CURLcode, bool premature);
133 static CURLcode ftp_connect(struct connectdata *conn, bool *done);
134 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
135 static CURLcode ftp_do_more(struct connectdata *conn, int *completed);
136 static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
137 static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks,
139 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
141 static CURLcode ftp_doing(struct connectdata *conn,
143 static CURLcode ftp_setup_connection(struct connectdata * conn);
145 static CURLcode init_wc_data(struct connectdata *conn);
146 static CURLcode wc_statemach(struct connectdata *conn);
148 static void wc_data_dtor(void *ptr);
150 static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize);
152 static CURLcode ftp_readresp(curl_socket_t sockfd,
156 static CURLcode ftp_dophase_done(struct connectdata *conn,
159 /* easy-to-use macro: */
160 #define PPSENDF(x,y,z) if((result = Curl_pp_sendf(x,y,z))) \
165 * FTP protocol handler.
168 const struct Curl_handler Curl_handler_ftp = {
170 ftp_setup_connection, /* setup_connection */
173 ftp_do_more, /* do_more */
174 ftp_connect, /* connect_it */
175 ftp_multi_statemach, /* connecting */
176 ftp_doing, /* doing */
177 ftp_getsock, /* proto_getsock */
178 ftp_getsock, /* doing_getsock */
179 ftp_domore_getsock, /* domore_getsock */
180 ZERO_NULL, /* perform_getsock */
181 ftp_disconnect, /* disconnect */
182 ZERO_NULL, /* readwrite */
183 PORT_FTP, /* defport */
184 CURLPROTO_FTP, /* protocol */
185 PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
186 | PROTOPT_NOURLQUERY /* flags */
192 * FTPS protocol handler.
195 const struct Curl_handler Curl_handler_ftps = {
197 ftp_setup_connection, /* setup_connection */
200 ftp_do_more, /* do_more */
201 ftp_connect, /* connect_it */
202 ftp_multi_statemach, /* connecting */
203 ftp_doing, /* doing */
204 ftp_getsock, /* proto_getsock */
205 ftp_getsock, /* doing_getsock */
206 ftp_domore_getsock, /* domore_getsock */
207 ZERO_NULL, /* perform_getsock */
208 ftp_disconnect, /* disconnect */
209 ZERO_NULL, /* readwrite */
210 PORT_FTPS, /* defport */
211 CURLPROTO_FTPS, /* protocol */
212 PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
213 PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY /* flags */
217 #ifndef CURL_DISABLE_HTTP
219 * HTTP-proxyed FTP protocol handler.
222 static const struct Curl_handler Curl_handler_ftp_proxy = {
224 Curl_http_setup_conn, /* setup_connection */
225 Curl_http, /* do_it */
226 Curl_http_done, /* done */
227 ZERO_NULL, /* do_more */
228 ZERO_NULL, /* connect_it */
229 ZERO_NULL, /* connecting */
230 ZERO_NULL, /* doing */
231 ZERO_NULL, /* proto_getsock */
232 ZERO_NULL, /* doing_getsock */
233 ZERO_NULL, /* domore_getsock */
234 ZERO_NULL, /* perform_getsock */
235 ZERO_NULL, /* disconnect */
236 ZERO_NULL, /* readwrite */
237 PORT_FTP, /* defport */
238 CURLPROTO_HTTP, /* protocol */
239 PROTOPT_NONE /* flags */
245 * HTTP-proxyed FTPS protocol handler.
248 static const struct Curl_handler Curl_handler_ftps_proxy = {
250 Curl_http_setup_conn, /* setup_connection */
251 Curl_http, /* do_it */
252 Curl_http_done, /* done */
253 ZERO_NULL, /* do_more */
254 ZERO_NULL, /* connect_it */
255 ZERO_NULL, /* connecting */
256 ZERO_NULL, /* doing */
257 ZERO_NULL, /* proto_getsock */
258 ZERO_NULL, /* doing_getsock */
259 ZERO_NULL, /* domore_getsock */
260 ZERO_NULL, /* perform_getsock */
261 ZERO_NULL, /* disconnect */
262 ZERO_NULL, /* readwrite */
263 PORT_FTPS, /* defport */
264 CURLPROTO_HTTP, /* protocol */
265 PROTOPT_NONE /* flags */
272 * NOTE: back in the old days, we added code in the FTP code that made NOBODY
273 * requests on files respond with headers passed to the client/stdout that
274 * looked like HTTP ones.
276 * This approach is not very elegant, it causes confusion and is error-prone.
277 * It is subject for removal at the next (or at least a future) soname bump.
278 * Until then you can test the effects of the removal by undefining the
279 * following define named CURL_FTP_HTTPSTYLE_HEAD.
281 #define CURL_FTP_HTTPSTYLE_HEAD 1
283 static void freedirs(struct ftp_conn *ftpc)
287 for(i=0; i < ftpc->dirdepth; i++) {
303 /* Returns non-zero if the given string contains CR (\r) or LF (\n),
304 which are not allowed within RFC 959 <string>.
305 Note: The input string is in the client's encoding which might
306 not be ASCII, so escape sequences \r & \n must be used instead
307 of hex values 0x0d & 0x0a.
309 static bool isBadFtpString(const char *string)
311 return ((NULL != strchr(string, '\r')) ||
312 (NULL != strchr(string, '\n'))) ? TRUE : FALSE;
315 /***********************************************************************
317 * AcceptServerConnect()
319 * After connection request is received from the server this function is
320 * called to accept the connection and close the listening socket
323 static CURLcode AcceptServerConnect(struct connectdata *conn)
325 struct SessionHandle *data = conn->data;
326 curl_socket_t sock = conn->sock[SECONDARYSOCKET];
327 curl_socket_t s = CURL_SOCKET_BAD;
329 struct Curl_sockaddr_storage add;
331 struct sockaddr_in add;
333 curl_socklen_t size = (curl_socklen_t) sizeof(add);
335 if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
338 s=accept(sock, (struct sockaddr *) &add, &size);
340 Curl_closesocket(conn, sock); /* close the first socket */
342 if(CURL_SOCKET_BAD == s) {
343 failf(data, "Error accept()ing server connect");
344 return CURLE_FTP_PORT_FAILED;
346 infof(data, "Connection accepted from server\n");
348 conn->sock[SECONDARYSOCKET] = s;
349 (void)curlx_nonblock(s, TRUE); /* enable non-blocking */
350 conn->sock_accepted[SECONDARYSOCKET] = TRUE;
352 if(data->set.fsockopt) {
355 /* activate callback for setting socket options */
356 error = data->set.fsockopt(data->set.sockopt_client,
358 CURLSOCKTYPE_ACCEPT);
361 Curl_closesocket(conn, s); /* close the socket and bail out */
362 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
363 return CURLE_ABORTED_BY_CALLBACK;
372 * ftp_timeleft_accept() returns the amount of milliseconds left allowed for
373 * waiting server to connect. If the value is negative, the timeout time has
376 * The start time is stored in progress.t_acceptdata - as set with
377 * Curl_pgrsTime(..., TIMER_STARTACCEPT);
380 static long ftp_timeleft_accept(struct SessionHandle *data)
382 long timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
386 if(data->set.accepttimeout > 0)
387 timeout_ms = data->set.accepttimeout;
391 /* check if the generic timeout possibly is set shorter */
392 other = Curl_timeleft(data, &now, FALSE);
393 if(other && (other < timeout_ms))
394 /* note that this also works fine for when other happens to be negative
395 due to it already having elapsed */
398 /* subtract elapsed time */
399 timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata);
401 /* avoid returning 0 as that means no timeout! */
409 /***********************************************************************
411 * ReceivedServerConnect()
413 * After allowing server to connect to us from data port, this function
414 * checks both data connection for connection establishment and ctrl
415 * connection for a negative response regarding a failure in connecting
418 static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
420 struct SessionHandle *data = conn->data;
421 curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
422 curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
423 struct ftp_conn *ftpc = &conn->proto.ftpc;
424 struct pingpong *pp = &ftpc->pp;
432 timeout_ms = ftp_timeleft_accept(data);
433 infof(data, "Checking for server connect\n");
435 /* if a timeout was already reached, bail out */
436 failf(data, "Accept timeout occurred while waiting server connect");
437 return CURLE_FTP_ACCEPT_TIMEOUT;
440 /* First check whether there is a cached response from server */
441 if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
442 /* Data connection could not be established, let's return */
443 infof(data, "There is negative response in cache while serv connect\n");
444 Curl_GetFTPResponse(&nread, conn, &ftpcode);
445 return CURLE_FTP_ACCEPT_FAILED;
448 result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
450 /* see if the connection request is already here */
454 failf(data, "Error while waiting for server connect");
455 return CURLE_FTP_ACCEPT_FAILED;
456 case 0: /* Server connect is not received yet */
460 if(result & CURL_CSELECT_IN2) {
461 infof(data, "Ready to accept data connection from server\n");
464 else if(result & CURL_CSELECT_IN) {
465 infof(data, "Ctrl conn has data while waiting for data conn\n");
466 Curl_GetFTPResponse(&nread, conn, &ftpcode);
469 return CURLE_FTP_ACCEPT_FAILED;
471 return CURLE_FTP_WEIRD_SERVER_REPLY;
481 /***********************************************************************
485 * After connection from server is accepted this function is called to
486 * setup transfer parameters and initiate the data transfer.
489 static CURLcode InitiateTransfer(struct connectdata *conn)
491 struct SessionHandle *data = conn->data;
492 struct FTP *ftp = data->req.protop;
493 CURLcode result = CURLE_OK;
495 if(conn->ssl[SECONDARYSOCKET].use) {
496 /* since we only have a plaintext TCP connection here, we must now
497 * do the TLS stuff */
498 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
499 result = Curl_ssl_connect(conn, SECONDARYSOCKET);
504 if(conn->proto.ftpc.state_saved == FTP_STOR) {
505 *(ftp->bytecountp)=0;
507 /* When we know we're uploading a specified file, we can get the file
508 size prior to the actual upload. */
510 Curl_pgrsSetUploadSize(data, data->state.infilesize);
512 /* set the SO_SNDBUF for the secondary socket for those who need it */
513 Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
515 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
516 SECONDARYSOCKET, ftp->bytecountp);
520 Curl_setup_transfer(conn, SECONDARYSOCKET,
521 conn->proto.ftpc.retr_size_saved, FALSE,
522 ftp->bytecountp, -1, NULL); /* no upload here */
525 conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
526 state(conn, FTP_STOP);
531 /***********************************************************************
533 * AllowServerConnect()
535 * When we've issue the PORT command, we have told the server to connect to
536 * us. This function checks whether data connection is established if so it is
540 static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
542 struct SessionHandle *data = conn->data;
544 CURLcode result = CURLE_OK;
547 infof(data, "Preparing for accepting server on data port\n");
549 /* Save the time we start accepting server connect */
550 Curl_pgrsTime(data, TIMER_STARTACCEPT);
552 timeout_ms = ftp_timeleft_accept(data);
554 /* if a timeout was already reached, bail out */
555 failf(data, "Accept timeout occurred while waiting server connect");
556 return CURLE_FTP_ACCEPT_TIMEOUT;
559 /* see if the connection request is already here */
560 result = ReceivedServerConnect(conn, connected);
565 result = AcceptServerConnect(conn);
569 result = InitiateTransfer(conn);
574 /* Add timeout to multi handle and break out of the loop */
575 if(!result && *connected == FALSE) {
576 if(data->set.accepttimeout > 0)
577 Curl_expire(data, data->set.accepttimeout);
579 Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
586 /* macro to check for a three-digit ftp status code at the start of the
588 #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
591 /* macro to check for the last line in an FTP server response */
592 #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
594 static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len,
599 if((len > 3) && LASTLINE(line)) {
600 *code = curlx_sltosi(strtol(line, NULL, 10));
607 static CURLcode ftp_readresp(curl_socket_t sockfd,
609 int *ftpcode, /* return the ftp-code if done */
610 size_t *size) /* size of the response */
612 struct connectdata *conn = pp->conn;
613 struct SessionHandle *data = conn->data;
615 char * const buf = data->state.buffer;
617 CURLcode result = CURLE_OK;
620 result = Curl_pp_readresp(sockfd, pp, &code, size);
622 #if defined(HAVE_GSSAPI)
623 /* handle the security-oriented responses 6xx ***/
624 /* FIXME: some errorchecking perhaps... ***/
627 code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
630 code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
633 code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
636 /* normal ftp stuff we pass through! */
641 /* store the latest code for later retrieval */
642 data->info.httpcode=code;
648 /* 421 means "Service not available, closing control connection." and FTP
649 * servers use it to signal that idle session timeout has been exceeded.
650 * If we ignored the response, it could end up hanging in some cases.
652 * This response code can come at any point so having it treated
653 * generically is a good idea.
655 infof(data, "We got a 421 - timeout!\n");
656 state(conn, FTP_STOP);
657 return CURLE_OPERATION_TIMEDOUT;
663 /* --- parse FTP server responses --- */
666 * Curl_GetFTPResponse() is a BLOCKING function to read the full response
667 * from a server after a command.
671 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
672 struct connectdata *conn,
673 int *ftpcode) /* return the ftp-code */
676 * We cannot read just one byte per read() and then go back to select() as
677 * the OpenSSL read() doesn't grok that properly.
679 * Alas, read as much as possible, split up into lines, use the ending
680 * line in a response or continue reading. */
682 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
683 long timeout; /* timeout in milliseconds */
685 struct SessionHandle *data = conn->data;
686 CURLcode result = CURLE_OK;
687 struct ftp_conn *ftpc = &conn->proto.ftpc;
688 struct pingpong *pp = &ftpc->pp;
691 int value_to_be_ignored=0;
694 *ftpcode = 0; /* 0 for errors */
696 /* make the pointer point to something for the rest of this function */
697 ftpcode = &value_to_be_ignored;
701 while(!*ftpcode && !result) {
702 /* check and reset timeout value every lap */
703 timeout = Curl_pp_state_timeout(pp);
706 failf(data, "FTP response timeout");
707 return CURLE_OPERATION_TIMEDOUT; /* already too little time */
710 interval_ms = 1000; /* use 1 second timeout intervals */
711 if(timeout < interval_ms)
712 interval_ms = timeout;
715 * Since this function is blocking, we need to wait here for input on the
716 * connection and only then we call the response reading function. We do
717 * timeout at least every second to make the timeout check run.
719 * A caution here is that the ftp_readresp() function has a cache that may
720 * contain pieces of a response from the previous invoke and we need to
721 * make sure we don't just wait for input while there is unhandled data in
722 * that cache. But also, if the cache is there, we call ftp_readresp() and
723 * the cache wasn't good enough to continue we must not just busy-loop
724 * around this function.
728 if(pp->cache && (cache_skip < 2)) {
730 * There's a cache left since before. We then skipping the wait for
731 * socket action, unless this is the same cache like the previous round
732 * as then the cache was deemed not enough to act on and we then need to
733 * wait for more data anyway.
737 switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, interval_ms)) {
738 case -1: /* select() error, stop reading */
739 failf(data, "FTP response aborted due to select/poll error: %d",
741 return CURLE_RECV_ERROR;
743 case 0: /* timeout */
744 if(Curl_pgrsUpdate(conn))
745 return CURLE_ABORTED_BY_CALLBACK;
746 continue; /* just continue in our loop for the timeout duration */
748 default: /* for clarity */
752 result = ftp_readresp(sockfd, pp, ftpcode, &nread);
756 if(!nread && pp->cache)
757 /* bump cache skip counter as on repeated skips we must wait for more
761 /* when we got data or there is no cache left, we reset the cache skip
767 } /* while there's buffer left and loop is requested */
769 pp->pending_resp = FALSE;
774 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
775 /* for debug purposes */
776 static const char * const ftp_state_names[]={
815 /* This is the ONLY way to change FTP state! */
816 static void _state(struct connectdata *conn,
823 struct ftp_conn *ftpc = &conn->proto.ftpc;
825 #if defined(DEBUGBUILD)
827 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
830 if(ftpc->state != newstate)
831 infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
832 (void *)ftpc, lineno, ftp_state_names[ftpc->state],
833 ftp_state_names[newstate]);
837 ftpc->state = newstate;
840 static CURLcode ftp_state_user(struct connectdata *conn)
843 struct FTP *ftp = conn->data->req.protop;
845 PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
847 state(conn, FTP_USER);
848 conn->data->state.ftp_trying_alternative = FALSE;
853 static CURLcode ftp_state_pwd(struct connectdata *conn)
857 /* send PWD to discover our entry point */
858 PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD");
859 state(conn, FTP_PWD);
864 /* For the FTP "protocol connect" and "doing" phases only */
865 static int ftp_getsock(struct connectdata *conn,
866 curl_socket_t *socks,
869 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
872 /* For the FTP "DO_MORE" phase only */
873 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
876 struct ftp_conn *ftpc = &conn->proto.ftpc;
879 return GETSOCK_BLANK;
881 /* When in DO_MORE state, we could be either waiting for us to connect to a
882 * remote site, or we could wait for that site to connect to us. Or just
883 * handle ordinary commands.
886 if(FTP_STOP == ftpc->state) {
887 int bits = GETSOCK_READSOCK(0);
889 /* if stopped and still in this state, then we're also waiting for a
890 connect on the secondary connection */
891 socks[0] = conn->sock[FIRSTSOCKET];
893 if(!conn->data->set.ftp_use_port) {
896 /* PORT is used to tell the server to connect to us, and during that we
897 don't do happy eyeballs, but we do if we connect to the server */
898 for(s=1, i=0; i<2; i++) {
899 if(conn->tempsock[i] != CURL_SOCKET_BAD) {
900 socks[s] = conn->tempsock[i];
901 bits |= GETSOCK_WRITESOCK(s++);
906 socks[1] = conn->sock[SECONDARYSOCKET];
907 bits |= GETSOCK_WRITESOCK(1);
913 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
916 /* This is called after the FTP_QUOTE state is passed.
918 ftp_state_cwd() sends the range of CWD commands to the server to change to
919 the correct directory. It may also need to send MKD commands to create
920 missing ones, if that option is enabled.
922 static CURLcode ftp_state_cwd(struct connectdata *conn)
924 CURLcode result = CURLE_OK;
925 struct ftp_conn *ftpc = &conn->proto.ftpc;
928 /* already done and fine */
929 result = ftp_state_mdtm(conn);
931 ftpc->count2 = 0; /* count2 counts failed CWDs */
933 /* count3 is set to allow a MKD to fail once. In the case when first CWD
934 fails and then MKD fails (due to another session raced it to create the
935 dir) this then allows for a second try to CWD to it */
936 ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
938 if(conn->bits.reuse && ftpc->entrypath) {
939 /* This is a re-used connection. Since we change directory to where the
940 transfer is taking place, we must first get back to the original dir
941 where we ended up after login: */
942 ftpc->count1 = 0; /* we count this as the first path, then we add one
943 for all upcoming ones in the ftp->dirs[] array */
944 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
945 state(conn, FTP_CWD);
950 /* issue the first CWD, the rest is sent when the CWD responses are
952 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
953 state(conn, FTP_CWD);
956 /* No CWD necessary */
957 result = ftp_state_mdtm(conn);
970 static CURLcode ftp_state_use_port(struct connectdata *conn,
971 ftpport fcmd) /* start with this */
974 CURLcode result = CURLE_OK;
975 struct ftp_conn *ftpc = &conn->proto.ftpc;
976 struct SessionHandle *data=conn->data;
977 curl_socket_t portsock= CURL_SOCKET_BAD;
978 char myhost[256] = "";
980 struct Curl_sockaddr_storage ss;
981 Curl_addrinfo *res, *ai;
982 curl_socklen_t sslen;
983 char hbuf[NI_MAXHOST];
984 struct sockaddr *sa=(struct sockaddr *)&ss;
985 struct sockaddr_in * const sa4 = (void *)sa;
987 struct sockaddr_in6 * const sa6 = (void *)sa;
990 static const char mode[][5] = { "EPRT", "PORT" };
994 char *string_ftpport = data->set.str[STRING_FTPPORT];
995 struct Curl_dns_entry *h=NULL;
996 unsigned short port_min = 0;
997 unsigned short port_max = 0;
999 bool possibly_non_local = TRUE;
1003 /* Step 1, figure out what is requested,
1005 * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
1008 if(data->set.str[STRING_FTPPORT] &&
1009 (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
1012 size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
1013 INET6_ADDRSTRLEN : strlen(string_ftpport);
1015 size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
1016 INET_ADDRSTRLEN : strlen(string_ftpport);
1018 char *ip_start = string_ftpport;
1019 char *ip_end = NULL;
1020 char *port_start = NULL;
1021 char *port_sep = NULL;
1023 addr = calloc(addrlen+1, 1);
1025 return CURLE_OUT_OF_MEMORY;
1028 if(*string_ftpport == '[') {
1029 /* [ipv6]:port(-range) */
1030 ip_start = string_ftpport + 1;
1031 if((ip_end = strchr(string_ftpport, ']')) != NULL )
1032 strncpy(addr, ip_start, ip_end - ip_start);
1036 if(*string_ftpport == ':') {
1038 ip_end = string_ftpport;
1040 else if((ip_end = strchr(string_ftpport, ':')) != NULL) {
1041 /* either ipv6 or (ipv4|domain|interface):port(-range) */
1043 if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
1045 port_min = port_max = 0;
1046 strcpy(addr, string_ftpport);
1047 ip_end = NULL; /* this got no port ! */
1051 /* (ipv4|domain|interface):port(-range) */
1052 strncpy(addr, string_ftpport, ip_end - ip_start );
1055 /* ipv4|interface */
1056 strcpy(addr, string_ftpport);
1058 /* parse the port */
1059 if(ip_end != NULL) {
1060 if((port_start = strchr(ip_end, ':')) != NULL) {
1061 port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
1062 if((port_sep = strchr(port_start, '-')) != NULL) {
1063 port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
1066 port_max = port_min;
1070 /* correct errors like:
1072 * :-4711 , in this case port_min is (unsigned)-1,
1073 * therefore port_min > port_max for all cases
1074 * but port_max = (unsigned)-1
1076 if(port_min > port_max )
1077 port_min = port_max = 0;
1081 /* attempt to get the address of the given interface name */
1082 switch(Curl_if2ip(conn->ip_addr->ai_family,
1083 Curl_ipv6_scope(conn->ip_addr->ai_addr),
1084 conn->scope_id, addr, hbuf, sizeof(hbuf))) {
1085 case IF2IP_NOT_FOUND:
1086 /* not an interface, use the given string as host name instead */
1089 case IF2IP_AF_NOT_SUPPORTED:
1090 return CURLE_FTP_PORT_FAILED;
1092 host = hbuf; /* use the hbuf for host name */
1096 /* there was only a port(-range) given, default the host */
1098 } /* data->set.ftpport */
1101 /* not an interface and not a host name, get default by extracting
1102 the IP from the control connection */
1105 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1106 failf(data, "getsockname() failed: %s",
1107 Curl_strerror(conn, SOCKERRNO) );
1108 Curl_safefree(addr);
1109 return CURLE_FTP_PORT_FAILED;
1111 switch(sa->sa_family) {
1114 Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
1118 Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
1121 host = hbuf; /* use this host name */
1122 possibly_non_local = FALSE; /* we know it is local now */
1125 /* resolv ip/host to ip */
1126 rc = Curl_resolv(conn, host, 0, &h);
1127 if(rc == CURLRESOLV_PENDING)
1128 (void)Curl_resolver_wait_resolv(conn, &h);
1131 /* when we return from this function, we can forget about this entry
1132 to we can unlock it now already */
1133 Curl_resolv_unlock(data, h);
1136 res = NULL; /* failure! */
1139 failf(data, "failed to resolve the address provided to PORT: %s", host);
1140 Curl_safefree(addr);
1141 return CURLE_FTP_PORT_FAILED;
1144 Curl_safefree(addr);
1147 /* step 2, create a socket for the requested address */
1149 portsock = CURL_SOCKET_BAD;
1151 for(ai = res; ai; ai = ai->ai_next) {
1152 result = Curl_socket(conn, ai, NULL, &portsock);
1160 failf(data, "socket failure: %s", Curl_strerror(conn, error));
1161 return CURLE_FTP_PORT_FAILED;
1164 /* step 3, bind to a suitable local address */
1166 memcpy(sa, ai->ai_addr, ai->ai_addrlen);
1167 sslen = ai->ai_addrlen;
1169 for(port = port_min; port <= port_max;) {
1170 if(sa->sa_family == AF_INET)
1171 sa4->sin_port = htons(port);
1174 sa6->sin6_port = htons(port);
1176 /* Try binding the given address. */
1177 if(bind(portsock, sa, sslen) ) {
1180 if(possibly_non_local && (error == EADDRNOTAVAIL)) {
1181 /* The requested bind address is not local. Use the address used for
1182 * the control connection instead and restart the port loop
1185 infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
1186 Curl_strerror(conn, error) );
1189 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1190 failf(data, "getsockname() failed: %s",
1191 Curl_strerror(conn, SOCKERRNO) );
1192 Curl_closesocket(conn, portsock);
1193 return CURLE_FTP_PORT_FAILED;
1196 possibly_non_local = FALSE; /* don't try this again */
1199 else if(error != EADDRINUSE && error != EACCES) {
1200 failf(data, "bind(port=%hu) failed: %s", port,
1201 Curl_strerror(conn, error) );
1202 Curl_closesocket(conn, portsock);
1203 return CURLE_FTP_PORT_FAILED;
1212 /* maybe all ports were in use already*/
1213 if(port > port_max) {
1214 failf(data, "bind() failed, we ran out of ports!");
1215 Curl_closesocket(conn, portsock);
1216 return CURLE_FTP_PORT_FAILED;
1219 /* get the name again after the bind() so that we can extract the
1220 port number it uses now */
1222 if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
1223 failf(data, "getsockname() failed: %s",
1224 Curl_strerror(conn, SOCKERRNO) );
1225 Curl_closesocket(conn, portsock);
1226 return CURLE_FTP_PORT_FAILED;
1229 /* step 4, listen on the socket */
1231 if(listen(portsock, 1)) {
1232 failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
1233 Curl_closesocket(conn, portsock);
1234 return CURLE_FTP_PORT_FAILED;
1237 /* step 5, send the proper FTP command */
1239 /* get a plain printable version of the numerical address to work with
1241 Curl_printable_address(ai, myhost, sizeof(myhost));
1244 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
1245 /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
1246 request and enable EPRT again! */
1247 conn->bits.ftp_use_eprt = TRUE;
1250 for(; fcmd != DONE; fcmd++) {
1252 if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
1253 /* if disabled, goto next */
1256 if((PORT == fcmd) && sa->sa_family != AF_INET)
1257 /* PORT is IPv4 only */
1260 switch(sa->sa_family) {
1262 port = ntohs(sa4->sin_port);
1266 port = ntohs(sa6->sin6_port);
1270 continue; /* might as well skip this */
1275 * Two fine examples from RFC2428;
1277 * EPRT |1|132.235.1.2|6275|
1279 * EPRT |2|1080::8:800:200C:417A|5282|
1282 result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
1283 sa->sa_family == AF_INET?1:2,
1286 failf(data, "Failure sending EPRT command: %s",
1287 curl_easy_strerror(result));
1288 Curl_closesocket(conn, portsock);
1289 /* don't retry using PORT */
1290 ftpc->count1 = PORT;
1292 state(conn, FTP_STOP);
1297 else if(PORT == fcmd) {
1298 char *source = myhost;
1301 /* translate x.x.x.x to x,x,x,x */
1302 while(source && *source) {
1311 snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
1313 result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
1315 failf(data, "Failure sending PORT command: %s",
1316 curl_easy_strerror(result));
1317 Curl_closesocket(conn, portsock);
1319 state(conn, FTP_STOP);
1326 /* store which command was sent */
1327 ftpc->count1 = fcmd;
1329 /* we set the secondary socket variable to this for now, it is only so that
1330 the cleanup function will close it in case we fail before the true
1331 secondary stuff is made */
1332 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
1333 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
1334 conn->sock[SECONDARYSOCKET] = portsock;
1336 /* this tcpconnect assignment below is a hackish work-around to make the
1337 multi interface with active FTP work - as it will not wait for a
1338 (passive) connect in Curl_is_connected().
1340 The *proper* fix is to make sure that the active connection from the
1341 server is done in a non-blocking way. Currently, it is still BLOCKING.
1343 conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
1345 state(conn, FTP_PORT);
1349 static CURLcode ftp_state_use_pasv(struct connectdata *conn)
1351 struct ftp_conn *ftpc = &conn->proto.ftpc;
1352 CURLcode result = CURLE_OK;
1354 Here's the excecutive summary on what to do:
1356 PASV is RFC959, expect:
1357 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1359 LPSV is RFC1639, expect:
1360 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1362 EPSV is RFC2428, expect:
1363 229 Entering Extended Passive Mode (|||port|)
1367 static const char mode[][5] = { "EPSV", "PASV" };
1371 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
1372 /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1373 request and enable EPSV again! */
1374 conn->bits.ftp_use_epsv = TRUE;
1377 modeoff = conn->bits.ftp_use_epsv?0:1;
1379 PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
1381 ftpc->count1 = modeoff;
1382 state(conn, FTP_PASV);
1383 infof(conn->data, "Connect data stream passively\n");
1389 * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc.
1391 * REST is the last command in the chain of commands when a "head"-like
1392 * request is made. Thus, if an actual transfer is to be made this is where we
1393 * take off for real.
1395 static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
1397 CURLcode result = CURLE_OK;
1398 struct FTP *ftp = conn->data->req.protop;
1399 struct SessionHandle *data = conn->data;
1401 if(ftp->transfer != FTPTRANSFER_BODY) {
1402 /* doesn't transfer any data */
1404 /* still possibly do PRE QUOTE jobs */
1405 state(conn, FTP_RETR_PREQUOTE);
1406 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1408 else if(data->set.ftp_use_port) {
1409 /* We have chosen to use the PORT (or similar) command */
1410 result = ftp_state_use_port(conn, EPRT);
1413 /* We have chosen (this is default) to use the PASV (or similar) command */
1414 if(data->set.ftp_use_pret) {
1415 /* The user has requested that we send a PRET command
1416 to prepare the server for the upcoming PASV */
1417 if(!conn->proto.ftpc.file) {
1418 PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
1419 data->set.str[STRING_CUSTOMREQUEST]?
1420 data->set.str[STRING_CUSTOMREQUEST]:
1421 (data->set.ftp_list_only?"NLST":"LIST"));
1423 else if(data->set.upload) {
1424 PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
1427 PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
1429 state(conn, FTP_PRET);
1432 result = ftp_state_use_pasv(conn);
1438 static CURLcode ftp_state_rest(struct connectdata *conn)
1440 CURLcode result = CURLE_OK;
1441 struct FTP *ftp = conn->data->req.protop;
1442 struct ftp_conn *ftpc = &conn->proto.ftpc;
1444 if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
1445 /* if a "head"-like request is being made (on a file) */
1447 /* Determine if server can respond to REST command and therefore
1448 whether it supports range */
1449 PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
1451 state(conn, FTP_REST);
1454 result = ftp_state_prepare_transfer(conn);
1459 static CURLcode ftp_state_size(struct connectdata *conn)
1461 CURLcode result = CURLE_OK;
1462 struct FTP *ftp = conn->data->req.protop;
1463 struct ftp_conn *ftpc = &conn->proto.ftpc;
1465 if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
1466 /* if a "head"-like request is being made (on a file) */
1468 /* we know ftpc->file is a valid pointer to a file name */
1469 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1471 state(conn, FTP_SIZE);
1474 result = ftp_state_rest(conn);
1479 static CURLcode ftp_state_list(struct connectdata *conn)
1481 CURLcode result = CURLE_OK;
1482 struct SessionHandle *data = conn->data;
1484 /* If this output is to be machine-parsed, the NLST command might be better
1485 to use, since the LIST command output is not specified or standard in any
1486 way. It has turned out that the NLST list output is not the same on all
1487 servers either... */
1490 if FTPFILE_NOCWD was specified, we are currently in
1491 the user's home directory, so we should add the path
1492 as argument for the LIST / NLST / or custom command.
1493 Whether the server will support this, is uncertain.
1495 The other ftp_filemethods will CWD into dir/dir/ first and
1496 then just do LIST (in that case: nothing to do here)
1498 char *cmd,*lstArg,*slashPos;
1501 if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
1503 data->state.path[0] &&
1504 strchr(data->state.path,'/')) {
1506 lstArg = strdup(data->state.path);
1508 return CURLE_OUT_OF_MEMORY;
1510 /* Check if path does not end with /, as then we cut off the file part */
1511 if(lstArg[strlen(lstArg) - 1] != '/') {
1513 /* chop off the file part if format is dir/dir/file */
1514 slashPos = strrchr(lstArg,'/');
1516 *(slashPos+1) = '\0';
1520 cmd = aprintf( "%s%s%s",
1521 data->set.str[STRING_CUSTOMREQUEST]?
1522 data->set.str[STRING_CUSTOMREQUEST]:
1523 (data->set.ftp_list_only?"NLST":"LIST"),
1525 lstArg? lstArg: "" );
1530 return CURLE_OUT_OF_MEMORY;
1533 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
1543 state(conn, FTP_LIST);
1548 static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
1550 CURLcode result = CURLE_OK;
1552 /* We've sent the TYPE, now we must send the list of prequote strings */
1554 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1559 static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
1561 CURLcode result = CURLE_OK;
1563 /* We've sent the TYPE, now we must send the list of prequote strings */
1565 result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
1570 static CURLcode ftp_state_type(struct connectdata *conn)
1572 CURLcode result = CURLE_OK;
1573 struct FTP *ftp = conn->data->req.protop;
1574 struct SessionHandle *data = conn->data;
1575 struct ftp_conn *ftpc = &conn->proto.ftpc;
1577 /* If we have selected NOBODY and HEADER, it means that we only want file
1578 information. Which in FTP can't be much more than the file size and
1580 if(data->set.opt_no_body && ftpc->file &&
1581 ftp_need_type(conn, data->set.prefer_ascii)) {
1582 /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
1583 may not support it! It is however the only way we have to get a file's
1586 ftp->transfer = FTPTRANSFER_INFO;
1587 /* this means no actual transfer will be made */
1589 /* Some servers return different sizes for different modes, and thus we
1590 must set the proper type before we check the size */
1591 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
1596 result = ftp_state_size(conn);
1601 /* This is called after the CWD commands have been done in the beginning of
1603 static CURLcode ftp_state_mdtm(struct connectdata *conn)
1605 CURLcode result = CURLE_OK;
1606 struct SessionHandle *data = conn->data;
1607 struct ftp_conn *ftpc = &conn->proto.ftpc;
1609 /* Requested time of file or time-depended transfer? */
1610 if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
1612 /* we have requested to get the modified-time of the file, this is a white
1613 spot as the MDTM is not mentioned in RFC959 */
1614 PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
1616 state(conn, FTP_MDTM);
1619 result = ftp_state_type(conn);
1625 /* This is called after the TYPE and possible quote commands have been sent */
1626 static CURLcode ftp_state_ul_setup(struct connectdata *conn,
1629 CURLcode result = CURLE_OK;
1630 struct FTP *ftp = conn->data->req.protop;
1631 struct SessionHandle *data = conn->data;
1632 struct ftp_conn *ftpc = &conn->proto.ftpc;
1633 int seekerr = CURL_SEEKFUNC_OK;
1635 if((data->state.resume_from && !sizechecked) ||
1636 ((data->state.resume_from > 0) && sizechecked)) {
1637 /* we're about to continue the uploading of a file */
1638 /* 1. get already existing file's size. We use the SIZE command for this
1639 which may not exist in the server! The SIZE command is not in
1642 /* 2. This used to set REST. But since we can do append, we
1643 don't another ftp command. We just skip the source file
1644 offset and then we APPEND the rest on the file instead */
1646 /* 3. pass file-size number of bytes in the source file */
1647 /* 4. lower the infilesize counter */
1648 /* => transfer as usual */
1650 if(data->state.resume_from < 0 ) {
1651 /* Got no given size to start from, figure it out */
1652 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1653 state(conn, FTP_STOR_SIZE);
1658 data->set.ftp_append = TRUE;
1660 /* Let's read off the proper amount of bytes from the input. */
1661 if(conn->seek_func) {
1662 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1666 if(seekerr != CURL_SEEKFUNC_OK) {
1667 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1668 failf(data, "Could not seek stream");
1669 return CURLE_FTP_COULDNT_USE_REST;
1671 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1673 curl_off_t passed=0;
1675 size_t readthisamountnow =
1676 (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
1677 BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
1679 size_t actuallyread =
1680 conn->fread_func(data->state.buffer, 1, readthisamountnow,
1683 passed += actuallyread;
1684 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1685 /* this checks for greater-than only to make sure that the
1686 CURL_READFUNC_ABORT return code still aborts */
1687 failf(data, "Failed to read data");
1688 return CURLE_FTP_COULDNT_USE_REST;
1690 } while(passed < data->state.resume_from);
1693 /* now, decrease the size of the read */
1694 if(data->state.infilesize>0) {
1695 data->state.infilesize -= data->state.resume_from;
1697 if(data->state.infilesize <= 0) {
1698 infof(data, "File already completely uploaded\n");
1700 /* no data to transfer */
1701 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1703 /* Set ->transfer so that we won't get any error in
1704 * ftp_done() because we didn't transfer anything! */
1705 ftp->transfer = FTPTRANSFER_NONE;
1707 state(conn, FTP_STOP);
1711 /* we've passed, proceed as normal */
1714 PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
1717 state(conn, FTP_STOR);
1722 static CURLcode ftp_state_quote(struct connectdata *conn,
1726 CURLcode result = CURLE_OK;
1727 struct SessionHandle *data = conn->data;
1728 struct FTP *ftp = data->req.protop;
1729 struct ftp_conn *ftpc = &conn->proto.ftpc;
1731 struct curl_slist *item;
1736 item = data->set.quote;
1738 case FTP_RETR_PREQUOTE:
1739 case FTP_STOR_PREQUOTE:
1740 item = data->set.prequote;
1743 item = data->set.postquote;
1749 * 'count1' to iterate over the commands to send
1750 * 'count2' to store wether to allow commands to fail
1761 /* Skip count1 items in the linked list */
1762 while((i< ftpc->count1) && item) {
1767 char *cmd = item->data;
1770 ftpc->count2 = 1; /* the sent command is allowed to fail */
1773 ftpc->count2 = 0; /* failure means cancel operation */
1775 PPSENDF(&ftpc->pp, "%s", cmd);
1776 state(conn, instate);
1782 /* No more quote to send, continue to ... */
1786 result = ftp_state_cwd(conn);
1788 case FTP_RETR_PREQUOTE:
1789 if(ftp->transfer != FTPTRANSFER_BODY)
1790 state(conn, FTP_STOP);
1792 if(ftpc->known_filesize != -1) {
1793 Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
1794 result = ftp_state_retr(conn, ftpc->known_filesize);
1797 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1798 state(conn, FTP_RETR_SIZE);
1802 case FTP_STOR_PREQUOTE:
1803 result = ftp_state_ul_setup(conn, FALSE);
1813 /* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
1815 static CURLcode ftp_epsv_disable(struct connectdata *conn)
1817 CURLcode result = CURLE_OK;
1818 infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
1819 /* disable it for next transfer */
1820 conn->bits.ftp_use_epsv = FALSE;
1821 conn->data->state.errorbuf = FALSE; /* allow error message to get
1823 PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV");
1824 conn->proto.ftpc.count1++;
1825 /* remain in/go to the FTP_PASV state */
1826 state(conn, FTP_PASV);
1831 * Perform the necessary magic that needs to be done once the TCP connection
1832 * to the proxy has completed.
1834 static CURLcode proxy_magic(struct connectdata *conn,
1835 char *newhost, unsigned short newport,
1838 CURLcode result = CURLE_OK;
1839 struct SessionHandle *data = conn->data;
1841 #if defined(CURL_DISABLE_PROXY)
1848 switch(conn->proxytype) {
1849 case CURLPROXY_SOCKS5:
1850 case CURLPROXY_SOCKS5_HOSTNAME:
1851 result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost,
1852 newport, SECONDARYSOCKET, conn);
1855 case CURLPROXY_SOCKS4:
1856 result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1857 SECONDARYSOCKET, conn, FALSE);
1860 case CURLPROXY_SOCKS4A:
1861 result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1862 SECONDARYSOCKET, conn, TRUE);
1865 case CURLPROXY_HTTP:
1866 case CURLPROXY_HTTP_1_0:
1867 /* do nothing here. handled later. */
1870 failf(data, "unknown proxytype option given");
1871 result = CURLE_COULDNT_CONNECT;
1875 if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
1877 /* We want "seamless" FTP operations through HTTP proxy tunnel */
1879 /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the
1880 * member conn->proto.http; we want FTP through HTTP and we have to
1881 * change the member temporarily for connecting to the HTTP proxy. After
1882 * Curl_proxyCONNECT we have to set back the member to the original
1883 * struct FTP pointer
1885 struct HTTP http_proxy;
1886 struct FTP *ftp_save = data->req.protop;
1887 memset(&http_proxy, 0, sizeof(http_proxy));
1888 data->req.protop = &http_proxy;
1890 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
1892 data->req.protop = ftp_save;
1897 if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) {
1898 /* the CONNECT procedure is not complete, the tunnel is not yet up */
1899 state(conn, FTP_STOP); /* this phase is completed */
1909 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1912 struct ftp_conn *ftpc = &conn->proto.ftpc;
1914 struct SessionHandle *data=conn->data;
1915 struct Curl_dns_entry *addr=NULL;
1917 unsigned short connectport; /* the local port connect() should use! */
1918 char *str=&data->state.buffer[4]; /* start on the first letter */
1920 if((ftpc->count1 == 0) &&
1922 /* positive EPSV response */
1923 char *ptr = strchr(str, '(');
1928 if(5 == sscanf(ptr, "%c%c%c%u%c",
1934 const char sep1 = separator[0];
1937 /* The four separators should be identical, or else this is an oddly
1938 formatted reply and we bail out immediately. */
1939 for(i=1; i<4; i++) {
1940 if(separator[i] != sep1) {
1941 ptr=NULL; /* set to NULL to signal error */
1946 failf(data, "Illegal port number in EPSV reply");
1947 return CURLE_FTP_WEIRD_PASV_REPLY;
1950 ftpc->newport = (unsigned short)(num & 0xffff);
1952 if(conn->bits.tunnel_proxy ||
1953 conn->proxytype == CURLPROXY_SOCKS5 ||
1954 conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
1955 conn->proxytype == CURLPROXY_SOCKS4 ||
1956 conn->proxytype == CURLPROXY_SOCKS4A)
1957 /* proxy tunnel -> use other host info because ip_addr_str is the
1958 proxy address not the ftp host */
1959 snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s",
1962 /* use the same IP we are already connected to */
1963 snprintf(ftpc->newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
1970 failf(data, "Weirdly formatted EPSV reply");
1971 return CURLE_FTP_WEIRD_PASV_REPLY;
1974 else if((ftpc->count1 == 1) &&
1976 /* positive PASV response */
1981 * Scan for a sequence of six comma-separated numbers and use them as
1982 * IP+port indicators.
1984 * Found reply-strings include:
1985 * "227 Entering Passive Mode (127,0,0,1,4,51)"
1986 * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1987 * "227 Entering passive mode. 127,0,0,1,4,51"
1990 if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1991 &ip[0], &ip[1], &ip[2], &ip[3],
1992 &port[0], &port[1]))
1998 failf(data, "Couldn't interpret the 227-response");
1999 return CURLE_FTP_WEIRD_227_FORMAT;
2002 /* we got OK from server */
2003 if(data->set.ftp_skip_ip) {
2004 /* told to ignore the remotely given IP but instead use the one we used
2005 for the control connection */
2006 infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
2007 ip[0], ip[1], ip[2], ip[3],
2009 if(conn->bits.tunnel_proxy ||
2010 conn->proxytype == CURLPROXY_SOCKS5 ||
2011 conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
2012 conn->proxytype == CURLPROXY_SOCKS4 ||
2013 conn->proxytype == CURLPROXY_SOCKS4A)
2014 /* proxy tunnel -> use other host info because ip_addr_str is the
2015 proxy address not the ftp host */
2016 snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s", conn->host.name);
2018 snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s",
2022 snprintf(ftpc->newhost, sizeof(ftpc->newhost),
2023 "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
2024 ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
2026 else if(ftpc->count1 == 0) {
2027 /* EPSV failed, move on to PASV */
2028 return ftp_epsv_disable(conn);
2031 failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
2032 return CURLE_FTP_WEIRD_PASV_REPLY;
2035 if(conn->bits.proxy) {
2037 * This connection uses a proxy and we need to connect to the proxy again
2038 * here. We don't want to rely on a former host lookup that might've
2039 * expired now, instead we remake the lookup here and now!
2041 rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
2042 if(rc == CURLRESOLV_PENDING)
2043 /* BLOCKING, ignores the return code but 'addr' will be NULL in
2045 (void)Curl_resolver_wait_resolv(conn, &addr);
2048 (unsigned short)conn->port; /* we connect to the proxy's port */
2051 failf(data, "Can't resolve proxy host %s:%hu",
2052 conn->proxy.name, connectport);
2053 return CURLE_FTP_CANT_GET_HOST;
2057 /* normal, direct, ftp connection */
2058 rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr);
2059 if(rc == CURLRESOLV_PENDING)
2061 (void)Curl_resolver_wait_resolv(conn, &addr);
2063 connectport = ftpc->newport; /* we connect to the remote port */
2066 failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
2067 return CURLE_FTP_CANT_GET_HOST;
2071 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
2072 result = Curl_connecthost(conn, addr);
2074 Curl_resolv_unlock(data, addr); /* we're done using this address */
2077 if(ftpc->count1 == 0 && ftpcode == 229)
2078 return ftp_epsv_disable(conn);
2085 * When this is used from the multi interface, this might've returned with
2086 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
2087 * connect to connect.
2090 if(data->set.verbose)
2091 /* this just dumps information about this second connection */
2092 ftp_pasv_verbose(conn, conn->ip_addr, ftpc->newhost, connectport);
2094 conn->bits.do_more = TRUE;
2095 state(conn, FTP_STOP); /* this phase is completed */
2100 static CURLcode ftp_state_port_resp(struct connectdata *conn,
2103 struct SessionHandle *data = conn->data;
2104 struct ftp_conn *ftpc = &conn->proto.ftpc;
2105 ftpport fcmd = (ftpport)ftpc->count1;
2106 CURLcode result = CURLE_OK;
2108 if(ftpcode != 200) {
2109 /* the command failed */
2112 infof(data, "disabling EPRT usage\n");
2113 conn->bits.ftp_use_eprt = FALSE;
2118 failf(data, "Failed to do PORT");
2119 result = CURLE_FTP_PORT_FAILED;
2123 result = ftp_state_use_port(conn, fcmd);
2126 infof(data, "Connect data stream actively\n");
2127 state(conn, FTP_STOP); /* end of DO phase */
2128 result = ftp_dophase_done(conn, FALSE);
2134 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
2137 CURLcode result = CURLE_OK;
2138 struct SessionHandle *data=conn->data;
2139 struct FTP *ftp = data->req.protop;
2140 struct ftp_conn *ftpc = &conn->proto.ftpc;
2145 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
2146 last .sss part is optional and means fractions of a second */
2147 int year, month, day, hour, minute, second;
2148 char *buf = data->state.buffer;
2149 if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
2150 &year, &month, &day, &hour, &minute, &second)) {
2151 /* we have a time, reformat it */
2152 time_t secs=time(NULL);
2153 /* using the good old yacc/bison yuck */
2154 snprintf(buf, sizeof(conn->data->state.buffer),
2155 "%04d%02d%02d %02d:%02d:%02d GMT",
2156 year, month, day, hour, minute, second);
2157 /* now, convert this into a time() value: */
2158 data->info.filetime = (long)curl_getdate(buf, &secs);
2161 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2162 /* If we asked for a time of the file and we actually got one as well,
2163 we "emulate" a HTTP-style header in our output. */
2165 if(data->set.opt_no_body &&
2167 data->set.get_filetime &&
2168 (data->info.filetime>=0) ) {
2169 time_t filetime = (time_t)data->info.filetime;
2171 const struct tm *tm = &buffer;
2173 result = Curl_gmtime(filetime, &buffer);
2177 /* format: "Tue, 15 Nov 1994 12:45:26" */
2178 snprintf(buf, BUFSIZE-1,
2179 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
2180 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2182 Curl_month[tm->tm_mon],
2187 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2190 } /* end of a ridiculous amount of conditionals */
2195 infof(data, "unsupported MDTM reply format\n");
2197 case 550: /* "No such file or directory" */
2198 failf(data, "Given file does not exist");
2199 result = CURLE_FTP_COULDNT_RETR_FILE;
2203 if(data->set.timecondition) {
2204 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2205 switch(data->set.timecondition) {
2206 case CURL_TIMECOND_IFMODSINCE:
2208 if(data->info.filetime <= data->set.timevalue) {
2209 infof(data, "The requested document is not new enough\n");
2210 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2211 data->info.timecond = TRUE;
2212 state(conn, FTP_STOP);
2216 case CURL_TIMECOND_IFUNMODSINCE:
2217 if(data->info.filetime > data->set.timevalue) {
2218 infof(data, "The requested document is not old enough\n");
2219 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2220 data->info.timecond = TRUE;
2221 state(conn, FTP_STOP);
2228 infof(data, "Skipping time comparison\n");
2233 result = ftp_state_type(conn);
2238 static CURLcode ftp_state_type_resp(struct connectdata *conn,
2242 CURLcode result = CURLE_OK;
2243 struct SessionHandle *data=conn->data;
2245 if(ftpcode/100 != 2) {
2246 /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
2247 successful 'TYPE I'. While that is not as RFC959 says, it is still a
2248 positive response code and we allow that. */
2249 failf(data, "Couldn't set desired mode");
2250 return CURLE_FTP_COULDNT_SET_TYPE;
2253 infof(data, "Got a %03d response code instead of the assumed 200\n",
2256 if(instate == FTP_TYPE)
2257 result = ftp_state_size(conn);
2258 else if(instate == FTP_LIST_TYPE)
2259 result = ftp_state_list(conn);
2260 else if(instate == FTP_RETR_TYPE)
2261 result = ftp_state_retr_prequote(conn);
2262 else if(instate == FTP_STOR_TYPE)
2263 result = ftp_state_stor_prequote(conn);
2268 static CURLcode ftp_state_retr(struct connectdata *conn,
2269 curl_off_t filesize)
2271 CURLcode result = CURLE_OK;
2272 struct SessionHandle *data=conn->data;
2273 struct FTP *ftp = data->req.protop;
2274 struct ftp_conn *ftpc = &conn->proto.ftpc;
2276 if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
2277 failf(data, "Maximum file size exceeded");
2278 return CURLE_FILESIZE_EXCEEDED;
2280 ftp->downloadsize = filesize;
2282 if(data->state.resume_from) {
2283 /* We always (attempt to) get the size of downloads, so it is done before
2284 this even when not doing resumes. */
2285 if(filesize == -1) {
2286 infof(data, "ftp server doesn't support SIZE\n");
2287 /* We couldn't get the size and therefore we can't know if there really
2288 is a part of the file left to get, although the server will just
2289 close the connection when we start the connection so it won't cause
2290 us any harm, just not make us exit as nicely. */
2293 /* We got a file size report, so we check that there actually is a
2294 part of the file left to get, or else we go home. */
2295 if(data->state.resume_from< 0) {
2296 /* We're supposed to download the last abs(from) bytes */
2297 if(filesize < -data->state.resume_from) {
2298 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2299 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2300 data->state.resume_from, filesize);
2301 return CURLE_BAD_DOWNLOAD_RESUME;
2303 /* convert to size to download */
2304 ftp->downloadsize = -data->state.resume_from;
2305 /* download from where? */
2306 data->state.resume_from = filesize - ftp->downloadsize;
2309 if(filesize < data->state.resume_from) {
2310 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2311 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2312 data->state.resume_from, filesize);
2313 return CURLE_BAD_DOWNLOAD_RESUME;
2315 /* Now store the number of bytes we are expected to download */
2316 ftp->downloadsize = filesize-data->state.resume_from;
2320 if(ftp->downloadsize == 0) {
2321 /* no data to transfer */
2322 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2323 infof(data, "File already completely downloaded\n");
2325 /* Set ->transfer so that we won't get any error in ftp_done()
2326 * because we didn't transfer the any file */
2327 ftp->transfer = FTPTRANSFER_NONE;
2328 state(conn, FTP_STOP);
2332 /* Set resume file transfer offset */
2333 infof(data, "Instructs server to resume from offset %"
2334 CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
2336 PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
2337 data->state.resume_from);
2339 state(conn, FTP_RETR_REST);
2343 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2344 state(conn, FTP_RETR);
2350 static CURLcode ftp_state_size_resp(struct connectdata *conn,
2354 CURLcode result = CURLE_OK;
2355 struct SessionHandle *data=conn->data;
2356 curl_off_t filesize;
2357 char *buf = data->state.buffer;
2359 /* get the size from the ascii string: */
2360 filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
2362 if(instate == FTP_SIZE) {
2363 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2364 if(-1 != filesize) {
2365 snprintf(buf, sizeof(data->state.buffer),
2366 "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
2367 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2372 Curl_pgrsSetDownloadSize(data, filesize);
2373 result = ftp_state_rest(conn);
2375 else if(instate == FTP_RETR_SIZE) {
2376 Curl_pgrsSetDownloadSize(data, filesize);
2377 result = ftp_state_retr(conn, filesize);
2379 else if(instate == FTP_STOR_SIZE) {
2380 data->state.resume_from = filesize;
2381 result = ftp_state_ul_setup(conn, TRUE);
2387 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
2391 CURLcode result = CURLE_OK;
2392 struct ftp_conn *ftpc = &conn->proto.ftpc;
2397 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2398 if(ftpcode == 350) {
2399 char buffer[24]= { "Accept-ranges: bytes\r\n" };
2400 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
2405 result = ftp_state_prepare_transfer(conn);
2409 if(ftpcode != 350) {
2410 failf(conn->data, "Couldn't use REST");
2411 result = CURLE_FTP_COULDNT_USE_REST;
2414 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2415 state(conn, FTP_RETR);
2423 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
2424 int ftpcode, ftpstate instate)
2426 CURLcode result = CURLE_OK;
2427 struct SessionHandle *data = conn->data;
2430 failf(data, "Failed FTP upload: %0d", ftpcode);
2431 state(conn, FTP_STOP);
2432 /* oops, we never close the sockets! */
2433 return CURLE_UPLOAD_FAILED;
2436 conn->proto.ftpc.state_saved = instate;
2438 /* PORT means we are now awaiting the server to connect to us. */
2439 if(data->set.ftp_use_port) {
2442 state(conn, FTP_STOP); /* no longer in STOR state */
2444 result = AllowServerConnect(conn, &connected);
2449 struct ftp_conn *ftpc = &conn->proto.ftpc;
2450 infof(data, "Data conn was not available immediately\n");
2451 ftpc->wait_data_conn = TRUE;
2457 return InitiateTransfer(conn);
2460 /* for LIST and RETR responses */
2461 static CURLcode ftp_state_get_resp(struct connectdata *conn,
2465 CURLcode result = CURLE_OK;
2466 struct SessionHandle *data = conn->data;
2467 struct FTP *ftp = data->req.protop;
2468 char *buf = data->state.buffer;
2470 if((ftpcode == 150) || (ftpcode == 125)) {
2474 150 Opening BINARY mode data connection for /etc/passwd (2241
2475 bytes). (ok, the file is being transferred)
2478 150 Opening ASCII mode data connection for /bin/ls
2481 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2484 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
2487 125 Data connection already open; Transfer starting. */
2489 curl_off_t size=-1; /* default unknown size */
2493 * It appears that there are FTP-servers that return size 0 for files when
2494 * SIZE is used on the file while being in BINARY mode. To work around
2495 * that (stupid) behavior, we attempt to parse the RETR response even if
2496 * the SIZE returned size zero.
2498 * Debugging help from Salvatore Sorrentino on February 26, 2003.
2501 if((instate != FTP_LIST) &&
2502 !data->set.prefer_ascii &&
2503 (ftp->downloadsize < 1)) {
2505 * It seems directory listings either don't show the size or very
2506 * often uses size 0 anyway. ASCII transfers may very well turn out
2507 * that the transferred amount of data is not the same as this line
2508 * tells, why using this number in those cases only confuses us.
2510 * Example D above makes this parsing a little tricky */
2512 bytes=strstr(buf, " bytes");
2514 long in=(long)(bytes-buf);
2515 /* this is a hint there is size information in there! ;-) */
2517 /* scan for the left parenthesis and break there */
2520 /* skip only digits */
2521 if(!ISDIGIT(*bytes)) {
2525 /* one more estep backwards */
2528 /* if we have nothing but digits: */
2530 /* get the number! */
2531 size = curlx_strtoofft(bytes, NULL, 0);
2535 else if(ftp->downloadsize > -1)
2536 size = ftp->downloadsize;
2538 if(size > data->req.maxdownload && data->req.maxdownload > 0)
2539 size = data->req.size = data->req.maxdownload;
2540 else if((instate != FTP_LIST) && (data->set.prefer_ascii))
2541 size = -1; /* kludge for servers that understate ASCII mode file size */
2543 infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
2544 data->req.maxdownload);
2546 if(instate != FTP_LIST)
2547 infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n",
2551 conn->proto.ftpc.state_saved = instate;
2552 conn->proto.ftpc.retr_size_saved = size;
2554 if(data->set.ftp_use_port) {
2557 result = AllowServerConnect(conn, &connected);
2562 struct ftp_conn *ftpc = &conn->proto.ftpc;
2563 infof(data, "Data conn was not available immediately\n");
2564 state(conn, FTP_STOP);
2565 ftpc->wait_data_conn = TRUE;
2569 return InitiateTransfer(conn);
2572 if((instate == FTP_LIST) && (ftpcode == 450)) {
2573 /* simply no matching files in the dir listing */
2574 ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
2575 state(conn, FTP_STOP); /* this phase is over */
2578 failf(data, "RETR response: %03d", ftpcode);
2579 return instate == FTP_RETR && ftpcode == 550?
2580 CURLE_REMOTE_FILE_NOT_FOUND:
2581 CURLE_FTP_COULDNT_RETR_FILE;
2588 /* after USER, PASS and ACCT */
2589 static CURLcode ftp_state_loggedin(struct connectdata *conn)
2591 CURLcode result = CURLE_OK;
2593 if(conn->ssl[FIRSTSOCKET].use) {
2594 /* PBSZ = PROTECTION BUFFER SIZE.
2596 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2598 Specifically, the PROT command MUST be preceded by a PBSZ
2599 command and a PBSZ command MUST be preceded by a successful
2600 security data exchange (the TLS negotiation in this case)
2602 ... (and on page 8):
2604 Thus the PBSZ command must still be issued, but must have a
2605 parameter of '0' to indicate that no buffering is taking place
2606 and the data connection should not be encapsulated.
2608 PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
2609 state(conn, FTP_PBSZ);
2612 result = ftp_state_pwd(conn);
2617 /* for USER and PASS responses */
2618 static CURLcode ftp_state_user_resp(struct connectdata *conn,
2622 CURLcode result = CURLE_OK;
2623 struct SessionHandle *data = conn->data;
2624 struct FTP *ftp = data->req.protop;
2625 struct ftp_conn *ftpc = &conn->proto.ftpc;
2626 (void)instate; /* no use for this yet */
2628 /* some need password anyway, and others just return 2xx ignored */
2629 if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2630 /* 331 Password required for ...
2631 (the server requires to send the user's password too) */
2632 PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
2633 state(conn, FTP_PASS);
2635 else if(ftpcode/100 == 2) {
2636 /* 230 User ... logged in.
2637 (the user logged in with or without password) */
2638 result = ftp_state_loggedin(conn);
2640 else if(ftpcode == 332) {
2641 if(data->set.str[STRING_FTP_ACCOUNT]) {
2642 PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
2643 state(conn, FTP_ACCT);
2646 failf(data, "ACCT requested but none available");
2647 result = CURLE_LOGIN_DENIED;
2651 /* All other response codes, like:
2653 530 User ... access denied
2654 (the server denies to log the specified user) */
2656 if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2657 !conn->data->state.ftp_trying_alternative) {
2658 /* Ok, USER failed. Let's try the supplied command. */
2659 PPSENDF(&conn->proto.ftpc.pp, "%s",
2660 conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2661 conn->data->state.ftp_trying_alternative = TRUE;
2662 state(conn, FTP_USER);
2666 failf(data, "Access denied: %03d", ftpcode);
2667 result = CURLE_LOGIN_DENIED;
2673 /* for ACCT response */
2674 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
2677 CURLcode result = CURLE_OK;
2678 struct SessionHandle *data = conn->data;
2679 if(ftpcode != 230) {
2680 failf(data, "ACCT rejected by server: %03d", ftpcode);
2681 result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2684 result = ftp_state_loggedin(conn);
2690 static CURLcode ftp_statemach_act(struct connectdata *conn)
2693 curl_socket_t sock = conn->sock[FIRSTSOCKET];
2694 struct SessionHandle *data=conn->data;
2696 struct ftp_conn *ftpc = &conn->proto.ftpc;
2697 struct pingpong *pp = &ftpc->pp;
2698 static const char ftpauth[][4] = { "SSL", "TLS" };
2702 return Curl_pp_flushsend(pp);
2704 result = ftp_readresp(sock, pp, &ftpcode, &nread);
2709 /* we have now received a full FTP server response */
2710 switch(ftpc->state) {
2713 /* 230 User logged in - already! */
2714 return ftp_state_user_resp(conn, ftpcode, ftpc->state);
2715 else if(ftpcode != 220) {
2716 failf(data, "Got a %03d ftp-server response when 220 was expected",
2718 return CURLE_FTP_WEIRD_SERVER_REPLY;
2721 /* We have received a 220 response fine, now we proceed. */
2724 /* If not anonymous login, try a secure login. Note that this
2725 procedure is still BLOCKING. */
2727 Curl_sec_request_prot(conn, "private");
2728 /* We set private first as default, in case the line below fails to
2729 set a valid level */
2730 Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2732 if(Curl_sec_login(conn))
2733 infof(data, "Logging in with password in cleartext!\n");
2735 infof(data, "Authentication successful\n");
2739 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
2740 /* We don't have a SSL/TLS connection yet, but FTPS is
2741 requested. Try a FTPS connection now */
2744 switch(data->set.ftpsslauth) {
2745 case CURLFTPAUTH_DEFAULT:
2746 case CURLFTPAUTH_SSL:
2747 ftpc->count2 = 1; /* add one to get next */
2750 case CURLFTPAUTH_TLS:
2751 ftpc->count2 = -1; /* subtract one to get next */
2755 failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2756 (int)data->set.ftpsslauth);
2757 return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
2759 PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2760 state(conn, FTP_AUTH);
2763 result = ftp_state_user(conn);
2771 /* we have gotten the response to a previous AUTH command */
2773 /* RFC2228 (page 5) says:
2775 * If the server is willing to accept the named security mechanism,
2776 * and does not require any security data, it must respond with
2777 * reply code 234/334.
2780 if((ftpcode == 234) || (ftpcode == 334)) {
2781 /* Curl_ssl_connect is BLOCKING */
2782 result = Curl_ssl_connect(conn, FIRSTSOCKET);
2784 conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
2785 result = ftp_state_user(conn);
2788 else if(ftpc->count3 < 1) {
2790 ftpc->count1 += ftpc->count2; /* get next attempt */
2791 result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2792 /* remain in this same state */
2795 if(data->set.use_ssl > CURLUSESSL_TRY)
2796 /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2797 result = CURLE_USE_SSL_FAILED;
2799 /* ignore the failure and continue */
2800 result = ftp_state_user(conn);
2809 result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
2813 result = ftp_state_acct_resp(conn, ftpcode);
2817 PPSENDF(&ftpc->pp, "PROT %c",
2818 data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2819 state(conn, FTP_PROT);
2824 if(ftpcode/100 == 2)
2825 /* We have enabled SSL for the data connection! */
2826 conn->ssl[SECONDARYSOCKET].use =
2827 (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
2828 /* FTP servers typically responds with 500 if they decide to reject
2830 else if(data->set.use_ssl > CURLUSESSL_CONTROL)
2831 /* we failed and bails out */
2832 return CURLE_USE_SSL_FAILED;
2834 if(data->set.ftp_ccc) {
2835 /* CCC - Clear Command Channel
2837 PPSENDF(&ftpc->pp, "%s", "CCC");
2838 state(conn, FTP_CCC);
2841 result = ftp_state_pwd(conn);
2849 /* First shut down the SSL layer (note: this call will block) */
2850 result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
2853 failf(conn->data, "Failed to clear the command channel (CCC)");
2858 /* Then continue as normal */
2859 result = ftp_state_pwd(conn);
2865 if(ftpcode == 257) {
2866 char *ptr=&data->state.buffer[4]; /* start on the first letter */
2870 dir = malloc(nread + 1);
2872 return CURLE_OUT_OF_MEMORY;
2874 /* Reply format is like
2875 257<space>[rubbish]"<directory-name>"<space><commentary> and the
2878 The directory name can contain any character; embedded
2879 double-quotes should be escaped by double-quotes (the
2880 "quote-doubling" convention).
2883 /* scan for the first double-quote for non-standard responses */
2884 while(ptr < &data->state.buffer[sizeof(data->state.buffer)]
2885 && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
2889 /* it started good */
2891 for(store = dir; *ptr;) {
2893 if('\"' == ptr[1]) {
2894 /* "quote-doubling" */
2900 *store = '\0'; /* zero terminate */
2901 break; /* get out of this loop */
2910 /* If the path name does not look like an absolute path (i.e.: it
2911 does not start with a '/'), we probably need some server-dependent
2912 adjustments. For example, this is the case when connecting to
2913 an OS400 FTP server: this server supports two name syntaxes,
2914 the default one being incompatible with standard pathes. In
2915 addition, this server switches automatically to the regular path
2916 syntax when one is encountered in a command: this results in
2917 having an entrypath in the wrong syntax when later used in CWD.
2918 The method used here is to check the server OS: we do it only
2919 if the path name looks strange to minimize overhead on other
2922 if(!ftpc->server_os && dir[0] != '/') {
2924 result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
2929 Curl_safefree(ftpc->entrypath);
2930 ftpc->entrypath = dir; /* remember this */
2931 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2932 /* also save it where getinfo can access it: */
2933 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2934 state(conn, FTP_SYST);
2938 Curl_safefree(ftpc->entrypath);
2939 ftpc->entrypath = dir; /* remember this */
2940 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2941 /* also save it where getinfo can access it: */
2942 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2945 /* couldn't get the path */
2947 infof(data, "Failed to figure out path\n");
2950 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2951 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2955 if(ftpcode == 215) {
2956 char *ptr=&data->state.buffer[4]; /* start on the first letter */
2960 os = malloc(nread + 1);
2962 return CURLE_OUT_OF_MEMORY;
2964 /* Reply format is like
2965 215<space><OS-name><space><commentary>
2969 for(store = os; *ptr && *ptr != ' ';)
2971 *store = '\0'; /* zero terminate */
2973 /* Check for special servers here. */
2975 if(strequal(os, "OS/400")) {
2976 /* Force OS400 name format 1. */
2977 result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
2982 /* remember target server OS */
2983 Curl_safefree(ftpc->server_os);
2984 ftpc->server_os = os;
2985 state(conn, FTP_NAMEFMT);
2989 /* Nothing special for the target server. */
2990 /* remember target server OS */
2991 Curl_safefree(ftpc->server_os);
2992 ftpc->server_os = os;
2996 /* Cannot identify server OS. Continue anyway and cross fingers. */
2999 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
3000 DEBUGF(infof(data, "protocol connect phase DONE\n"));
3004 if(ftpcode == 250) {
3005 /* Name format change successful: reload initial path. */
3006 ftp_state_pwd(conn);
3010 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
3011 DEBUGF(infof(data, "protocol connect phase DONE\n"));
3016 case FTP_RETR_PREQUOTE:
3017 case FTP_STOR_PREQUOTE:
3018 if((ftpcode >= 400) && !ftpc->count2) {
3019 /* failure response code, and not allowed to fail */
3020 failf(conn->data, "QUOT command failed with %03d", ftpcode);
3021 return CURLE_QUOTE_ERROR;
3023 result = ftp_state_quote(conn, FALSE, ftpc->state);
3030 if(ftpcode/100 != 2) {
3031 /* failure to CWD there */
3032 if(conn->data->set.ftp_create_missing_dirs &&
3033 ftpc->count1 && !ftpc->count2) {
3035 ftpc->count2++; /* counter to prevent CWD-MKD loops */
3036 PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
3037 state(conn, FTP_MKD);
3040 /* return failure */
3041 failf(data, "Server denied you to change to the given directory");
3042 ftpc->cwdfail = TRUE; /* don't remember this path as we failed
3044 return CURLE_REMOTE_ACCESS_DENIED;
3050 if(++ftpc->count1 <= ftpc->dirdepth) {
3052 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3055 result = ftp_state_mdtm(conn);
3063 if((ftpcode/100 != 2) && !ftpc->count3--) {
3064 /* failure to MKD the dir */
3065 failf(data, "Failed to MKD dir: %03d", ftpcode);
3066 return CURLE_REMOTE_ACCESS_DENIED;
3068 state(conn, FTP_CWD);
3070 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3074 result = ftp_state_mdtm_resp(conn, ftpcode);
3081 result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
3087 result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
3092 result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
3096 if(ftpcode != 200) {
3097 /* there only is this one standard OK return code. */
3098 failf(data, "PRET command not accepted: %03d", ftpcode);
3099 return CURLE_FTP_PRET_FAILED;
3101 result = ftp_state_use_pasv(conn);
3105 result = ftp_state_pasv_resp(conn, ftpcode);
3109 result = ftp_state_port_resp(conn, ftpcode);
3114 result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
3118 result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
3122 /* fallthrough, just stop! */
3124 /* internal error */
3125 state(conn, FTP_STOP);
3134 /* called repeatedly until done from multi.c */
3135 static CURLcode ftp_multi_statemach(struct connectdata *conn,
3138 struct ftp_conn *ftpc = &conn->proto.ftpc;
3139 CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
3141 /* Check for the state outside of the Curl_socket_ready() return code checks
3142 since at times we are in fact already in this state when this function
3144 *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
3149 static CURLcode ftp_block_statemach(struct connectdata *conn)
3151 struct ftp_conn *ftpc = &conn->proto.ftpc;
3152 struct pingpong *pp = &ftpc->pp;
3153 CURLcode result = CURLE_OK;
3155 while(ftpc->state != FTP_STOP) {
3156 result = Curl_pp_statemach(pp, TRUE);
3165 * ftp_connect() should do everything that is to be considered a part of
3166 * the connection phase.
3168 * The variable 'done' points to will be TRUE if the protocol-layer connect
3169 * phase is done when this function returns, or FALSE if not.
3172 static CURLcode ftp_connect(struct connectdata *conn,
3173 bool *done) /* see description above */
3176 struct ftp_conn *ftpc = &conn->proto.ftpc;
3177 struct pingpong *pp = &ftpc->pp;
3179 *done = FALSE; /* default to not done yet */
3181 /* We always support persistent connections on ftp */
3182 connkeep(conn, "FTP default");
3184 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
3185 pp->statemach_act = ftp_statemach_act;
3186 pp->endofresp = ftp_endofresp;
3189 if(conn->handler->flags & PROTOPT_SSL) {
3191 result = Curl_ssl_connect(conn, FIRSTSOCKET);
3196 Curl_pp_init(pp); /* init the generic pingpong data */
3198 /* When we connect, we start in the state where we await the 220
3200 state(conn, FTP_WAIT220);
3202 result = ftp_multi_statemach(conn, done);
3207 /***********************************************************************
3211 * The DONE function. This does what needs to be done after a single DO has
3214 * Input argument is already checked for validity.
3216 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
3219 struct SessionHandle *data = conn->data;
3220 struct FTP *ftp = data->req.protop;
3221 struct ftp_conn *ftpc = &conn->proto.ftpc;
3222 struct pingpong *pp = &ftpc->pp;
3225 CURLcode result = CURLE_OK;
3226 bool was_ctl_valid = ftpc->ctl_valid;
3228 const char *path_to_use = data->state.path;
3231 /* When the easy handle is removed from the multi while libcurl is still
3232 * trying to resolve the host name, it seems that the ftp struct is not
3233 * yet initialized, but the removal action calls Curl_done() which calls
3234 * this function. So we simply return success if no ftp pointer is set.
3239 case CURLE_BAD_DOWNLOAD_RESUME:
3240 case CURLE_FTP_WEIRD_PASV_REPLY:
3241 case CURLE_FTP_PORT_FAILED:
3242 case CURLE_FTP_ACCEPT_FAILED:
3243 case CURLE_FTP_ACCEPT_TIMEOUT:
3244 case CURLE_FTP_COULDNT_SET_TYPE:
3245 case CURLE_FTP_COULDNT_RETR_FILE:
3246 case CURLE_PARTIAL_FILE:
3247 case CURLE_UPLOAD_FAILED:
3248 case CURLE_REMOTE_ACCESS_DENIED:
3249 case CURLE_FILESIZE_EXCEEDED:
3250 case CURLE_REMOTE_FILE_NOT_FOUND:
3251 case CURLE_WRITE_ERROR:
3252 /* the connection stays alive fine even though this happened */
3254 case CURLE_OK: /* doesn't affect the control connection's status */
3256 ftpc->ctl_valid = was_ctl_valid;
3259 /* until we cope better with prematurely ended requests, let them
3260 * fallback as if in complete failure */
3261 default: /* by default, an error means the control connection is
3262 wedged and should not be used anymore */
3263 ftpc->ctl_valid = FALSE;
3264 ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3265 current path, as this connection is going */
3266 connclose(conn, "FTP ended with bad error code");
3267 result = status; /* use the already set error code */
3271 /* now store a copy of the directory we are in */
3273 free(ftpc->prevpath);
3275 if(data->set.wildcardmatch) {
3276 if(data->set.chunk_end && ftpc->file) {
3277 data->set.chunk_end(data->wildcard.customptr);
3279 ftpc->known_filesize = -1;
3282 /* get the "raw" path */
3283 path = curl_easy_unescape(data, path_to_use, 0, NULL);
3285 /* out of memory, but we can limp along anyway (and should try to
3286 * since we may already be in the out of memory cleanup path) */
3288 result = CURLE_OUT_OF_MEMORY;
3289 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3290 connclose(conn, "FTP: out of memory!"); /* mark for connection closure */
3291 ftpc->prevpath = NULL; /* no path remembering */
3294 size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
3295 size_t dlen = strlen(path)-flen;
3296 if(!ftpc->cwdfail) {
3297 if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
3298 ftpc->prevpath = path;
3300 /* if 'path' is not the whole string */
3301 ftpc->prevpath[dlen]=0; /* terminate */
3304 /* we never changed dir */
3305 ftpc->prevpath=strdup("");
3309 infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
3312 ftpc->prevpath = NULL; /* no path */
3316 /* free the dir tree and file parts */
3319 /* shut down the socket to inform the server we're done */
3322 shutdown(conn->sock[SECONDARYSOCKET],2); /* SD_BOTH */
3325 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3326 if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
3327 /* partial download completed */
3328 result = Curl_pp_sendf(pp, "%s", "ABOR");
3330 failf(data, "Failure sending ABOR command: %s",
3331 curl_easy_strerror(result));
3332 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3333 connclose(conn, "ABOR command failed"); /* connection closure */
3337 if(conn->ssl[SECONDARYSOCKET].use) {
3338 /* The secondary socket is using SSL so we must close down that part
3339 first before we close the socket for real */
3340 Curl_ssl_close(conn, SECONDARYSOCKET);
3342 /* Note that we keep "use" set to TRUE since that (next) connection is
3343 still requested to use SSL */
3345 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
3346 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
3347 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
3348 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
3352 if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
3353 pp->pending_resp && !premature) {
3355 * Let's see what the server says about the transfer we just performed,
3356 * but lower the timeout as sometimes this connection has died while the
3357 * data has been transferred. This happens when doing through NATs etc that
3358 * abandon old silent connections.
3360 long old_time = pp->response_time;
3362 pp->response_time = 60*1000; /* give it only a minute for now */
3363 pp->response = Curl_tvnow(); /* timeout relative now */
3365 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3367 pp->response_time = old_time; /* set this back to previous value */
3369 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3370 failf(data, "control connection looks dead");
3371 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3372 connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
3378 if(ftpc->dont_check && data->req.maxdownload > 0) {
3379 /* we have just sent ABOR and there is no reliable way to check if it was
3380 * successful or not; we have to close the connection now */
3381 infof(data, "partial download completed, closing connection\n");
3382 connclose(conn, "Partial download with no ability to check");
3386 if(!ftpc->dont_check) {
3387 /* 226 Transfer complete, 250 Requested file action okay, completed. */
3388 if((ftpcode != 226) && (ftpcode != 250)) {
3389 failf(data, "server did not report OK, got %d", ftpcode);
3390 result = CURLE_PARTIAL_FILE;
3395 if(result || premature)
3396 /* the response code from the transfer showed an error already so no
3397 use checking further */
3399 else if(data->set.upload) {
3400 if((-1 != data->state.infilesize) &&
3401 (data->state.infilesize != *ftp->bytecountp) &&
3403 (ftp->transfer == FTPTRANSFER_BODY)) {
3404 failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
3405 " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
3406 *ftp->bytecountp, data->state.infilesize);
3407 result = CURLE_PARTIAL_FILE;
3411 if((-1 != data->req.size) &&
3412 (data->req.size != *ftp->bytecountp) &&
3413 #ifdef CURL_DO_LINEEND_CONV
3414 /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3415 * we'll check to see if the discrepancy can be explained by the number
3416 * of CRLFs we've changed to LFs.
3418 ((data->req.size + data->state.crlf_conversions) !=
3419 *ftp->bytecountp) &&
3420 #endif /* CURL_DO_LINEEND_CONV */
3421 (data->req.maxdownload != *ftp->bytecountp)) {
3422 failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
3423 " bytes", *ftp->bytecountp);
3424 result = CURLE_PARTIAL_FILE;
3426 else if(!ftpc->dont_check &&
3427 !*ftp->bytecountp &&
3428 (data->req.size>0)) {
3429 failf(data, "No data was received!");
3430 result = CURLE_FTP_COULDNT_RETR_FILE;
3434 /* clear these for next connection */
3435 ftp->transfer = FTPTRANSFER_BODY;
3436 ftpc->dont_check = FALSE;
3438 /* Send any post-transfer QUOTE strings? */
3439 if(!status && !result && !premature && data->set.postquote)
3440 result = ftp_sendquote(conn, data->set.postquote);
3445 /***********************************************************************
3449 * Where a 'quote' means a list of custom commands to send to the server.
3450 * The quote list is passed as an argument.
3456 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
3458 struct curl_slist *item;
3462 struct ftp_conn *ftpc = &conn->proto.ftpc;
3463 struct pingpong *pp = &ftpc->pp;
3468 char *cmd = item->data;
3469 bool acceptfail = FALSE;
3471 /* if a command starts with an asterisk, which a legal FTP command never
3472 can, the command will be allowed to fail without it causing any
3473 aborts or cancels etc. It will cause libcurl to act as if the command
3474 is successful, whatever the server reponds. */
3481 PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
3483 pp->response = Curl_tvnow(); /* timeout relative now */
3485 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3489 if(!acceptfail && (ftpcode >= 400)) {
3490 failf(conn->data, "QUOT string not accepted: %s", cmd);
3491 return CURLE_QUOTE_ERROR;
3501 /***********************************************************************
3505 * Returns TRUE if we in the current situation should send TYPE
3507 static int ftp_need_type(struct connectdata *conn,
3510 return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3513 /***********************************************************************
3517 * Set TYPE. We only deal with ASCII or BINARY so this function
3519 * If the transfer type is not sent, simulate on OK response in newstate
3521 static CURLcode ftp_nb_type(struct connectdata *conn,
3522 bool ascii, ftpstate newstate)
3524 struct ftp_conn *ftpc = &conn->proto.ftpc;
3526 char want = (char)(ascii?'A':'I');
3528 if(ftpc->transfertype == want) {
3529 state(conn, newstate);
3530 return ftp_state_type_resp(conn, 200, newstate);
3533 PPSENDF(&ftpc->pp, "TYPE %c", want);
3534 state(conn, newstate);
3536 /* keep track of our current transfer type */
3537 ftpc->transfertype = want;
3541 /***************************************************************************
3543 * ftp_pasv_verbose()
3545 * This function only outputs some informationals about this second connection
3546 * when we've issued a PASV command before and thus we have connected to a
3547 * possibly new IP address.
3550 #ifndef CURL_DISABLE_VERBOSE_STRINGS
3552 ftp_pasv_verbose(struct connectdata *conn,
3554 char *newhost, /* ascii version */
3558 Curl_printable_address(ai, buf, sizeof(buf));
3559 infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3564 Check if this is a range download, and if so, set the internal variables
3568 static CURLcode ftp_range(struct connectdata *conn)
3570 curl_off_t from, to;
3573 struct SessionHandle *data = conn->data;
3574 struct ftp_conn *ftpc = &conn->proto.ftpc;
3576 if(data->state.use_range && data->state.range) {
3577 from=curlx_strtoofft(data->state.range, &ptr, 0);
3578 while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
3580 to=curlx_strtoofft(ptr, &ptr2, 0);
3582 /* we didn't get any digit */
3585 if((-1 == to) && (from>=0)) {
3587 data->state.resume_from = from;
3588 DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T
3589 " to end of file\n", from));
3593 data->req.maxdownload = -from;
3594 data->state.resume_from = from;
3595 DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T
3596 " bytes\n", -from));
3600 data->req.maxdownload = (to-from)+1; /* include last byte */
3601 data->state.resume_from = from;
3602 DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T
3603 " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
3604 from, data->req.maxdownload));
3606 DEBUGF(infof(conn->data, "range-download from %" CURL_FORMAT_CURL_OFF_T
3607 " to %" CURL_FORMAT_CURL_OFF_T ", totally %"
3608 CURL_FORMAT_CURL_OFF_T " bytes\n",
3609 from, to, data->req.maxdownload));
3610 ftpc->dont_check = TRUE; /* dont check for successful transfer */
3613 data->req.maxdownload = -1;
3621 * This function shall be called when the second FTP (data) connection is
3624 * 'complete' can return 0 for incomplete, 1 for done and -1 for go back
3625 * (which basically is only for when PASV is being sent to retry a failed
3629 static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
3631 struct SessionHandle *data=conn->data;
3632 struct ftp_conn *ftpc = &conn->proto.ftpc;
3633 CURLcode result = CURLE_OK;
3634 bool connected = FALSE;
3635 bool complete = FALSE;
3637 /* the ftp struct is inited in ftp_connect() */
3638 struct FTP *ftp = data->req.protop;
3640 /* if the second connection isn't done yet, wait for it */
3641 if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
3642 if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
3643 /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
3644 aren't used so we blank their arguments. TODO: make this nicer */
3645 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
3650 result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
3652 /* Ready to do more? */
3654 DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
3655 if(conn->bits.proxy) {
3656 infof(data, "Connection to proxy confirmed\n");
3657 result = proxy_magic(conn, ftpc->newhost, ftpc->newport, &connected);
3661 if(result && (ftpc->count1 == 0)) {
3662 *completep = -1; /* go back to DOING please */
3663 /* this is a EPSV connect failing, try PASV instead */
3664 return ftp_epsv_disable(conn);
3671 /* already in a state so skip the intial commands.
3672 They are only done to kickstart the do_more state */
3673 result = ftp_multi_statemach(conn, &complete);
3675 *completep = (int)complete;
3677 /* if we got an error or if we don't wait for a data connection return
3679 if(result || (ftpc->wait_data_conn != TRUE))
3682 if(ftpc->wait_data_conn)
3683 /* if we reach the end of the FTP state machine here, *complete will be
3684 TRUE but so is ftpc->wait_data_conn, which says we need to wait for
3685 the data connection and therefore we're not actually complete */
3689 if(ftp->transfer <= FTPTRANSFER_INFO) {
3690 /* a transfer is about to take place, or if not a file name was given
3691 so we'll do a SIZE on it later and then we need the right TYPE first */
3693 if(ftpc->wait_data_conn == TRUE) {
3696 result = ReceivedServerConnect(conn, &serv_conned);
3698 return result; /* Failed to accept data connection */
3701 /* It looks data connection is established */
3702 result = AcceptServerConnect(conn);
3703 ftpc->wait_data_conn = FALSE;
3705 result = InitiateTransfer(conn);
3710 *completep = 1; /* this state is now complete when the server has
3711 connected back to us */
3714 else if(data->set.upload) {
3715 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
3719 result = ftp_multi_statemach(conn, &complete);
3720 *completep = (int)complete;
3724 ftp->downloadsize = -1; /* unknown as of yet */
3726 result = ftp_range(conn);
3729 else if(data->set.ftp_list_only || !ftpc->file) {
3730 /* The specified path ends with a slash, and therefore we think this
3731 is a directory that is requested, use LIST. But before that we
3732 need to set ASCII transfer mode. */
3734 /* But only if a body transfer was requested. */
3735 if(ftp->transfer == FTPTRANSFER_BODY) {
3736 result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
3740 /* otherwise just fall through */
3743 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
3748 result = ftp_multi_statemach(conn, &complete);
3749 *completep = (int)complete;
3754 if(!result && (ftp->transfer != FTPTRANSFER_BODY))
3755 /* no data to transfer. FIX: it feels like a kludge to have this here
3757 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3759 if(!ftpc->wait_data_conn) {
3760 /* no waiting for the data connection so this is now complete */
3762 DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
3770 /***********************************************************************
3774 * This is the actual DO function for FTP. Get a file/directory according to
3775 * the options previously setup.
3779 CURLcode ftp_perform(struct connectdata *conn,
3780 bool *connected, /* connect status after PASV / PORT */
3783 /* this is FTP and no proxy */
3784 CURLcode result=CURLE_OK;
3786 DEBUGF(infof(conn->data, "DO phase starts\n"));
3788 if(conn->data->set.opt_no_body) {
3789 /* requested no body means no transfer... */
3790 struct FTP *ftp = conn->data->req.protop;
3791 ftp->transfer = FTPTRANSFER_INFO;
3794 *dophase_done = FALSE; /* not done yet */
3796 /* start the first command in the DO phase */
3797 result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
3801 /* run the state-machine */
3802 result = ftp_multi_statemach(conn, dophase_done);
3804 *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
3806 infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected);
3809 DEBUGF(infof(conn->data, "DO phase is complete1\n"));
3814 static void wc_data_dtor(void *ptr)
3816 struct ftp_wc_tmpdata *tmp = ptr;
3818 Curl_ftp_parselist_data_free(&tmp->parser);
3822 static CURLcode init_wc_data(struct connectdata *conn)
3825 char *path = conn->data->state.path;
3826 struct WildcardData *wildcard = &(conn->data->wildcard);
3827 CURLcode result = CURLE_OK;
3828 struct ftp_wc_tmpdata *ftp_tmp;
3830 last_slash = strrchr(conn->data->state.path, '/');
3833 if(last_slash[0] == '\0') {
3834 wildcard->state = CURLWC_CLEAN;
3835 result = ftp_parse_url_path(conn);
3839 wildcard->pattern = strdup(last_slash);
3840 if(!wildcard->pattern)
3841 return CURLE_OUT_OF_MEMORY;
3842 last_slash[0] = '\0'; /* cut file from path */
3845 else { /* there is only 'wildcard pattern' or nothing */
3847 wildcard->pattern = strdup(path);
3848 if(!wildcard->pattern)
3849 return CURLE_OUT_OF_MEMORY;
3852 else { /* only list */
3853 wildcard->state = CURLWC_CLEAN;
3854 result = ftp_parse_url_path(conn);
3859 /* program continues only if URL is not ending with slash, allocate needed
3860 resources for wildcard transfer */
3862 /* allocate ftp protocol specific temporary wildcard data */
3863 ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata));
3865 Curl_safefree(wildcard->pattern);
3866 return CURLE_OUT_OF_MEMORY;
3869 /* INITIALIZE parselist structure */
3870 ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
3871 if(!ftp_tmp->parser) {
3872 Curl_safefree(wildcard->pattern);
3873 Curl_safefree(ftp_tmp);
3874 return CURLE_OUT_OF_MEMORY;
3877 wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
3878 wildcard->tmp_dtor = wc_data_dtor;
3880 /* wildcard does not support NOCWD option (assert it?) */
3881 if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
3882 conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
3884 /* try to parse ftp url */
3885 result = ftp_parse_url_path(conn);
3887 Curl_safefree(wildcard->pattern);
3888 wildcard->tmp_dtor(wildcard->tmp);
3889 wildcard->tmp_dtor = ZERO_NULL;
3890 wildcard->tmp = NULL;
3894 wildcard->path = strdup(conn->data->state.path);
3895 if(!wildcard->path) {
3896 Curl_safefree(wildcard->pattern);
3897 wildcard->tmp_dtor(wildcard->tmp);
3898 wildcard->tmp_dtor = ZERO_NULL;
3899 wildcard->tmp = NULL;
3900 return CURLE_OUT_OF_MEMORY;
3903 /* backup old write_function */
3904 ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
3905 /* parsing write function */
3906 conn->data->set.fwrite_func = Curl_ftp_parselist;
3907 /* backup old file descriptor */
3908 ftp_tmp->backup.file_descriptor = conn->data->set.out;
3909 /* let the writefunc callback know what curl pointer is working with */
3910 conn->data->set.out = conn;
3912 infof(conn->data, "Wildcard - Parsing started\n");
3916 /* This is called recursively */
3917 static CURLcode wc_statemach(struct connectdata *conn)
3919 struct WildcardData * const wildcard = &(conn->data->wildcard);
3920 CURLcode result = CURLE_OK;
3922 switch (wildcard->state) {
3924 result = init_wc_data(conn);
3925 if(wildcard->state == CURLWC_CLEAN)
3929 wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
3932 case CURLWC_MATCHING: {
3933 /* In this state is LIST response successfully parsed, so lets restore
3934 previous WRITEFUNCTION callback and WRITEDATA pointer */
3935 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3936 conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
3937 conn->data->set.out = ftp_tmp->backup.file_descriptor;
3938 ftp_tmp->backup.write_function = ZERO_NULL;
3939 ftp_tmp->backup.file_descriptor = NULL;
3940 wildcard->state = CURLWC_DOWNLOADING;
3942 if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
3943 /* error found in LIST parsing */
3944 wildcard->state = CURLWC_CLEAN;
3945 return wc_statemach(conn);
3947 else if(wildcard->filelist->size == 0) {
3948 /* no corresponding file */
3949 wildcard->state = CURLWC_CLEAN;
3950 return CURLE_REMOTE_FILE_NOT_FOUND;
3952 return wc_statemach(conn);
3955 case CURLWC_DOWNLOADING: {
3956 /* filelist has at least one file, lets get first one */
3957 struct ftp_conn *ftpc = &conn->proto.ftpc;
3958 struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
3960 char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
3962 return CURLE_OUT_OF_MEMORY;
3964 /* switch default "state.pathbuffer" and tmp_path, good to see
3965 ftp_parse_url_path function to understand this trick */
3966 Curl_safefree(conn->data->state.pathbuffer);
3967 conn->data->state.pathbuffer = tmp_path;
3968 conn->data->state.path = tmp_path;
3970 infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
3971 if(conn->data->set.chunk_bgn) {
3972 long userresponse = conn->data->set.chunk_bgn(
3973 finfo, wildcard->customptr, (int)wildcard->filelist->size);
3974 switch(userresponse) {
3975 case CURL_CHUNK_BGN_FUNC_SKIP:
3976 infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
3978 wildcard->state = CURLWC_SKIP;
3979 return wc_statemach(conn);
3980 case CURL_CHUNK_BGN_FUNC_FAIL:
3981 return CURLE_CHUNK_FAILED;
3985 if(finfo->filetype != CURLFILETYPE_FILE) {
3986 wildcard->state = CURLWC_SKIP;
3987 return wc_statemach(conn);
3990 if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
3991 ftpc->known_filesize = finfo->size;
3993 result = ftp_parse_url_path(conn);
3997 /* we don't need the Curl_fileinfo of first file anymore */
3998 Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
4000 if(wildcard->filelist->size == 0) { /* remains only one file to down. */
4001 wildcard->state = CURLWC_CLEAN;
4002 /* after that will be ftp_do called once again and no transfer
4003 will be done because of CURLWC_CLEAN state */
4009 if(conn->data->set.chunk_end)
4010 conn->data->set.chunk_end(conn->data->wildcard.customptr);
4011 Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
4012 wildcard->state = (wildcard->filelist->size == 0) ?
4013 CURLWC_CLEAN : CURLWC_DOWNLOADING;
4014 return wc_statemach(conn);
4017 case CURLWC_CLEAN: {
4018 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
4021 result = Curl_ftp_parselist_geterror(ftp_tmp->parser);
4023 wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
4034 /***********************************************************************
4038 * This function is registered as 'curl_do' function. It decodes the path
4039 * parts etc as a wrapper to the actual DO function (ftp_perform).
4041 * The input argument is already checked for validity.
4043 static CURLcode ftp_do(struct connectdata *conn, bool *done)
4045 CURLcode result = CURLE_OK;
4046 struct ftp_conn *ftpc = &conn->proto.ftpc;
4048 *done = FALSE; /* default to false */
4049 ftpc->wait_data_conn = FALSE; /* default to no such wait */
4051 if(conn->data->set.wildcardmatch) {
4052 result = wc_statemach(conn);
4053 if(conn->data->wildcard.state == CURLWC_SKIP ||
4054 conn->data->wildcard.state == CURLWC_DONE) {
4055 /* do not call ftp_regular_transfer */
4058 if(result) /* error, loop or skipping the file */
4061 else { /* no wildcard FSM needed */
4062 result = ftp_parse_url_path(conn);
4067 result = ftp_regular_transfer(conn, done);
4073 CURLcode Curl_ftpsendf(struct connectdata *conn,
4074 const char *fmt, ...)
4076 ssize_t bytes_written;
4077 #define SBUF_SIZE 1024
4081 CURLcode result = CURLE_OK;
4083 enum protection_level data_sec = conn->data_prot;
4088 write_len = vsnprintf(s, SBUF_SIZE-3, fmt, ap);
4091 strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
4096 result = Curl_convert_to_network(conn->data, s, write_len);
4097 /* Curl_convert_to_network calls failf if unsuccessful */
4103 conn->data_prot = PROT_CMD;
4105 result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
4108 DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
4109 conn->data_prot = data_sec;
4115 if(conn->data->set.verbose)
4116 Curl_debug(conn->data, CURLINFO_HEADER_OUT,
4117 sptr, (size_t)bytes_written, conn);
4119 if(bytes_written != (ssize_t)write_len) {
4120 write_len -= bytes_written;
4121 sptr += bytes_written;
4130 /***********************************************************************
4134 * This should be called before calling sclose() on an ftp control connection
4135 * (not data connections). We should then wait for the response from the
4136 * server before returning. The calling code should then try to close the
4140 static CURLcode ftp_quit(struct connectdata *conn)
4142 CURLcode result = CURLE_OK;
4144 if(conn->proto.ftpc.ctl_valid) {
4145 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT");
4147 failf(conn->data, "Failure sending QUIT command: %s",
4148 curl_easy_strerror(result));
4149 conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
4150 connclose(conn, "QUIT command failed"); /* mark for connection closure */
4151 state(conn, FTP_STOP);
4155 state(conn, FTP_QUIT);
4157 result = ftp_block_statemach(conn);
4163 /***********************************************************************
4167 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
4168 * resources. BLOCKING.
4170 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
4172 struct ftp_conn *ftpc= &conn->proto.ftpc;
4173 struct pingpong *pp = &ftpc->pp;
4175 /* We cannot send quit unconditionally. If this connection is stale or
4176 bad in any way, sending quit and waiting around here will make the
4177 disconnect wait in vain and cause more problems than we need to.
4179 ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
4180 will try to send the QUIT command, otherwise it will just return.
4183 ftpc->ctl_valid = FALSE;
4185 /* The FTP session may or may not have been allocated/setup at this point! */
4186 (void)ftp_quit(conn); /* ignore errors on the QUIT */
4188 if(ftpc->entrypath) {
4189 struct SessionHandle *data = conn->data;
4190 if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
4191 data->state.most_recent_ftp_entrypath = NULL;
4193 free(ftpc->entrypath);
4194 ftpc->entrypath = NULL;
4198 if(ftpc->prevpath) {
4199 free(ftpc->prevpath);
4200 ftpc->prevpath = NULL;
4202 if(ftpc->server_os) {
4203 free(ftpc->server_os);
4204 ftpc->server_os = NULL;
4207 Curl_pp_disconnect(pp);
4216 /***********************************************************************
4218 * ftp_parse_url_path()
4220 * Parse the URL path into separate path components.
4224 CURLcode ftp_parse_url_path(struct connectdata *conn)
4226 struct SessionHandle *data = conn->data;
4227 /* the ftp struct is already inited in ftp_connect() */
4228 struct FTP *ftp = data->req.protop;
4229 struct ftp_conn *ftpc = &conn->proto.ftpc;
4230 const char *slash_pos; /* position of the first '/' char in curpos */
4231 const char *path_to_use = data->state.path;
4232 const char *cur_pos;
4233 const char *filename = NULL;
4235 cur_pos = path_to_use; /* current position in path. point at the begin
4236 of next path component */
4238 ftpc->ctl_valid = FALSE;
4239 ftpc->cwdfail = FALSE;
4241 switch(data->set.ftp_filemethod) {
4243 /* fastest, but less standard-compliant */
4246 The best time to check whether the path is a file or directory is right
4249 the first condition in the if() right here, is there just in case
4250 someone decides to set path to NULL one day
4252 if(data->state.path &&
4253 data->state.path[0] &&
4254 (data->state.path[strlen(data->state.path) - 1] != '/') )
4255 filename = data->state.path; /* this is a full file path */
4257 ftpc->file is not used anywhere other than for operations on a file.
4258 In other words, never for directory operations.
4259 So we can safely leave filename as NULL here and use it as a
4260 argument in dir/file decisions.
4264 case FTPFILE_SINGLECWD:
4265 /* get the last slash */
4266 if(!path_to_use[0]) {
4267 /* no dir, no file */
4271 slash_pos=strrchr(cur_pos, '/');
4272 if(slash_pos || !*cur_pos) {
4273 size_t dirlen = slash_pos-cur_pos;
4275 ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
4277 return CURLE_OUT_OF_MEMORY;
4282 ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
4283 slash_pos ? curlx_uztosi(dirlen) : 1,
4285 if(!ftpc->dirs[0]) {
4287 return CURLE_OUT_OF_MEMORY;
4289 ftpc->dirdepth = 1; /* we consider it to be a single dir */
4290 filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
4293 filename = cur_pos; /* this is a file name only */
4296 default: /* allow pretty much anything */
4297 case FTPFILE_MULTICWD:
4299 ftpc->diralloc = 5; /* default dir depth to allocate */
4300 ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
4302 return CURLE_OUT_OF_MEMORY;
4304 /* we have a special case for listing the root dir only */
4305 if(strequal(path_to_use, "/")) {
4306 cur_pos++; /* make it point to the zero byte */
4307 ftpc->dirs[0] = strdup("/");
4311 /* parse the URL path into separate path components */
4312 while((slash_pos = strchr(cur_pos, '/')) != NULL) {
4313 /* 1 or 0 pointer offset to indicate absolute directory */
4314 ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
4315 (ftpc->dirdepth == 0))?1:0;
4317 /* seek out the next path component */
4318 if(slash_pos-cur_pos) {
4319 /* we skip empty path components, like "x//y" since the FTP command
4320 CWD requires a parameter and a non-existent parameter a) doesn't
4321 work on many servers and b) has no effect on the others. */
4322 int len = curlx_sztosi(slash_pos - cur_pos + absolute_dir);
4323 ftpc->dirs[ftpc->dirdepth] =
4324 curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);
4325 if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
4326 failf(data, "no memory");
4328 return CURLE_OUT_OF_MEMORY;
4330 if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
4331 free(ftpc->dirs[ftpc->dirdepth]);
4333 return CURLE_URL_MALFORMAT;
4337 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4338 if(!ftpc->dirdepth) {
4339 /* path starts with a slash, add that as a directory */
4340 ftpc->dirs[ftpc->dirdepth] = strdup("/");
4341 if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */
4342 failf(data, "no memory");
4344 return CURLE_OUT_OF_MEMORY;
4350 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4351 if(++ftpc->dirdepth >= ftpc->diralloc) {
4354 ftpc->diralloc *= 2; /* double the size each time */
4355 bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
4358 return CURLE_OUT_OF_MEMORY;
4360 ftpc->dirs = bigger;
4364 filename = cur_pos; /* the rest is the file name */
4368 if(filename && *filename) {
4369 ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
4370 if(NULL == ftpc->file) {
4372 failf(data, "no memory");
4373 return CURLE_OUT_OF_MEMORY;
4375 if(isBadFtpString(ftpc->file)) {
4377 return CURLE_URL_MALFORMAT;
4381 ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
4384 if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
4385 /* We need a file name when uploading. Return error! */
4386 failf(data, "Uploading to a URL without a file name!");
4387 return CURLE_URL_MALFORMAT;
4390 ftpc->cwddone = FALSE; /* default to not done */
4392 if(ftpc->prevpath) {
4393 /* prevpath is "raw" so we convert the input path before we compare the
4396 char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
4399 return CURLE_OUT_OF_MEMORY;
4402 dlen -= ftpc->file?curlx_uztosi(strlen(ftpc->file)):0;
4403 if((dlen == curlx_uztosi(strlen(ftpc->prevpath))) &&
4404 strnequal(path, ftpc->prevpath, dlen)) {
4405 infof(data, "Request has same path as previous transfer\n");
4406 ftpc->cwddone = TRUE;
4414 /* call this when the DO phase has completed */
4415 static CURLcode ftp_dophase_done(struct connectdata *conn,
4418 struct FTP *ftp = conn->data->req.protop;
4419 struct ftp_conn *ftpc = &conn->proto.ftpc;
4423 CURLcode result = ftp_do_more(conn, &completed);
4426 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
4427 /* close the second socket if it was created already */
4428 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
4429 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
4435 if(ftp->transfer != FTPTRANSFER_BODY)
4436 /* no data to transfer */
4437 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
4439 /* since we didn't connect now, we want do_more to get called */
4440 conn->bits.do_more = TRUE;
4442 ftpc->ctl_valid = TRUE; /* seems good */
4447 /* called from multi.c while DOing */
4448 static CURLcode ftp_doing(struct connectdata *conn,
4451 CURLcode result = ftp_multi_statemach(conn, dophase_done);
4454 DEBUGF(infof(conn->data, "DO phase failed\n"));
4455 else if(*dophase_done) {
4456 result = ftp_dophase_done(conn, FALSE /* not connected */);
4458 DEBUGF(infof(conn->data, "DO phase is complete2\n"));
4463 /***********************************************************************
4465 * ftp_regular_transfer()
4467 * The input argument is already checked for validity.
4469 * Performs all commands done before a regular transfer between a local and a
4472 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
4473 * ftp_done() function without finding any major problem.
4476 CURLcode ftp_regular_transfer(struct connectdata *conn,
4479 CURLcode result=CURLE_OK;
4480 bool connected=FALSE;
4481 struct SessionHandle *data = conn->data;
4482 struct ftp_conn *ftpc = &conn->proto.ftpc;
4483 data->req.size = -1; /* make sure this is unknown at this point */
4485 Curl_pgrsSetUploadCounter(data, 0);
4486 Curl_pgrsSetDownloadCounter(data, 0);
4487 Curl_pgrsSetUploadSize(data, -1);
4488 Curl_pgrsSetDownloadSize(data, -1);
4490 ftpc->ctl_valid = TRUE; /* starts good */
4492 result = ftp_perform(conn,
4493 &connected, /* have we connected after PASV/PORT */
4494 dophase_done); /* all commands in the DO-phase done? */
4499 /* the DO phase has not completed yet */
4502 result = ftp_dophase_done(conn, connected);
4513 static CURLcode ftp_setup_connection(struct connectdata *conn)
4515 struct SessionHandle *data = conn->data;
4520 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
4521 /* Unless we have asked to tunnel ftp operations through the proxy, we
4522 switch and use HTTP operations only */
4523 #ifndef CURL_DISABLE_HTTP
4524 if(conn->handler == &Curl_handler_ftp)
4525 conn->handler = &Curl_handler_ftp_proxy;
4528 conn->handler = &Curl_handler_ftps_proxy;
4530 failf(data, "FTPS not supported!");
4531 return CURLE_UNSUPPORTED_PROTOCOL;
4534 /* set it up as a HTTP connection instead */
4535 return conn->handler->setup_connection(conn);
4537 failf(data, "FTP over http proxy requires HTTP support built-in!");
4538 return CURLE_UNSUPPORTED_PROTOCOL;
4542 conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
4544 return CURLE_OUT_OF_MEMORY;
4546 data->state.path++; /* don't include the initial slash */
4547 data->state.slash_removed = TRUE; /* we've skipped the slash */
4549 /* FTP URLs support an extension like ";type=<typecode>" that
4550 * we'll try to get now! */
4551 type = strstr(data->state.path, ";type=");
4554 type = strstr(conn->host.rawalloc, ";type=");
4557 *type = 0; /* it was in the middle of the hostname */
4558 command = Curl_raw_toupper(type[6]);
4559 conn->bits.type_set = TRUE;
4562 case 'A': /* ASCII mode */
4563 data->set.prefer_ascii = TRUE;
4566 case 'D': /* directory mode */
4567 data->set.ftp_list_only = TRUE;
4570 case 'I': /* binary mode */
4572 /* switch off ASCII */
4573 data->set.prefer_ascii = FALSE;
4578 /* get some initial data into the ftp struct */
4579 ftp->bytecountp = &conn->data->req.bytecount;
4580 ftp->transfer = FTPTRANSFER_BODY;
4581 ftp->downloadsize = 0;
4583 /* No need to duplicate user+password, the connectdata struct won't change
4584 during a session, but we re-init them here since on subsequent inits
4585 since the conn struct may have changed or been replaced.
4587 ftp->user = conn->user;
4588 ftp->passwd = conn->passwd;
4589 if(isBadFtpString(ftp->user))
4590 return CURLE_URL_MALFORMAT;
4591 if(isBadFtpString(ftp->passwd))
4592 return CURLE_URL_MALFORMAT;
4594 conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
4599 #endif /* CURL_DISABLE_FTP */