1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2004, 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.
22 ***************************************************************************/
26 #ifndef CURL_DISABLE_FTP
37 #ifdef HAVE_SYS_SELECT_H
38 #include <sys/select.h>
41 #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
43 #else /* some kind of unix */
44 #ifdef HAVE_SYS_SOCKET_H
45 #include <sys/socket.h>
47 #include <sys/types.h>
48 #ifdef HAVE_NETINET_IN_H
49 #include <netinet/in.h>
51 #ifdef HAVE_ARPA_INET_H
52 #include <arpa/inet.h>
54 #include <sys/utsname.h>
64 #if defined(WIN32) && defined(__GNUC__) || defined(__MINGW32__)
68 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
70 #define in_addr_t unsigned long
73 #include <curl/curl.h>
82 #include "http.h" /* for HTTP proxy tunnel stuff */
90 #include "strtoofft.h"
97 #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
98 #include "inet_ntoa_r.h"
101 #define _MPRINTF_REPLACE /* use our functions only */
102 #include <curl/mprintf.h>
104 /* The last #include file should be: */
106 #include "memdebug.h"
109 #ifdef HAVE_NI_WITHSCOPEID
110 #define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID
112 #define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV
115 /* Local API functions */
116 static CURLcode ftp_sendquote(struct connectdata *conn,
117 struct curl_slist *quote);
118 static CURLcode ftp_cwd(struct connectdata *conn, char *path);
119 static CURLcode ftp_mkd(struct connectdata *conn, char *path);
120 static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path);
121 static CURLcode ftp_quit(struct connectdata *conn);
123 /* easy-to-use macro: */
124 #define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z))) return result
126 static void freedirs(struct FTP *ftp)
130 for (i=0; i < ftp->dirdepth; i++){
145 /***********************************************************************
147 * AllowServerConnect()
149 * When we've issue the PORT command, we have told the server to connect
150 * to us. This function will sit and wait here until the server has
154 static CURLcode AllowServerConnect(struct connectdata *conn)
158 struct SessionHandle *data = conn->data;
159 curl_socket_t sock = conn->sock[SECONDARYSOCKET];
160 struct timeval now = Curl_tvnow();
161 long timespent = Curl_tvdiff(Curl_tvnow(), now)/1000;
162 long timeout = data->set.connecttimeout?data->set.connecttimeout:
163 (data->set.timeout?data->set.timeout: 0);
167 FD_SET(sock, &rdset);
170 timeout -= timespent;
172 failf(data, "Timed out before server could connect to us");
173 return CURLE_OPERATION_TIMEDOUT;
177 /* we give the server 60 seconds to connect to us, or a custom timeout */
178 dt.tv_sec = (int)(timeout?timeout:60);
181 switch (select(sock+1, &rdset, NULL, NULL, &dt)) {
184 failf(data, "Error while waiting for server connect");
185 return CURLE_FTP_PORT_FAILED;
186 case 0: /* timeout */
188 failf(data, "Timeout while waiting for server connect");
189 return CURLE_FTP_PORT_FAILED;
191 /* we have received data here */
194 size_t size = sizeof(struct sockaddr_in);
195 struct sockaddr_in add;
197 getsockname(sock, (struct sockaddr *) &add, (socklen_t *)&size);
198 s=accept(sock, (struct sockaddr *) &add, (socklen_t *)&size);
200 sclose(sock); /* close the first socket */
202 if (CURL_SOCKET_BAD == s) {
204 failf(data, "Error accept()ing server connect");
205 return CURLE_FTP_PORT_FAILED;
207 infof(data, "Connection accepted from server\n");
209 conn->sock[SECONDARYSOCKET] = s;
210 Curl_nonblock(s, TRUE); /* enable non-blocking */
219 /* --- parse FTP server responses --- */
222 * Curl_GetFTPResponse() is supposed to be invoked after each command sent to
223 * a remote FTP server. This function will wait and read all lines of the
224 * response and extract the relevant return code for the invoking function.
227 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
228 struct connectdata *conn,
229 int *ftpcode) /* return the ftp-code */
231 /* Brand new implementation.
232 * We cannot read just one byte per read() and then go back to select()
233 * as it seems that the OpenSSL read() stuff doesn't grok that properly.
235 * Alas, read as much as possible, split up into lines, use the ending
236 * line in a response or continue reading. */
238 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
239 int perline; /* count bytes per line */
243 long timeout; /* timeout in seconds */
244 struct timeval interval;
247 struct SessionHandle *data = conn->data;
249 int code=0; /* default ftp "error code" to return */
250 char *buf = data->state.buffer;
251 CURLcode result = CURLE_OK;
252 struct FTP *ftp = conn->proto.ftp;
253 struct timeval now = Curl_tvnow();
256 *ftpcode = 0; /* 0 for errors */
258 FD_ZERO (&readfd); /* clear it */
259 FD_SET (sockfd, &readfd); /* read socket */
261 /* get this in a backup variable to be able to restore it on each lap in the
272 while((*nreadp<BUFSIZE) && (keepon && !result)) {
273 /* check and reset timeout value every lap */
274 if(data->set.ftp_response_timeout )
275 /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine
276 remaining time. Also, use "now" as opposed to "conn->now"
277 because ftp_response_timeout is only supposed to govern
278 the response for any given ftp response, not for the time
279 from connect to the given ftp response. */
280 timeout = data->set.ftp_response_timeout - /* timeout time */
281 Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
282 else if(data->set.timeout)
283 /* if timeout is requested, find out how much remaining time we have */
284 timeout = data->set.timeout - /* timeout time */
285 Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
287 /* Even without a requested timeout, we only wait response_time
288 seconds for the full response to arrive before we bail out */
289 timeout = ftp->response_time -
290 Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
293 failf(data, "FTP response timeout");
294 return CURLE_OPERATION_TIMEDOUT; /* already too little time */
298 readfd = rkeepfd; /* set every lap */
299 interval.tv_sec = 1; /* use 1 second timeout intervals */
300 interval.tv_usec = 0;
302 switch (select (sockfd+1, &readfd, NULL, NULL, &interval)) {
303 case -1: /* select() error, stop reading */
304 result = CURLE_RECV_ERROR;
305 failf(data, "FTP response aborted due to select() error: %d", errno);
307 case 0: /* timeout */
308 if(Curl_pgrsUpdate(conn))
309 return CURLE_ABORTED_BY_CALLBACK;
310 continue; /* just continue in our loop for the timeout duration */
316 if(CURLE_OK == result) {
318 * This code previously didn't use the kerberos sec_read() code
319 * to read, but when we use Curl_read() it may do so. Do confirm
320 * that this is still ok and then remove this comment!
323 /* we had data in the "cache", copy that instead of doing an actual
326 * Dave Meyer, December 2003:
327 * ftp->cache_size is cast to int here. This should be safe,
328 * because it would have been populated with something of size
329 * int to begin with, even though its datatype may be larger
332 memcpy(ptr, ftp->cache, (int)ftp->cache_size);
333 gotbytes = (int)ftp->cache_size;
334 free(ftp->cache); /* free the cache */
335 ftp->cache = NULL; /* clear the pointer */
336 ftp->cache_size = 0; /* zero the size just in case */
339 int res = Curl_read(conn, sockfd, ptr, BUFSIZE-*nreadp, &gotbytes);
342 continue; /* go looping again */
350 else if(gotbytes <= 0) {
352 result = CURLE_RECV_ERROR;
353 failf(data, "FTP response reading failed");
356 /* we got a whole chunk of data, which can be anything from one
357 * byte to a set of lines and possible just a piece of the last
361 conn->headerbytecount += gotbytes;
364 for(i = 0; i < gotbytes; ptr++, i++) {
367 /* a newline is CRLF in ftp-talk, so the CR is ignored as
368 the line isn't really terminated until the LF comes */
370 /* output debug output if that is requested */
371 if(data->set.verbose)
372 Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline);
375 * We pass all response-lines to the callback function registered
376 * for "headers". The response lines can be seen as a kind of
379 result = Curl_client_write(data, CLIENTWRITE_HEADER,
380 line_start, perline);
384 #define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
385 isdigit((int)line[2]) && (' ' == line[3]))
387 if(perline>3 && lastline(line_start)) {
388 /* This is the end of the last line, copy the last
389 * line to the start of the buffer and zero terminate,
390 * for old times sake (and krb4)! */
393 for(meow=line_start, n=0; meow<ptr; meow++, n++)
395 *meow=0; /* zero terminate */
397 line_start = ptr+1; /* advance pointer */
398 i++; /* skip this before getting out */
401 perline=0; /* line starts over here */
405 if(!keepon && (i != gotbytes)) {
406 /* We found the end of the response lines, but we didn't parse the
407 full chunk of data we have read from the server. We therefore
408 need to store the rest of the data to be checked on the next
409 invoke as it may actually contain another end of response
410 already! Cleverly figured out by Eric Lavigne in December
412 ftp->cache_size = gotbytes - i;
413 ftp->cache = (char *)malloc((int)ftp->cache_size);
415 memcpy(ftp->cache, line_start, (int)ftp->cache_size);
417 return CURLE_OUT_OF_MEMORY; /**BANG**/
419 } /* there was data */
421 } /* while there's buffer left and loop is requested */
427 /* handle the security-oriented responses 6xx ***/
428 /* FIXME: some errorchecking perhaps... ***/
431 Curl_sec_read_msg(conn, buf, prot_safe);
434 Curl_sec_read_msg(conn, buf, prot_private);
437 Curl_sec_read_msg(conn, buf, prot_confidential);
440 /* normal ftp stuff we pass through! */
446 *ftpcode=code; /* return the initial number like this */
448 /* store the latest code for later retrieval */
449 conn->data->info.httpcode=code;
454 static const char *ftpauth[]= {
459 * Curl_ftp_connect() should do everything that is to be considered a part of
460 * the connection phase.
462 CURLcode Curl_ftp_connect(struct connectdata *conn)
464 /* this is FTP and no proxy */
466 struct SessionHandle *data=conn->data;
467 char *buf = data->state.buffer; /* this is our buffer */
472 ftp = (struct FTP *)malloc(sizeof(struct FTP));
474 return CURLE_OUT_OF_MEMORY;
476 memset(ftp, 0, sizeof(struct FTP));
477 conn->proto.ftp = ftp;
479 /* We always support persistant connections on ftp */
480 conn->bits.close = FALSE;
482 /* get some initial data into the ftp struct */
483 ftp->bytecountp = &conn->bytecount;
485 /* no need to duplicate them, this connectdata struct won't change */
486 ftp->user = conn->user;
487 ftp->passwd = conn->passwd;
488 ftp->response_time = 3600; /* set default response time-out */
490 if (conn->bits.tunnel_proxy) {
491 /* We want "seamless" FTP operations through HTTP proxy tunnel */
492 result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET,
493 conn->host.name, conn->remote_port);
494 if(CURLE_OK != result)
498 if(conn->protocol & PROT_FTPS) {
499 /* FTPS is simply ftp with SSL for the control channel */
500 /* now, perform the SSL initialization for this socket */
501 result = Curl_SSLConnect(conn, FIRSTSOCKET);
506 /* The first thing we do is wait for the "220*" line: */
507 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
512 failf(data, "This doesn't seem like a nice ftp-server response");
513 return CURLE_FTP_WEIRD_SERVER_REPLY;
517 /* if not anonymous login, try a secure login */
520 /* request data protection level (default is 'clear') */
521 Curl_sec_request_prot(conn, "private");
523 /* We set private first as default, in case the line below fails to
525 Curl_sec_request_prot(conn, data->set.krb4_level);
527 if(Curl_sec_login(conn) != 0)
528 infof(data, "Logging in with password in cleartext!\n");
530 infof(data, "Authentication successful\n");
534 if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
535 /* we don't have a SSL/TLS connection, try a FTPS connection now */
537 for (try = 0; ftpauth[try]; try++) {
539 FTPSENDF(conn, "AUTH %s", ftpauth[try]);
541 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
546 /* RFC2228 (page 5) says:
548 * If the server is willing to accept the named security mechanism, and
549 * does not require any security data, it must respond with reply code
553 if((ftpcode == 234) || (ftpcode == 334)) {
554 result = Curl_SSLConnect(conn, FIRSTSOCKET);
557 conn->protocol |= PROT_FTPS;
558 conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
565 FTPSENDF(conn, "USER %s", ftp->user?ftp->user:"");
567 /* wait for feedback */
568 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
573 /* 530 User ... access denied
574 (the server denies to log the specified user) */
575 failf(data, "Access denied: %s", &buf[4]);
576 return CURLE_FTP_ACCESS_DENIED;
578 else if(ftpcode == 331) {
579 /* 331 Password required for ...
580 (the server requires to send the user's password too) */
581 FTPSENDF(conn, "PASS %s", ftp->passwd?ftp->passwd:"");
582 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
587 /* 530 Login incorrect.
588 (the username and/or the password are incorrect) */
589 failf(data, "the username and/or the password are incorrect");
590 return CURLE_FTP_USER_PASSWORD_INCORRECT;
592 else if(ftpcode == 230) {
593 /* 230 User ... logged in.
594 (user successfully logged in) */
596 infof(data, "We have successfully logged in\n");
599 failf(data, "Odd return code after PASS");
600 return CURLE_FTP_WEIRD_PASS_REPLY;
603 else if(buf[0] == '2') {
604 /* 230 User ... logged in.
605 (the user logged in without password) */
606 infof(data, "We have successfully logged in\n");
607 if (conn->ssl[FIRSTSOCKET].use) {
609 /* We are logged in with Kerberos, now set the requested protection
612 if(conn->sec_complete)
613 Curl_sec_set_protection_level(conn);
615 /* We may need to issue a KAUTH here to have access to the files
616 * do it if user supplied a password
618 if(conn->passwd && *conn->passwd) {
619 result = Curl_krb_kauth(conn);
627 failf(data, "Odd return code after USER");
628 return CURLE_FTP_WEIRD_USER_REPLY;
631 if(conn->ssl[FIRSTSOCKET].use) {
632 /* PBSZ = PROTECTION BUFFER SIZE.
634 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
636 Specifically, the PROT command MUST be preceded by a PBSZ command
637 and a PBSZ command MUST be preceded by a successful security data
638 exchange (the TLS negotiation in this case)
642 Thus the PBSZ command must still be issued, but must have a parameter
643 of '0' to indicate that no buffering is taking place and the data
644 connection should not be encapsulated.
646 FTPSENDF(conn, "PBSZ %d", 0);
647 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
651 /* For TLS, the data connection can have one of two security levels.
653 1)Clear (requested by 'PROT C')
655 2)Private (requested by 'PROT P')
657 if(!conn->ssl[SECONDARYSOCKET].use) {
658 FTPSENDF(conn, "PROT %c", 'P');
659 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
664 /* We have enabled SSL for the data connection! */
665 conn->ssl[SECONDARYSOCKET].use = TRUE;
667 /* FTP servers typically responds with 500 if they decide to reject
672 /* send PWD to discover our entry point */
673 FTPSENDF(conn, "PWD", NULL);
675 /* wait for feedback */
676 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
681 char *dir = (char *)malloc(nread+1);
683 char *ptr=&buf[4]; /* start on the first letter */
686 return CURLE_OUT_OF_MEMORY;
688 /* Reply format is like
689 257<space>"<directory-name>"<space><commentary> and the RFC959 says
691 The directory name can contain any character; embedded double-quotes
692 should be escaped by double-quotes (the "quote-doubling" convention).
695 /* it started good */
700 /* "quote-doubling" */
706 *store = '\0'; /* zero terminate */
707 break; /* get out of this loop */
715 ftp->entrypath =dir; /* remember this */
716 infof(data, "Entry path is '%s'\n", ftp->entrypath);
719 /* couldn't get the path */
721 infof(data, "Failed to figure out path\n");
726 /* We couldn't read the PWD response! */
732 /***********************************************************************
736 * The DONE function. This does what needs to be done after a single DO has
739 * Input argument is already checked for validity.
741 CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
743 struct SessionHandle *data = conn->data;
744 struct FTP *ftp = conn->proto.ftp;
747 CURLcode result=CURLE_OK;
749 bool was_ctl_valid = ftp->ctl_valid;
751 /* free the dir tree and file parts */
754 ftp->ctl_valid = FALSE;
756 if(data->set.upload) {
757 if((-1 != data->set.infilesize) &&
758 (data->set.infilesize != *ftp->bytecountp) &&
760 failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
761 " out of %" FORMAT_OFF_T " bytes)",
762 *ftp->bytecountp, data->set.infilesize);
763 conn->bits.close = TRUE; /* close this connection since we don't
764 know what state this error leaves us in */
765 return CURLE_PARTIAL_FILE;
769 if((-1 != conn->size) && (conn->size != *ftp->bytecountp) &&
770 (conn->maxdownload != *ftp->bytecountp)) {
771 failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
773 conn->bits.close = TRUE; /* close this connection since we don't
774 know what state this error leaves us in */
775 return CURLE_PARTIAL_FILE;
777 else if(!ftp->dont_check &&
780 /* We consider this an error, but there's no true FTP error received
781 why we need to continue to "read out" the server response too.
782 We don't want to leave a "waiting" server reply if we'll get told
783 to make a second request on this same connection! */
784 failf(data, "No data was received!");
785 result = CURLE_FTP_COULDNT_RETR_FILE;
790 case CURLE_BAD_DOWNLOAD_RESUME:
791 case CURLE_FTP_WEIRD_PASV_REPLY:
792 case CURLE_FTP_PORT_FAILED:
793 case CURLE_FTP_COULDNT_SET_BINARY:
794 case CURLE_FTP_COULDNT_RETR_FILE:
795 case CURLE_FTP_ACCESS_DENIED:
796 /* the connection stays alive fine even though this happened */
798 case CURLE_OK: /* doesn't affect the control connection's status */
799 ftp->ctl_valid = was_ctl_valid;
801 default: /* by default, an error means the control connection is
802 wedged and should not be used anymore */
803 ftp->ctl_valid = FALSE;
808 Curl_sec_fflush_fd(conn, conn->sock[SECONDARYSOCKET]);
810 /* shut down the socket to inform the server we're done */
811 sclose(conn->sock[SECONDARYSOCKET]);
812 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
814 if(!ftp->no_transfer && !status) {
815 /* Let's see what the server says about the transfer we just performed,
816 * but lower the timeout as sometimes this connection has died while the
817 * data has been transfered. This happens when doing through NATs etc that
818 * abandon old silent connections.
820 ftp->response_time = 60; /* give it only a minute for now */
822 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
824 ftp->response_time = 3600; /* set this back to one hour waits */
826 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
827 failf(data, "control connection looks dead");
834 if(!ftp->dont_check) {
835 /* 226 Transfer complete, 250 Requested file action okay, completed. */
836 if((ftpcode != 226) && (ftpcode != 250)) {
837 failf(data, "server did not report OK, got %d", ftpcode);
838 return CURLE_FTP_WRITE_ERROR;
843 /* clear these for next connection */
844 ftp->no_transfer = FALSE;
845 ftp->dont_check = FALSE;
847 /* Send any post-transfer QUOTE strings? */
848 if(!result && data->set.postquote)
849 result = ftp_sendquote(conn, data->set.postquote);
854 /***********************************************************************
858 * Where a 'quote' means a list of custom commands to send to the server.
859 * The quote list is passed as an argument.
863 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
865 struct curl_slist *item;
873 FTPSENDF(conn, "%s", item->data);
875 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
879 if (ftpcode >= 400) {
880 failf(conn->data, "QUOT string not accepted: %s", item->data);
881 return CURLE_FTP_QUOTE_ERROR;
891 /***********************************************************************
895 * Get the timestamp of the given file.
898 CURLcode ftp_getfiletime(struct connectdata *conn, char *file)
900 CURLcode result=CURLE_OK;
901 int ftpcode; /* for ftp status */
903 char *buf = conn->data->state.buffer;
905 /* we have requested to get the modified-time of the file, this is yet
906 again a grey area as the MDTM is not kosher RFC959 */
907 FTPSENDF(conn, "MDTM %s", file);
909 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
916 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
917 last .sss part is optional and means fractions of a second */
918 int year, month, day, hour, minute, second;
919 if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
920 &year, &month, &day, &hour, &minute, &second)) {
921 /* we have a time, reformat it */
922 time_t secs=time(NULL);
923 sprintf(buf, "%04d%02d%02d %02d:%02d:%02d GMT",
924 year, month, day, hour, minute, second);
925 /* now, convert this into a time() value: */
926 conn->data->info.filetime = curl_getdate(buf, &secs);
931 infof(conn->data, "unsupported MDTM reply format\n");
933 case 550: /* "No such file or directory" */
934 failf(conn->data, "Given file does not exist");
935 result = CURLE_FTP_COULDNT_RETR_FILE;
941 /***********************************************************************
945 * Set transfer type. We only deal with ASCII or BINARY so this function
948 static CURLcode ftp_transfertype(struct connectdata *conn,
951 struct SessionHandle *data = conn->data;
956 FTPSENDF(conn, "TYPE %s", ascii?"A":"I");
958 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
963 failf(data, "Couldn't set %s mode",
964 ascii?"ASCII":"binary");
965 return ascii? CURLE_FTP_COULDNT_SET_ASCII:CURLE_FTP_COULDNT_SET_BINARY;
971 /***********************************************************************
975 * Returns the file size (in bytes) of the given remote file.
979 CURLcode ftp_getsize(struct connectdata *conn, char *file,
982 struct SessionHandle *data = conn->data;
985 char *buf=data->state.buffer;
988 FTPSENDF(conn, "SIZE %s", file);
989 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
994 /* get the size from the ascii string: */
995 *size = curlx_strtoofft(buf+4, NULL, 0);
998 return CURLE_FTP_COULDNT_GET_SIZE;
1003 /***************************************************************************
1005 * ftp_pasv_verbose()
1007 * This function only outputs some informationals about this second connection
1008 * when we've issued a PASV command before and thus we have connected to a
1009 * possibly new IP address.
1013 ftp_pasv_verbose(struct connectdata *conn,
1014 Curl_ipconnect *addr,
1015 char *newhost, /* ascii version */
1019 /*****************************************************************
1021 * IPv4-only code section
1025 struct hostent * answer;
1027 #ifdef HAVE_INET_NTOA_R
1030 /* The array size trick below is to make this a large chunk of memory
1031 suitably 8-byte aligned on 64-bit platforms. This was thoughtfully
1032 suggested by Philip Gladstone. */
1033 long bigbuf[9000 / sizeof(long)];
1035 #if defined(HAVE_INET_ADDR)
1037 # if defined(HAVE_GETHOSTBYADDR_R)
1040 char *hostent_buf = (char *)bigbuf; /* get a char * to the buffer */
1042 address = inet_addr(newhost);
1043 # ifdef HAVE_GETHOSTBYADDR_R
1045 # ifdef HAVE_GETHOSTBYADDR_R_5
1046 /* AIX, Digital Unix (OSF1, Tru64) style:
1047 extern int gethostbyaddr_r(char *addr, size_t len, int type,
1048 struct hostent *htent, struct hostent_data *ht_data); */
1050 /* Fred Noz helped me try this out, now it at least compiles! */
1052 /* Bjorn Reese (November 28 2001):
1053 The Tru64 man page on gethostbyaddr_r() says that
1054 the hostent struct must be filled with zeroes before the call to
1057 ... as must be struct hostent_data Craig Markwardt 19 Sep 2002. */
1059 memset(hostent_buf, 0, sizeof(struct hostent)+sizeof(struct hostent_data));
1061 if(gethostbyaddr_r((char *) &address,
1062 sizeof(address), AF_INET,
1063 (struct hostent *)hostent_buf,
1064 (struct hostent_data *)(hostent_buf + sizeof(*answer))))
1067 answer=(struct hostent *)hostent_buf;
1070 # ifdef HAVE_GETHOSTBYADDR_R_7
1071 /* Solaris and IRIX */
1072 answer = gethostbyaddr_r((char *) &address, sizeof(address), AF_INET,
1073 (struct hostent *)bigbuf,
1074 hostent_buf + sizeof(*answer),
1075 sizeof(bigbuf) - sizeof(*answer),
1078 # ifdef HAVE_GETHOSTBYADDR_R_8
1080 if(gethostbyaddr_r((char *) &address, sizeof(address), AF_INET,
1081 (struct hostent *)hostent_buf,
1082 hostent_buf + sizeof(*answer),
1083 sizeof(bigbuf) - sizeof(*answer),
1086 answer=NULL; /* error */
1090 (void)hostent_buf; /* avoid compiler warning */
1091 answer = gethostbyaddr((char *) &address, sizeof(address), AF_INET);
1096 (void) memcpy(&in.s_addr, addr, sizeof (Curl_ipconnect));
1097 infof(conn->data, "Connecting to %s (%s) port %u\n",
1098 answer?answer->h_name:newhost,
1099 #if defined(HAVE_INET_NTOA_R)
1100 inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)),
1107 /*****************************************************************
1109 * IPv6-only code section
1111 char hbuf[NI_MAXHOST]; /* ~1KB */
1112 char nbuf[NI_MAXHOST]; /* ~1KB */
1113 char sbuf[NI_MAXSERV]; /* around 32 */
1114 (void)port; /* prevent compiler warning */
1115 if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
1116 nbuf, sizeof(nbuf), sbuf, sizeof(sbuf), NIFLAGS)) {
1117 snprintf(nbuf, sizeof(nbuf), "?");
1118 snprintf(sbuf, sizeof(sbuf), "?");
1121 if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
1122 hbuf, sizeof(hbuf), NULL, 0, 0)) {
1123 infof(conn->data, "Connecting to %s (%s) port %s\n", nbuf, newhost, sbuf);
1126 infof(conn->data, "Connecting to %s (%s) port %s\n", hbuf, nbuf, sbuf);
1131 /***********************************************************************
1135 * Send the proper PORT command. PORT is the ftp client's way of telling the
1136 * server that *WE* open a port that we listen on an awaits the server to
1137 * connect to. This is the opposite of PASV.
1141 CURLcode ftp_use_port(struct connectdata *conn)
1143 struct SessionHandle *data=conn->data;
1144 curl_socket_t portsock= CURL_SOCKET_BAD;
1146 int ftpcode; /* receive FTP response codes in this */
1150 /******************************************************************
1152 * Here's a piece of IPv6-specific code coming up
1156 struct addrinfo hints, *res, *ai;
1157 struct sockaddr_storage ss;
1159 char hbuf[NI_MAXHOST];
1161 struct sockaddr *sa=(struct sockaddr *)&ss;
1164 char portmsgbuf[4096], tmp[4096];
1166 const char *mode[] = { "EPRT", "LPRT", "PORT", NULL };
1172 * we should use Curl_if2ip? given pickiness of recent ftpd,
1173 * I believe we should use the same address as the control connection.
1176 rc = getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)&ss, &sslen);
1178 failf(data, "getsockname() returned %d\n", rc);
1179 return CURLE_FTP_PORT_FAILED;
1182 rc = getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, 0,
1185 failf(data, "getnameinfo() returned %d\n", rc);
1186 return CURLE_FTP_PORT_FAILED;
1189 memset(&hints, 0, sizeof(hints));
1190 hints.ai_family = sa->sa_family;
1191 /*hints.ai_family = ss.ss_family;
1192 this way can be used if sockaddr_storage is properly defined, as glibc
1194 hints.ai_socktype = SOCK_STREAM;
1195 hints.ai_flags = AI_PASSIVE;
1197 rc = getaddrinfo(hbuf, NULL, &hints, &res);
1199 failf(data, "getaddrinfo() returned %d\n", rc);
1200 return CURLE_FTP_PORT_FAILED;
1203 portsock = CURL_SOCKET_BAD;
1205 for (ai = res; ai; ai = ai->ai_next) {
1207 * Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype):
1209 if (ai->ai_socktype == 0)
1210 ai->ai_socktype = hints.ai_socktype;
1212 portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1213 if (portsock == CURL_SOCKET_BAD) {
1214 error = Curl_ourerrno();
1218 if (bind(portsock, ai->ai_addr, ai->ai_addrlen) < 0) {
1219 error = Curl_ourerrno();
1221 portsock = CURL_SOCKET_BAD;
1225 if (listen(portsock, 1) < 0) {
1226 error = Curl_ourerrno();
1228 portsock = CURL_SOCKET_BAD;
1235 if (portsock == CURL_SOCKET_BAD) {
1236 failf(data, "%s", Curl_strerror(conn,error));
1237 return CURLE_FTP_PORT_FAILED;
1241 if (getsockname(portsock, sa, &sslen) < 0) {
1242 failf(data, "%s", Curl_strerror(conn,Curl_ourerrno()));
1243 return CURLE_FTP_PORT_FAILED;
1246 for (modep = (char **)(data->set.ftp_use_eprt?&mode[0]:&mode[2]);
1247 modep && *modep; modep++) {
1251 switch (sa->sa_family) {
1253 ap = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_addr;
1254 alen = sizeof(((struct sockaddr_in *)&ss)->sin_addr);
1255 pp = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_port;
1256 plen = sizeof(((struct sockaddr_in *)&ss)->sin_port);
1261 ap = (unsigned char *)&((struct sockaddr_in6 *)&ss)->sin6_addr;
1262 alen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_addr);
1263 pp = (unsigned char *)&((struct sockaddr_in6 *)&ss)->sin6_port;
1264 plen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_port);
1270 lprtaf = eprtaf = -1;
1274 if (strcmp(*modep, "EPRT") == 0) {
1277 if (getnameinfo((struct sockaddr *)&ss, sslen,
1278 portmsgbuf, sizeof(portmsgbuf), tmp, sizeof(tmp),
1282 /* do not transmit IPv6 scope identifier to the wire */
1283 if (sa->sa_family == AF_INET6) {
1284 char *q = strchr(portmsgbuf, '%');
1289 result = Curl_ftpsendf(conn, "%s |%d|%s|%s|", *modep, eprtaf,
1294 else if (strcmp(*modep, "LPRT") == 0 ||
1295 strcmp(*modep, "PORT") == 0) {
1298 if (strcmp(*modep, "LPRT") == 0 && lprtaf < 0)
1300 if (strcmp(*modep, "PORT") == 0 && sa->sa_family != AF_INET)
1303 portmsgbuf[0] = '\0';
1304 if (strcmp(*modep, "LPRT") == 0) {
1305 snprintf(tmp, sizeof(tmp), "%d,%d", lprtaf, alen);
1306 if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1307 sizeof(portmsgbuf)) {
1312 for (i = 0; i < alen; i++) {
1314 snprintf(tmp, sizeof(tmp), ",%u", ap[i]);
1316 snprintf(tmp, sizeof(tmp), "%u", ap[i]);
1318 if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1319 sizeof(portmsgbuf)) {
1324 if (strcmp(*modep, "LPRT") == 0) {
1325 snprintf(tmp, sizeof(tmp), ",%d", plen);
1327 if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf))
1331 for (i = 0; i < plen; i++) {
1332 snprintf(tmp, sizeof(tmp), ",%u", pp[i]);
1334 if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1335 sizeof(portmsgbuf)) {
1340 result = Curl_ftpsendf(conn, "%s %s", *modep, portmsgbuf);
1345 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1349 if (ftpcode != 200) {
1358 failf(data, "PORT command attempts failed");
1359 return CURLE_FTP_PORT_FAILED;
1361 /* we set the secondary socket variable to this for now, it
1362 is only so that the cleanup function will close it in case
1363 we fail before the true secondary stuff is made */
1364 conn->sock[SECONDARYSOCKET] = portsock;
1367 /******************************************************************
1369 * Here's a piece of IPv4-specific code coming up
1372 struct sockaddr_in sa;
1373 struct Curl_dns_entry *h=NULL;
1374 unsigned short porttouse;
1375 char myhost[256] = "";
1376 bool sa_filled_in = FALSE;
1378 if(data->set.ftpport) {
1382 /* First check if the given name is an IP address */
1383 in=inet_addr(data->set.ftpport);
1385 if((in == CURL_INADDR_NONE) &&
1386 Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) {
1387 rc = Curl_resolv(conn, myhost, 0, &h);
1388 if(rc == CURLRESOLV_PENDING)
1389 rc = Curl_wait_for_resolv(conn, &h);
1392 size_t len = strlen(data->set.ftpport);
1394 rc = Curl_resolv(conn, data->set.ftpport, 0, &h);
1395 if(rc == CURLRESOLV_PENDING)
1396 rc = Curl_wait_for_resolv(conn, &h);
1399 strcpy(myhost, data->set.ftpport); /* buffer overflow risk */
1403 /* pick a suitable default here */
1408 if (getsockname(conn->sock[FIRSTSOCKET],
1409 (struct sockaddr *)&sa, &sslen) < 0) {
1410 failf(data, "getsockname() failed");
1411 return CURLE_FTP_PORT_FAILED;
1414 sa_filled_in = TRUE; /* the sa struct is filled in */
1418 /* when we return from here, we can forget about this */
1419 Curl_resolv_unlock(data, h);
1421 if ( h || sa_filled_in) {
1422 if( (portsock = socket(AF_INET, SOCK_STREAM, 0)) != CURL_SOCKET_BAD ) {
1425 /* we set the secondary socket variable to this for now, it
1426 is only so that the cleanup function will close it in case
1427 we fail before the true secondary stuff is made */
1428 conn->sock[SECONDARYSOCKET] = portsock;
1431 memset((char *)&sa, 0, sizeof(sa));
1432 memcpy((char *)&sa.sin_addr,
1435 sa.sin_family = AF_INET;
1436 sa.sin_addr.s_addr = INADDR_ANY;
1442 if(bind(portsock, (struct sockaddr *)&sa, size) >= 0) {
1443 /* we succeeded to bind */
1444 struct sockaddr_in add;
1445 socklen_t socksize = sizeof(add);
1447 if(getsockname(portsock, (struct sockaddr *) &add,
1449 failf(data, "getsockname() failed");
1450 return CURLE_FTP_PORT_FAILED;
1452 porttouse = ntohs(add.sin_port);
1454 if ( listen(portsock, 1) < 0 ) {
1455 failf(data, "listen(2) failed on socket");
1456 return CURLE_FTP_PORT_FAILED;
1460 failf(data, "bind(2) failed on socket");
1461 return CURLE_FTP_PORT_FAILED;
1465 failf(data, "socket(2) failed (%s)");
1466 return CURLE_FTP_PORT_FAILED;
1470 failf(data, "could't find my own IP address (%s)", myhost);
1471 return CURLE_FTP_PORT_FAILED;
1474 #ifdef HAVE_INET_NTOA_R
1478 unsigned short ip[5];
1479 (void) memcpy(&in.s_addr,
1480 h?*h->addr->h_addr_list:(char *)&sa.sin_addr.s_addr,
1481 sizeof (in.s_addr));
1483 #ifdef HAVE_INET_NTOA_R
1484 /* ignore the return code from inet_ntoa_r() as it is int or
1485 char * depending on system */
1486 inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf));
1487 sscanf( ntoa_buf, "%hu.%hu.%hu.%hu",
1488 &ip[0], &ip[1], &ip[2], &ip[3]);
1490 sscanf( inet_ntoa(in), "%hu.%hu.%hu.%hu",
1491 &ip[0], &ip[1], &ip[2], &ip[3]);
1493 infof(data, "Telling server to connect to %d.%d.%d.%d:%d\n",
1494 ip[0], ip[1], ip[2], ip[3], porttouse);
1496 result=Curl_ftpsendf(conn, "PORT %d,%d,%d,%d,%d,%d",
1497 ip[0], ip[1], ip[2], ip[3],
1504 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1508 if(ftpcode != 200) {
1509 failf(data, "Server does not grok PORT, try without it!");
1510 return CURLE_FTP_PORT_FAILED;
1512 #endif /* end of ipv4-specific code */
1517 /***********************************************************************
1521 * Send the PASV command. PASV is the ftp client's way of asking the server to
1522 * open a second port that we can connect to (for the data transfer). This is
1523 * the opposite of PORT.
1527 CURLcode ftp_use_pasv(struct connectdata *conn,
1530 struct SessionHandle *data = conn->data;
1532 char *buf = data->state.buffer; /* this is our buffer */
1533 int ftpcode; /* receive FTP response codes in this */
1535 struct Curl_dns_entry *addr=NULL;
1536 Curl_ipconnect *conninfo;
1540 Here's the excecutive summary on what to do:
1542 PASV is RFC959, expect:
1543 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1545 LPSV is RFC1639, expect:
1546 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1548 EPSV is RFC2428, expect:
1549 229 Entering Extended Passive Mode (|||port|)
1553 const char *mode[] = { "EPSV", "PASV", NULL };
1554 int results[] = { 229, 227, 0 };
1556 unsigned short connectport; /* the local port connect() should use! */
1557 unsigned short newport=0; /* remote port, not necessary the local one */
1559 /* newhost must be able to hold a full IP-style address in ASCII, which
1560 in the IPv6 case means 5*8-1 = 39 letters */
1562 char *newhostp=NULL;
1564 for (modeoff = (data->set.ftp_use_epsv?0:1);
1565 mode[modeoff]; modeoff++) {
1566 result = Curl_ftpsendf(conn, "%s", mode[modeoff]);
1569 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1572 if (ftpcode == results[modeoff])
1576 if (!mode[modeoff]) {
1577 failf(data, "Odd return code after PASV");
1578 return CURLE_FTP_WEIRD_PASV_REPLY;
1580 else if (227 == results[modeoff]) {
1586 * New 227-parser June 3rd 1999.
1587 * It now scans for a sequence of six comma-separated numbers and
1588 * will take them as IP+port indicators.
1590 * Found reply-strings include:
1591 * "227 Entering Passive Mode (127,0,0,1,4,51)"
1592 * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1593 * "227 Entering passive mode. 127,0,0,1,4,51"
1597 if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1598 &ip[0], &ip[1], &ip[2], &ip[3],
1599 &port[0], &port[1]))
1605 failf(data, "Couldn't interpret this 227-reply: %s", buf);
1606 return CURLE_FTP_WEIRD_227_FORMAT;
1609 sprintf(newhost, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1611 newport = (port[0]<<8) + port[1];
1613 else if (229 == results[modeoff]) {
1614 char *ptr = strchr(buf, '(');
1619 if(5 == sscanf(ptr, "%c%c%c%u%c",
1625 char sep1 = separator[0];
1628 /* The four separators should be identical, or else this is an oddly
1629 formatted reply and we bail out immediately. */
1630 for(i=1; i<4; i++) {
1631 if(separator[i] != sep1) {
1632 ptr=NULL; /* set to NULL to signal error */
1639 /* we should use the same host we already are connected to */
1640 newhostp = conn->host.name;
1647 failf(data, "Weirdly formatted EPSV reply");
1648 return CURLE_FTP_WEIRD_PASV_REPLY;
1652 return CURLE_FTP_CANT_RECONNECT;
1654 if(data->change.proxy && *data->change.proxy) {
1656 * This is a tunnel through a http proxy and we need to connect to the
1659 * We don't want to rely on a former host lookup that might've expired
1660 * now, instead we remake the lookup here and now!
1662 rc = Curl_resolv(conn, conn->proxy.name, conn->port, &addr);
1663 if(rc == CURLRESOLV_PENDING)
1664 rc = Curl_wait_for_resolv(conn, &addr);
1667 (unsigned short)conn->port; /* we connect to the proxy's port */
1671 /* normal, direct, ftp connection */
1672 rc = Curl_resolv(conn, newhostp, newport, &addr);
1673 if(rc == CURLRESOLV_PENDING)
1674 rc = Curl_wait_for_resolv(conn, &addr);
1677 failf(data, "Can't resolve new host %s:%d", newhostp, newport);
1678 return CURLE_FTP_CANT_GET_HOST;
1680 connectport = newport; /* we connect to the remote port */
1683 result = Curl_connecthost(conn,
1686 &conn->sock[SECONDARYSOCKET],
1690 Curl_resolv_unlock(data, addr); /* we're done using this address */
1696 * When this is used from the multi interface, this might've returned with
1697 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
1698 * connect to connect and we should not be "hanging" here waiting.
1701 if(data->set.verbose)
1702 /* this just dumps information about this second connection */
1703 ftp_pasv_verbose(conn, conninfo, newhostp, connectport);
1705 if(conn->bits.tunnel_proxy) {
1706 /* We want "seamless" FTP operations through HTTP proxy tunnel */
1707 result = Curl_ConnectHTTPProxyTunnel(conn, SECONDARYSOCKET,
1709 if(CURLE_OK != result)
1717 * Curl_ftp_nextconnect()
1719 * This function shall be called when the second FTP connection has been
1720 * established and is confirmed connected.
1723 CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
1725 struct SessionHandle *data=conn->data;
1726 char *buf = data->state.buffer; /* this is our buffer */
1729 int ftpcode; /* for ftp status */
1731 /* the ftp struct is already inited in Curl_ftp_connect() */
1732 struct FTP *ftp = conn->proto.ftp;
1733 curl_off_t *bytecountp = ftp->bytecountp;
1735 if(data->set.upload) {
1737 /* Set type to binary (unless specified ASCII) */
1738 result = ftp_transfertype(conn, data->set.ftp_ascii);
1742 /* Send any PREQUOTE strings after transfer type is set? (Wesley Laxton)*/
1743 if(data->set.prequote) {
1744 if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
1748 if(conn->resume_from) {
1749 /* we're about to continue the uploading of a file */
1750 /* 1. get already existing file's size. We use the SIZE
1751 command for this which may not exist in the server!
1752 The SIZE command is not in RFC959. */
1754 /* 2. This used to set REST. But since we can do append, we
1755 don't another ftp command. We just skip the source file
1756 offset and then we APPEND the rest on the file instead */
1758 /* 3. pass file-size number of bytes in the source file */
1759 /* 4. lower the infilesize counter */
1760 /* => transfer as usual */
1762 if(conn->resume_from < 0 ) {
1763 /* we could've got a specified offset from the command line,
1764 but now we know we didn't */
1765 curl_off_t gottensize;
1767 if(CURLE_OK != ftp_getsize(conn, ftp->file, &gottensize)) {
1768 failf(data, "Couldn't get remote file size");
1769 return CURLE_FTP_COULDNT_GET_SIZE;
1771 conn->resume_from = gottensize;
1774 if(conn->resume_from) {
1775 /* do we still game? */
1776 curl_off_t passed=0;
1777 /* enable append instead */
1778 data->set.ftp_append = 1;
1780 /* Now, let's read off the proper amount of bytes from the
1781 input. If we knew it was a proper file we could've just
1782 fseek()ed but we only have a stream here */
1784 curl_off_t readthisamountnow = (conn->resume_from - passed);
1785 curl_off_t actuallyread;
1787 if(readthisamountnow > BUFSIZE)
1788 readthisamountnow = BUFSIZE;
1791 conn->fread(data->state.buffer, 1, (size_t)readthisamountnow,
1794 passed += actuallyread;
1795 if(actuallyread != readthisamountnow) {
1796 failf(data, "Could only read %" FORMAT_OFF_T
1797 " bytes from the input", passed);
1798 return CURLE_FTP_COULDNT_USE_REST;
1801 while(passed != conn->resume_from);
1803 /* now, decrease the size of the read */
1804 if(data->set.infilesize>0) {
1805 data->set.infilesize -= conn->resume_from;
1807 if(data->set.infilesize <= 0) {
1808 infof(data, "File already completely uploaded\n");
1810 /* no data to transfer */
1811 result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1813 /* Set no_transfer so that we won't get any error in
1814 * Curl_ftp_done() because we didn't transfer anything! */
1815 ftp->no_transfer = TRUE;
1820 /* we've passed, proceed as normal */
1824 /* Send everything on data->state.in to the socket */
1825 if(data->set.ftp_append) {
1826 /* we append onto the file instead of rewriting it */
1827 FTPSENDF(conn, "APPE %s", ftp->file);
1830 FTPSENDF(conn, "STOR %s", ftp->file);
1833 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1838 failf(data, "Failed FTP upload:%s", buf+3);
1839 /* oops, we never close the sockets! */
1840 return CURLE_FTP_COULDNT_STOR_FILE;
1843 if(data->set.ftp_use_port) {
1844 /* PORT means we are now awaiting the server to connect to us. */
1845 result = AllowServerConnect(conn);
1850 if(conn->ssl[SECONDARYSOCKET].use) {
1851 /* since we only have a plaintext TCP connection here, we must now
1853 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
1854 result = Curl_SSLConnect(conn, SECONDARYSOCKET);
1861 /* When we know we're uploading a specified file, we can get the file
1862 size prior to the actual upload. */
1864 Curl_pgrsSetUploadSize(data, data->set.infilesize);
1866 result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
1867 SECONDARYSOCKET, bytecountp);
1872 else if(!conn->bits.no_body) {
1873 /* Retrieve file or directory */
1875 curl_off_t downloadsize=-1;
1877 if(conn->bits.use_range && conn->range) {
1878 curl_off_t from, to;
1879 curl_off_t totalsize=-1;
1883 from=curlx_strtoofft(conn->range, &ptr, 0);
1884 while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-')))
1886 to=curlx_strtoofft(ptr, &ptr2, 0);
1888 /* we didn't get any digit */
1891 if((-1 == to) && (from>=0)) {
1893 conn->resume_from = from;
1894 infof(data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n", from);
1899 conn->maxdownload = -from;
1900 conn->resume_from = from;
1901 infof(data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n", totalsize);
1905 totalsize = to-from;
1906 conn->maxdownload = totalsize+1; /* include the last mentioned byte */
1907 conn->resume_from = from;
1908 infof(data, "FTP RANGE from %" FORMAT_OFF_T
1909 " getting %" FORMAT_OFF_T " bytes\n", from, conn->maxdownload);
1911 infof(data, "range-download from %" FORMAT_OFF_T
1912 " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
1913 from, to, conn->maxdownload);
1914 ftp->dont_check = TRUE; /* dont check for successful transfer */
1917 if((data->set.ftp_list_only) || !ftp->file) {
1918 /* The specified path ends with a slash, and therefore we think this
1919 is a directory that is requested, use LIST. But before that we
1920 need to set ASCII transfer mode. */
1923 /* Set type to ASCII */
1924 result = ftp_transfertype(conn, TRUE /* ASCII enforced */);
1928 /* if this output is to be machine-parsed, the NLST command will be
1929 better used since the LIST command output is not specified or
1930 standard in any way */
1932 FTPSENDF(conn, "%s",
1933 data->set.customrequest?data->set.customrequest:
1934 (data->set.ftp_list_only?"NLST":"LIST"));
1937 curl_off_t foundsize;
1939 /* Set type to binary (unless specified ASCII) */
1940 result = ftp_transfertype(conn, data->set.ftp_ascii);
1944 /* Send any PREQUOTE strings after transfer type is set? */
1945 if(data->set.prequote) {
1946 if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
1950 /* Attempt to get the size, it'll be useful in some cases: for resumed
1951 downloads and when talking to servers that don't give away the size
1952 in the RETR response line. */
1953 result = ftp_getsize(conn, ftp->file, &foundsize);
1954 if(CURLE_OK == result) {
1955 if (data->set.max_filesize && foundsize > data->set.max_filesize) {
1956 failf(data, "Maximum file size exceeded");
1957 return CURLE_FILESIZE_EXCEEDED;
1959 downloadsize = foundsize;
1962 if(conn->resume_from) {
1964 /* Daniel: (August 4, 1999)
1966 * We start with trying to use the SIZE command to figure out the size
1967 * of the file we're gonna get. If we can get the size, this is by far
1968 * the best way to know if we're trying to resume beyond the EOF.
1970 * Daniel, November 28, 2001. We *always* get the size on downloads
1971 * now, so it is done before this even when not doing resumes. I saved
1972 * the comment above for nostalgical reasons! ;-)
1974 if(CURLE_OK != result) {
1975 infof(data, "ftp server doesn't support SIZE\n");
1976 /* We couldn't get the size and therefore we can't know if there
1977 really is a part of the file left to get, although the server
1978 will just close the connection when we start the connection so it
1979 won't cause us any harm, just not make us exit as nicely. */
1982 /* We got a file size report, so we check that there actually is a
1983 part of the file left to get, or else we go home. */
1984 if(conn->resume_from< 0) {
1985 /* We're supposed to download the last abs(from) bytes */
1986 if(foundsize < -conn->resume_from) {
1987 failf(data, "Offset (%" FORMAT_OFF_T
1988 ") was beyond file size (%" FORMAT_OFF_T ")",
1989 conn->resume_from, foundsize);
1990 return CURLE_FTP_BAD_DOWNLOAD_RESUME;
1992 /* convert to size to download */
1993 downloadsize = -conn->resume_from;
1994 /* download from where? */
1995 conn->resume_from = foundsize - downloadsize;
1998 if(foundsize < conn->resume_from) {
1999 failf(data, "Offset (%" FORMAT_OFF_T
2000 ") was beyond file size (%" FORMAT_OFF_T ")",
2001 conn->resume_from, foundsize);
2002 return CURLE_FTP_BAD_DOWNLOAD_RESUME;
2004 /* Now store the number of bytes we are expected to download */
2005 downloadsize = foundsize-conn->resume_from;
2009 if (downloadsize == 0) {
2010 /* no data to transfer */
2011 result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2012 infof(data, "File already completely downloaded\n");
2014 /* Set no_transfer so that we won't get any error in Curl_ftp_done()
2015 * because we didn't transfer the any file */
2016 ftp->no_transfer = TRUE;
2020 /* Set resume file transfer offset */
2021 infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
2025 FTPSENDF(conn, "REST %" FORMAT_OFF_T, conn->resume_from);
2027 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2031 if(ftpcode != 350) {
2032 failf(data, "Couldn't use REST: %s", buf+4);
2033 return CURLE_FTP_COULDNT_USE_REST;
2037 FTPSENDF(conn, "RETR %s", ftp->file);
2040 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2044 if((ftpcode == 150) || (ftpcode == 125)) {
2048 150 Opening BINARY mode data connection for /etc/passwd (2241
2049 bytes). (ok, the file is being transfered)
2052 150 Opening ASCII mode data connection for /bin/ls
2055 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2058 150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes).
2061 125 Data connection already open; Transfer starting. */
2063 curl_off_t size=-1; /* default unknown size */
2067 * It appears that there are FTP-servers that return size 0 for files
2068 * when SIZE is used on the file while being in BINARY mode. To work
2069 * around that (stupid) behavior, we attempt to parse the RETR response
2070 * even if the SIZE returned size zero.
2072 * Debugging help from Salvatore Sorrentino on February 26, 2003.
2076 !data->set.ftp_ascii &&
2077 (downloadsize < 1)) {
2079 * It seems directory listings either don't show the size or very
2080 * often uses size 0 anyway. ASCII transfers may very well turn out
2081 * that the transfered amount of data is not the same as this line
2082 * tells, why using this number in those cases only confuses us.
2084 * Example D above makes this parsing a little tricky */
2086 bytes=strstr(buf, " bytes");
2089 /* this is a hint there is size information in there! ;-) */
2091 /* scan for the parenthesis and break there */
2094 /* if only skip digits, or else we're in deep trouble */
2095 if(!isdigit((int)*bytes)) {
2099 /* one more estep backwards */
2102 /* only if we have nothing but digits: */
2104 /* get the number! */
2105 size = curlx_strtoofft(bytes, NULL, 0);
2110 else if(downloadsize > -1)
2111 size = downloadsize;
2113 if(data->set.ftp_use_port) {
2114 result = AllowServerConnect(conn);
2119 if(conn->ssl[SECONDARYSOCKET].use) {
2120 /* since we only have a plaintext TCP connection here, we must now
2122 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
2123 result = Curl_SSLConnect(conn, SECONDARYSOCKET);
2128 if(size > conn->maxdownload && conn->maxdownload > 0)
2129 size = conn->size = conn->maxdownload;
2131 infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
2134 result=Curl_Transfer(conn, SECONDARYSOCKET, size, FALSE,
2136 -1, NULL); /* no upload here */
2141 if(dirlist && (ftpcode == 450)) {
2142 /* simply no matching files */
2143 ftp->no_transfer = TRUE; /* don't think we should download anything */
2146 failf(data, "%s", buf+4);
2147 return CURLE_FTP_COULDNT_RETR_FILE;
2152 /* end of transfer */
2157 /***********************************************************************
2161 * This is the actual DO function for FTP. Get a file/directory according to
2162 * the options previously setup.
2166 CURLcode ftp_perform(struct connectdata *conn,
2167 bool *connected) /* for the TCP connect status after
2170 /* this is FTP and no proxy */
2171 CURLcode result=CURLE_OK;
2172 struct SessionHandle *data=conn->data;
2173 char *buf = data->state.buffer; /* this is our buffer */
2175 /* the ftp struct is already inited in Curl_ftp_connect() */
2176 struct FTP *ftp = conn->proto.ftp;
2178 /* Send any QUOTE strings? */
2179 if(data->set.quote) {
2180 if ((result = ftp_sendquote(conn, data->set.quote)) != CURLE_OK)
2184 /* This is a re-used connection. Since we change directory to where the
2185 transfer is taking place, we must now get back to the original dir
2186 where we ended up after login: */
2187 if (conn->bits.reuse && ftp->entrypath) {
2188 if ((result = ftp_cwd_and_mkd(conn, ftp->entrypath)) != CURLE_OK)
2193 int i; /* counter for loop */
2194 for (i=0; i < ftp->dirdepth; i++) {
2195 /* RFC 1738 says empty components should be respected too, but
2196 that is plain stupid since CWD can't be used with an empty argument */
2197 if ((result = ftp_cwd_and_mkd(conn, ftp->dirs[i])) != CURLE_OK)
2202 /* Requested time of file or time-depended transfer? */
2203 if((data->set.get_filetime || data->set.timecondition) &&
2205 result = ftp_getfiletime(conn, ftp->file);
2208 case CURLE_FTP_COULDNT_RETR_FILE:
2210 if(data->set.timecondition) {
2211 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2212 switch(data->set.timecondition) {
2213 case CURL_TIMECOND_IFMODSINCE:
2215 if(data->info.filetime < data->set.timevalue) {
2216 infof(data, "The requested document is not new enough\n");
2217 ftp->no_transfer = TRUE; /* mark this to not transfer data */
2221 case CURL_TIMECOND_IFUNMODSINCE:
2222 if(data->info.filetime > data->set.timevalue) {
2223 infof(data, "The requested document is not old enough\n");
2224 ftp->no_transfer = TRUE; /* mark this to not transfer data */
2231 infof(data, "Skipping time comparison\n");
2240 /* If we have selected NOBODY and HEADER, it means that we only want file
2241 information. Which in FTP can't be much more than the file size and
2243 if(conn->bits.no_body && data->set.include_header && ftp->file) {
2244 /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
2245 may not support it! It is however the only way we have to get a file's
2247 curl_off_t filesize;
2251 ftp->no_transfer = TRUE; /* this means no actual transfer is made */
2253 /* Some servers return different sizes for different modes, and thus we
2254 must set the proper type before we check the size */
2255 result = ftp_transfertype(conn, data->set.ftp_ascii);
2259 /* failing to get size is not a serious error */
2260 result = ftp_getsize(conn, ftp->file, &filesize);
2262 if(CURLE_OK == result) {
2263 sprintf(buf, "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
2264 result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
2269 /* Determine if server can respond to REST command and therefore
2270 whether it can do a range */
2271 FTPSENDF(conn, "REST 0", NULL);
2272 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2274 if ((CURLE_OK == result) && (ftpcode == 350)) {
2275 result = Curl_client_write(data, CLIENTWRITE_BOTH,
2276 (char *)"Accept-ranges: bytes\r\n", 0);
2281 /* If we asked for a time of the file and we actually got one as
2282 well, we "emulate" a HTTP-style header in our output. */
2284 #ifdef HAVE_STRFTIME
2285 if(data->set.get_filetime && (data->info.filetime>=0) ) {
2287 time_t clock = (time_t)data->info.filetime;
2288 #ifdef HAVE_GMTIME_R
2290 tm = (struct tm *)gmtime_r(&clock, &buffer);
2292 tm = gmtime(&clock);
2294 /* format: "Tue, 15 Nov 1994 12:45:26" */
2295 strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S GMT\r\n",
2297 result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
2306 if(conn->bits.no_body)
2307 /* doesn't really transfer any data */
2308 ftp->no_transfer = TRUE;
2309 /* Get us a second connection up and connected */
2310 else if(data->set.ftp_use_port) {
2311 /* We have chosen to use the PORT command */
2312 result = ftp_use_port(conn);
2313 if(CURLE_OK == result) {
2314 /* we have the data connection ready */
2315 infof(data, "Ordered connect of the data stream with PORT!\n");
2316 *connected = TRUE; /* mark us "still connected" */
2320 /* We have chosen (this is default) to use the PASV command */
2321 result = ftp_use_pasv(conn, connected);
2322 if(CURLE_OK == result && *connected)
2323 infof(data, "Connected the data stream with PASV!\n");
2329 /***********************************************************************
2333 * This function is registered as 'curl_do' function. It decodes the path
2334 * parts etc as a wrapper to the actual DO function (ftp_perform).
2336 * The input argument is already checked for validity.
2338 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
2339 * Curl_ftp_done() function without finding any major problem.
2341 CURLcode Curl_ftp(struct connectdata *conn)
2343 CURLcode retcode=CURLE_OK;
2345 struct SessionHandle *data = conn->data;
2348 char *slash_pos; /* position of the first '/' char in curpos */
2349 char *cur_pos=conn->path; /* current position in ppath. point at the begin
2350 of next path component */
2352 /* the ftp struct is already inited in ftp_connect() */
2353 ftp = conn->proto.ftp;
2354 ftp->ctl_valid = FALSE;
2355 conn->size = -1; /* make sure this is unknown at this point */
2357 Curl_pgrsSetUploadCounter(data, 0);
2358 Curl_pgrsSetDownloadCounter(data, 0);
2359 Curl_pgrsSetUploadSize(data, 0);
2360 Curl_pgrsSetDownloadSize(data, 0);
2363 ftp->diralloc = 5; /* default dir depth to allocate */
2364 ftp->dirs = (char **)malloc(ftp->diralloc * sizeof(ftp->dirs[0]));
2366 return CURLE_OUT_OF_MEMORY;
2367 ftp->dirs[0] = NULL; /* to start with */
2369 /* parse the URL path into separate path components */
2370 while((slash_pos=strchr(cur_pos, '/'))) {
2371 /* 1 or 0 to indicate absolute directory */
2372 bool absolute_dir = (cur_pos - conn->path > 0) && (ftp->dirdepth == 0);
2374 /* seek out the next path component */
2375 if (slash_pos-cur_pos) {
2376 /* we skip empty path components, like "x//y" since the FTP command CWD
2377 requires a parameter and a non-existant parameter a) doesn't work on
2378 many servers and b) has no effect on the others. */
2379 ftp->dirs[ftp->dirdepth] = curl_unescape(cur_pos - absolute_dir,
2380 slash_pos - cur_pos +
2383 if (!ftp->dirs[ftp->dirdepth]) { /* run out of memory ... */
2384 failf(data, "no memory");
2386 return CURLE_OUT_OF_MEMORY;
2390 cur_pos = slash_pos + 1; /* jump to the rest of the string */
2395 cur_pos = slash_pos + 1; /* jump to the rest of the string */
2396 if(++ftp->dirdepth >= ftp->diralloc) {
2399 ftp->diralloc *= 2; /* double the size each time */
2400 bigger = realloc(ftp->dirs, ftp->diralloc * sizeof(ftp->dirs[0]));
2403 return CURLE_OUT_OF_MEMORY;
2405 ftp->dirs = (char **)bigger;
2410 ftp->file = cur_pos; /* the rest is the file name */
2413 ftp->file = curl_unescape(ftp->file, 0);
2414 if(NULL == ftp->file) {
2416 failf(data, "no memory");
2417 return CURLE_OUT_OF_MEMORY;
2421 ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL
2424 retcode = ftp_perform(conn, &connected);
2426 if(CURLE_OK == retcode) {
2428 retcode = Curl_ftp_nextconnect(conn);
2430 if(retcode && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
2431 /* Failure detected, close the second socket if it was created already */
2432 sclose(conn->sock[SECONDARYSOCKET]);
2433 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
2436 if(ftp->no_transfer)
2437 /* no data to transfer */
2438 retcode=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2440 /* since we didn't connect now, we want do_more to get called */
2441 conn->bits.do_more = TRUE;
2446 ftp->ctl_valid = TRUE; /* seems good */
2451 /***********************************************************************
2455 * Sends the formated string as a ftp command to a ftp server
2457 * NOTE: we build the command in a fixed-length buffer, which sets length
2458 * restrictions on the command!
2460 CURLcode Curl_ftpsendf(struct connectdata *conn,
2461 const char *fmt, ...)
2463 ssize_t bytes_written;
2467 CURLcode res = CURLE_OK;
2471 vsnprintf(s, 250, fmt, ap);
2474 strcat(s, "\r\n"); /* append a trailing CRLF */
2477 write_len = strlen(s);
2480 res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
2486 if(conn->data->set.verbose)
2487 Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, bytes_written);
2489 if(bytes_written != (ssize_t)write_len) {
2490 write_len -= bytes_written;
2491 sptr += bytes_written;
2500 /***********************************************************************
2504 * This should be called before calling sclose() on an ftp control connection
2505 * (not data connections). We should then wait for the response from the
2506 * server before returning. The calling code should then try to close the
2510 static CURLcode ftp_quit(struct connectdata *conn)
2514 CURLcode ret = CURLE_OK;
2516 if(conn->proto.ftp->ctl_valid) {
2517 ret = Curl_ftpsendf(conn, "%s", "QUIT");
2519 ret = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2525 /***********************************************************************
2527 * Curl_ftp_disconnect()
2529 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
2532 CURLcode Curl_ftp_disconnect(struct connectdata *conn)
2534 struct FTP *ftp= conn->proto.ftp;
2536 /* We cannot send quit unconditionally. If this connection is stale or
2537 bad in any way, sending quit and waiting around here will make the
2538 disconnect wait in vain and cause more problems than we need to.
2540 ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
2541 will try to send the QUIT command, otherwise it will just return.
2544 /* The FTP session may or may not have been allocated/setup at this point! */
2546 (void)ftp_quit(conn); /* ignore errors on the QUIT */
2549 free(ftp->entrypath);
2559 /***********************************************************************
2563 * Makes a directory on the FTP server.
2567 static CURLcode ftp_mkd(struct connectdata *conn, char *path)
2569 CURLcode result=CURLE_OK;
2570 int ftpcode; /* for ftp status */
2573 /* Create a directory on the remote server */
2574 FTPSENDF(conn, "MKD %s", path);
2576 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2583 infof( conn->data , "Created remote directory %s\n" , path );
2586 failf(conn->data, "Permission denied to make directory %s", path);
2587 result = CURLE_FTP_ACCESS_DENIED;
2590 failf(conn->data, "unrecognized MKD response: %d", ftpcode );
2591 result = CURLE_FTP_ACCESS_DENIED;
2597 /***********************************************************************
2601 * Send 'CWD' to the remote server to Change Working Directory. It is the ftp
2602 * version of the unix 'cd' command. This function is only called from the
2603 * ftp_cwd_and_mkd() function these days.
2605 * This function does NOT call failf().
2608 CURLcode ftp_cwd(struct connectdata *conn, char *path)
2614 FTPSENDF(conn, "CWD %s", path);
2615 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2617 /* According to RFC959, CWD is supposed to return 250 on success, but
2618 there seem to be non-compliant FTP servers out there that return 200,
2619 so we accept any '2xy' code here. */
2620 if (ftpcode/100 != 2)
2621 result = CURLE_FTP_ACCESS_DENIED;
2627 /***********************************************************************
2631 * Change to the given directory. If the directory is not present, and we
2632 * have been told to allow it, then create the directory and cd to it.
2635 static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path)
2639 result = ftp_cwd(conn, path);
2641 if(conn->data->set.ftp_create_missing_dirs) {
2642 result = ftp_mkd(conn, path);
2644 /* ftp_mkd() calls failf() itself */
2646 result = ftp_cwd(conn, path);
2649 failf(conn->data, "Couldn't cd to %s", path);
2654 #endif /* CURL_DISABLE_FTP */