doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ftp.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
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.
13  *
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.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * $Id: ftp.c,v 1.240 2004/03/17 12:46:45 bagder Exp $
22  ***************************************************************************/
23 
24 #include "setup.h"
25 
26 #ifndef CURL_DISABLE_FTP
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <ctype.h>
32 #include <errno.h>
33 
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37 #ifdef HAVE_SYS_SELECT_H
38 #include <sys/select.h>
39 #endif
40 
41 #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
42 
43 #else /* some kind of unix */
44 #ifdef HAVE_SYS_SOCKET_H
45 #include <sys/socket.h>
46 #endif
47 #include <sys/types.h>
48 #ifdef HAVE_NETINET_IN_H
49 #include <netinet/in.h>
50 #endif
51 #ifdef HAVE_ARPA_INET_H
52 #include <arpa/inet.h>
53 #endif
54 #include <sys/utsname.h>
55 #ifdef HAVE_NETDB_H
56 #include <netdb.h>
57 #endif
58 #ifdef VMS
59 #include <in.h>
60 #include <inet.h>
61 #endif
62 #endif
63 
64 #if defined(WIN32) && defined(__GNUC__) || defined(__MINGW32__)
65 #include <errno.h>
66 #endif
67 
68 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
69 #undef in_addr_t
70 #define in_addr_t unsigned long
71 #endif
72 
73 #include <curl/curl.h>
74 #include "urldata.h"
75 #include "sendf.h"
76 
77 #include "if2ip.h"
78 #include "hostip.h"
79 #include "progress.h"
80 #include "transfer.h"
81 #include "escape.h"
82 #include "http.h" /* for HTTP proxy tunnel stuff */
83 #include "ftp.h"
84 
85 #ifdef HAVE_KRB4
86 #include "security.h"
87 #include "krb4.h"
88 #endif
89 
90 #include "strtoofft.h"
91 #include "strequal.h"
92 #include "ssluse.h"
93 #include "connect.h"
94 
95 #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
96 #include "inet_ntoa_r.h"
97 #endif
98 
99 #define _MPRINTF_REPLACE /* use our functions only */
100 #include <curl/mprintf.h>
101 
102 /* The last #include file should be: */
103 #ifdef CURLDEBUG
104 #include "memdebug.h"
105 #endif
106 
107 /* Local API functions */
108 static CURLcode ftp_sendquote(struct connectdata *conn,
109  struct curl_slist *quote);
110 static CURLcode ftp_cwd(struct connectdata *conn, char *path);
111 static CURLcode ftp_mkd(struct connectdata *conn, char *path);
112 static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path);
113 
114 /* easy-to-use macro: */
115 #define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z))) return result
116 
117 static void freedirs(struct FTP *ftp)
118 {
119  int i;
120  for (i=0; ftp->dirs[i]; i++){
121  free(ftp->dirs[i]);
122  ftp->dirs[i]=NULL;
123  }
124 }
125 
126 /***********************************************************************
127  *
128  * AllowServerConnect()
129  *
130  * When we've issue the PORT command, we have told the server to connect
131  * to us. This function will sit and wait here until the server has
132  * connected.
133  *
134  */
135 static CURLcode AllowServerConnect(struct connectdata *conn)
136 {
137  fd_set rdset;
138  struct timeval dt;
139  struct SessionHandle *data = conn->data;
140  curl_socket_t sock = conn->sock[SECONDARYSOCKET];
141  struct timeval now = Curl_tvnow();
142  long timespent = Curl_tvdiff(Curl_tvnow(), now)/1000;
143  long timeout = data->set.connecttimeout?data->set.connecttimeout:
144  (data->set.timeout?data->set.timeout: 0);
145 
146  FD_ZERO(&rdset);
147 
148  FD_SET(sock, &rdset);
149 
150  if(timeout) {
151  timeout -= timespent;
152  if(timeout<=0) {
153  failf(data, "Timed out before server could connect to us");
155  }
156  }
157 
158  /* we give the server 60 seconds to connect to us, or a custom timeout */
159  dt.tv_sec = (int)(timeout?timeout:60);
160  dt.tv_usec = 0;
161 
162  switch (select(sock+1, &rdset, NULL, NULL, &dt)) {
163  case -1: /* error */
164  /* let's die here */
165  failf(data, "Error while waiting for server connect");
166  return CURLE_FTP_PORT_FAILED;
167  case 0: /* timeout */
168  /* let's die here */
169  failf(data, "Timeout while waiting for server connect");
170  return CURLE_FTP_PORT_FAILED;
171  default:
172  /* we have received data here */
173  {
175  size_t size = sizeof(struct sockaddr_in);
176  struct sockaddr_in add;
177 
178  getsockname(sock, (struct sockaddr *) &add, (socklen_t *)&size);
179  s=accept(sock, (struct sockaddr *) &add, (socklen_t *)&size);
180 
181  sclose(sock); /* close the first socket */
182 
183  if (CURL_SOCKET_BAD == s) {
184  /* DIE! */
185  failf(data, "Error accept()ing server connect");
186  return CURLE_FTP_PORT_FAILED;
187  }
188  infof(data, "Connection accepted from server\n");
189 
190  conn->sock[SECONDARYSOCKET] = s;
191  Curl_nonblock(s, TRUE); /* enable non-blocking */
192  }
193  break;
194  }
195 
196  return CURLE_OK;
197 }
198 
199 
200 /* --- parse FTP server responses --- */
201 
202 /*
203  * Curl_GetFTPResponse() is supposed to be invoked after each command sent to
204  * a remote FTP server. This function will wait and read all lines of the
205  * response and extract the relevant return code for the invoking function.
206  */
207 
208 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
209  struct connectdata *conn,
210  int *ftpcode) /* return the ftp-code */
211 {
212  /* Brand new implementation.
213  * We cannot read just one byte per read() and then go back to select()
214  * as it seems that the OpenSSL read() stuff doesn't grok that properly.
215  *
216  * Alas, read as much as possible, split up into lines, use the ending
217  * line in a response or continue reading. */
218 
219  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
220  int perline; /* count bytes per line */
221  bool keepon=TRUE;
222  ssize_t gotbytes;
223  char *ptr;
224  long timeout; /* timeout in seconds */
225  struct timeval interval;
226  fd_set rkeepfd;
227  fd_set readfd;
228  struct SessionHandle *data = conn->data;
229  char *line_start;
230  int code=0; /* default ftp "error code" to return */
231  char *buf = data->state.buffer;
233  struct FTP *ftp = conn->proto.ftp;
234  struct timeval now = Curl_tvnow();
235 
236  if (ftpcode)
237  *ftpcode = 0; /* 0 for errors */
238 
239  FD_ZERO (&readfd); /* clear it */
240  FD_SET (sockfd, &readfd); /* read socket */
241 
242  /* get this in a backup variable to be able to restore it on each lap in the
243  select() loop */
244  rkeepfd = readfd;
245 
246  ptr=buf;
247  line_start = buf;
248 
249  *nreadp=0;
250  perline=0;
251  keepon=TRUE;
252 
253  while((*nreadp<BUFSIZE) && (keepon && !result)) {
254  /* check and reset timeout value every lap */
255  if(data->set.ftp_response_timeout )
256  /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine
257  remaining time. Also, use "now" as opposed to "conn->now"
258  because ftp_response_timeout is only supposed to govern
259  the response for any given ftp response, not for the time
260  from connect to the given ftp response. */
261  timeout = data->set.ftp_response_timeout - /* timeout time */
262  Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
263  else if(data->set.timeout)
264  /* if timeout is requested, find out how much remaining time we have */
265  timeout = data->set.timeout - /* timeout time */
266  Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
267  else
268  /* Even without a requested timeout, we only wait response_time
269  seconds for the full response to arrive before we bail out */
270  timeout = ftp->response_time -
271  Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
272 
273  if(timeout <=0 ) {
274  failf(data, "FTP response timeout");
275  return CURLE_OPERATION_TIMEDOUT; /* already too little time */
276  }
277 
278  if(!ftp->cache) {
279  readfd = rkeepfd; /* set every lap */
280  interval.tv_sec = 1; /* use 1 second timeout intervals */
281  interval.tv_usec = 0;
282 
283  switch (select (sockfd+1, &readfd, NULL, NULL, &interval)) {
284  case -1: /* select() error, stop reading */
285  result = CURLE_RECV_ERROR;
286  failf(data, "FTP response aborted due to select() error: %d", errno);
287  break;
288  case 0: /* timeout */
289  if(Curl_pgrsUpdate(conn))
291  continue; /* just continue in our loop for the timeout duration */
292 
293  default:
294  break;
295  }
296  }
297  if(CURLE_OK == result) {
298  /*
299  * This code previously didn't use the kerberos sec_read() code
300  * to read, but when we use Curl_read() it may do so. Do confirm
301  * that this is still ok and then remove this comment!
302  */
303  if(ftp->cache) {
304  /* we had data in the "cache", copy that instead of doing an actual
305  * read
306  *
307  * Dave Meyer, December 2003:
308  * ftp->cache_size is cast to int here. This should be safe,
309  * because it would have been populated with something of size
310  * int to begin with, even though its datatype may be larger
311  * than an int.
312  */
313  memcpy(ptr, ftp->cache, (int)ftp->cache_size);
314  gotbytes = (int)ftp->cache_size;
315  free(ftp->cache); /* free the cache */
316  ftp->cache = NULL; /* clear the pointer */
317  ftp->cache_size = 0; /* zero the size just in case */
318  }
319  else {
320  int res = Curl_read(conn, sockfd, ptr, BUFSIZE-*nreadp, &gotbytes);
321  if(res < 0)
322  /* EWOULDBLOCK */
323  continue; /* go looping again */
324 
325  if(CURLE_OK != res)
326  keepon = FALSE;
327  }
328 
329  if(!keepon)
330  ;
331  else if(gotbytes <= 0) {
332  keepon = FALSE;
333  result = CURLE_RECV_ERROR;
334  failf(data, "FTP response reading failed");
335  }
336  else {
337  /* we got a whole chunk of data, which can be anything from one
338  * byte to a set of lines and possible just a piece of the last
339  * line */
340  int i;
341 
342  *nreadp += gotbytes;
343  for(i = 0; i < gotbytes; ptr++, i++) {
344  perline++;
345  if(*ptr=='\n') {
346  /* a newline is CRLF in ftp-talk, so the CR is ignored as
347  the line isn't really terminated until the LF comes */
348 
349  /* output debug output if that is requested */
350  if(data->set.verbose)
351  Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline);
352 
353  /*
354  * We pass all response-lines to the callback function registered
355  * for "headers". The response lines can be seen as a kind of
356  * headers.
357  */
358  result = Curl_client_write(data, CLIENTWRITE_HEADER,
359  line_start, perline);
360  if(result)
361  return result;
362 
363 #define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
364  isdigit((int)line[2]) && (' ' == line[3]))
365 
366  if(perline>3 && lastline(line_start)) {
367  /* This is the end of the last line, copy the last
368  * line to the start of the buffer and zero terminate,
369  * for old times sake (and krb4)! */
370  char *meow;
371  int n;
372  for(meow=line_start, n=0; meow<ptr; meow++, n++)
373  buf[n] = *meow;
374  *meow=0; /* zero terminate */
375  keepon=FALSE;
376  line_start = ptr+1; /* advance pointer */
377  i++; /* skip this before getting out */
378  break;
379  }
380  perline=0; /* line starts over here */
381  line_start = ptr+1;
382  }
383  }
384  if(!keepon && (i != gotbytes)) {
385  /* We found the end of the response lines, but we didn't parse the
386  full chunk of data we have read from the server. We therefore
387  need to store the rest of the data to be checked on the next
388  invoke as it may actually contain another end of response
389  already! Cleverly figured out by Eric Lavigne in December
390  2001. */
391  ftp->cache_size = gotbytes - i;
392  ftp->cache = (char *)malloc((int)ftp->cache_size);
393  if(ftp->cache)
394  memcpy(ftp->cache, line_start, (int)ftp->cache_size);
395  else
396  return CURLE_OUT_OF_MEMORY;
397  }
398  } /* there was data */
399  } /* if(no error) */
400  } /* while there's buffer left and loop is requested */
401 
402  if(!result)
403  code = atoi(buf);
404 
405 #ifdef HAVE_KRB4
406  /* handle the security-oriented responses 6xx ***/
407  /* FIXME: some errorchecking perhaps... ***/
408  switch(code) {
409  case 631:
410  Curl_sec_read_msg(conn, buf, prot_safe);
411  break;
412  case 632:
413  Curl_sec_read_msg(conn, buf, prot_private);
414  break;
415  case 633:
416  Curl_sec_read_msg(conn, buf, prot_confidential);
417  break;
418  default:
419  /* normal ftp stuff we pass through! */
420  break;
421  }
422 #endif
423 
424  if(ftpcode)
425  *ftpcode=code; /* return the initial number like this */
426 
427  /* store the latest code for later retrieval */
428  conn->data->info.httpcode=code;
429 
430  return result;
431 }
432 
433 static const char *ftpauth[]= {
434  "SSL", "TLS", NULL
435 };
436 
437 /*
438  * Curl_ftp_connect() should do everything that is to be considered a part of
439  * the connection phase.
440  */
442 {
443  /* this is FTP and no proxy */
444  ssize_t nread;
445  struct SessionHandle *data=conn->data;
446  char *buf = data->state.buffer; /* this is our buffer */
447  struct FTP *ftp;
449  int ftpcode, try;
450 
451  ftp = (struct FTP *)malloc(sizeof(struct FTP));
452  if(!ftp)
453  return CURLE_OUT_OF_MEMORY;
454 
455  memset(ftp, 0, sizeof(struct FTP));
456  conn->proto.ftp = ftp;
457 
458  /* We always support persistant connections on ftp */
459  conn->bits.close = FALSE;
460 
461  /* get some initial data into the ftp struct */
462  ftp->bytecountp = &conn->bytecount;
463 
464  /* no need to duplicate them, this connectdata struct won't change */
465  ftp->user = conn->user;
466  ftp->passwd = conn->passwd;
467  ftp->response_time = 3600; /* set default response time-out */
468 
469  if (data->set.tunnel_thru_httpproxy) {
470  /* We want "seamless" FTP operations through HTTP proxy tunnel */
472  conn->hostname, conn->remote_port);
473  if(CURLE_OK != result)
474  return result;
475  }
476 
477  if(conn->protocol & PROT_FTPS) {
478  /* FTPS is simply ftp with SSL for the control channel */
479  /* now, perform the SSL initialization for this socket */
480  result = Curl_SSLConnect(conn, FIRSTSOCKET);
481  if(result)
482  return result;
483  }
484 
485  /* The first thing we do is wait for the "220*" line: */
486  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
487  if(result)
488  return result;
489 
490  if(ftpcode != 220) {
491  failf(data, "This doesn't seem like a nice ftp-server response");
493  }
494 
495 #ifdef HAVE_KRB4
496  /* if not anonymous login, try a secure login */
497  if(data->set.krb4) {
498 
499  /* request data protection level (default is 'clear') */
500  Curl_sec_request_prot(conn, "private");
501 
502  /* We set private first as default, in case the line below fails to
503  set a valid level */
504  Curl_sec_request_prot(conn, data->set.krb4_level);
505 
506  if(Curl_sec_login(conn) != 0)
507  infof(data, "Logging in with password in cleartext!\n");
508  else
509  infof(data, "Authentication successful\n");
510  }
511 #endif
512 
513  if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
514  /* we don't have a SSL/TLS connection, try a FTPS connection now */
515 
516  for (try = 0; ftpauth[try]; try++) {
517 
518  FTPSENDF(conn, "AUTH %s", ftpauth[try]);
519 
520  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
521 
522  if(result)
523  return result;
524 
525  /* RFC2228 (page 5) says:
526  *
527  * If the server is willing to accept the named security mechanism, and
528  * does not require any security data, it must respond with reply code
529  * 234/334.
530  */
531 
532  if((ftpcode == 234) || (ftpcode == 334)) {
533  result = Curl_SSLConnect(conn, FIRSTSOCKET);
534  if(result)
535  return result;
536  conn->protocol |= PROT_FTPS;
537  conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
538  break;
539  }
540  }
541  }
542 
543  /* send USER */
544  FTPSENDF(conn, "USER %s", ftp->user?ftp->user:"");
545 
546  /* wait for feedback */
547  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
548  if(result)
549  return result;
550 
551  if(ftpcode == 530) {
552  /* 530 User ... access denied
553  (the server denies to log the specified user) */
554  failf(data, "Access denied: %s", &buf[4]);
556  }
557  else if(ftpcode == 331) {
558  /* 331 Password required for ...
559  (the server requires to send the user's password too) */
560  FTPSENDF(conn, "PASS %s", ftp->passwd?ftp->passwd:"");
561  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
562  if(result)
563  return result;
564 
565  if(ftpcode == 530) {
566  /* 530 Login incorrect.
567  (the username and/or the password are incorrect) */
568  failf(data, "the username and/or the password are incorrect");
570  }
571  else if(ftpcode == 230) {
572  /* 230 User ... logged in.
573  (user successfully logged in) */
574 
575  infof(data, "We have successfully logged in\n");
576  }
577  else {
578  failf(data, "Odd return code after PASS");
580  }
581  }
582  else if(buf[0] == '2') {
583  /* 230 User ... logged in.
584  (the user logged in without password) */
585  infof(data, "We have successfully logged in\n");
586  if (conn->ssl[FIRSTSOCKET].use) {
587 #ifdef HAVE_KRB4
588  /* we are logged in (with Kerberos)
589  * now set the requested protection level
590  */
591  if(conn->sec_complete)
593 
594  /* we may need to issue a KAUTH here to have access to the files
595  * do it if user supplied a password
596  */
597  if(conn->passwd && *conn->passwd) {
598  result = Curl_krb_kauth(conn);
599  if(result)
600  return result;
601  }
602 #endif
603  }
604  }
605  else {
606  failf(data, "Odd return code after USER");
608  }
609 
610  if(conn->ssl[FIRSTSOCKET].use) {
611  /* PBSZ = PROTECTION BUFFER SIZE.
612 
613  The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
614 
615  Specifically, the PROT command MUST be preceded by a PBSZ command
616  and a PBSZ command MUST be preceded by a successful security data
617  exchange (the TLS negotiation in this case)
618 
619  ... (and on page 8):
620 
621  Thus the PBSZ command must still be issued, but must have a parameter
622  of '0' to indicate that no buffering is taking place and the data
623  connection should not be encapsulated.
624  */
625  FTPSENDF(conn, "PBSZ %d", 0);
626  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
627  if(result)
628  return result;
629 
630  /* For TLS, the data connection can have one of two security levels.
631 
632  1)Clear (requested by 'PROT C')
633 
634  2)Private (requested by 'PROT P')
635  */
636  if(!conn->ssl[SECONDARYSOCKET].use) {
637  FTPSENDF(conn, "PROT %c", 'P');
638  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
639  if(result)
640  return result;
641 
642  if(ftpcode == 200)
643  /* We have enabled SSL for the data connection! */
644  conn->ssl[SECONDARYSOCKET].use = TRUE;
645 
646  /* FTP servers typically responds with 500 if they decide to reject
647  our 'P' request */
648  }
649  }
650 
651  /* send PWD to discover our entry point */
652  FTPSENDF(conn, "PWD", NULL);
653 
654  /* wait for feedback */
655  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
656  if(result)
657  return result;
658 
659  if(ftpcode == 257) {
660  char *dir = (char *)malloc(nread+1);
661  char *store=dir;
662  char *ptr=&buf[4]; /* start on the first letter */
663 
664  if(!dir)
665  return CURLE_OUT_OF_MEMORY;
666 
667  /* Reply format is like
668  257<space>"<directory-name>"<space><commentary> and the RFC959 says
669 
670  The directory name can contain any character; embedded double-quotes
671  should be escaped by double-quotes (the "quote-doubling" convention).
672  */
673  if('\"' == *ptr) {
674  /* it started good */
675  ptr++;
676  while(ptr && *ptr) {
677  if('\"' == *ptr) {
678  if('\"' == ptr[1]) {
679  /* "quote-doubling" */
680  *store = ptr[1];
681  ptr++;
682  }
683  else {
684  /* end of path */
685  *store = '\0'; /* zero terminate */
686  break; /* get out of this loop */
687  }
688  }
689  else
690  *store = *ptr;
691  store++;
692  ptr++;
693  }
694  ftp->entrypath =dir; /* remember this */
695  infof(data, "Entry path is '%s'\n", ftp->entrypath);
696  }
697  else {
698  /* couldn't get the path */
699  free(dir);
700  infof(data, "Failed to figure out path\n");
701  }
702 
703  }
704  else {
705  /* We couldn't read the PWD response! */
706  }
707 
708  return CURLE_OK;
709 }
710 
711 /***********************************************************************
712  *
713  * Curl_ftp_done()
714  *
715  * The DONE function. This does what needs to be done after a single DO has
716  * performed.
717  *
718  * Input argument is already checked for validity.
719  */
721 {
722  struct SessionHandle *data = conn->data;
723  struct FTP *ftp = conn->proto.ftp;
724  ssize_t nread;
725  int ftpcode;
727 
728  /* free the dir tree parts */
729  freedirs(ftp);
730 
731  if(ftp->file) {
732  free(ftp->file);
733  ftp->file = NULL;
734  }
735 
736  if(data->set.upload) {
737  if((-1 != data->set.infilesize) &&
738  (data->set.infilesize != *ftp->bytecountp) &&
739  !data->set.crlf) {
740  failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
741  " out of %" FORMAT_OFF_T " bytes)",
742  *ftp->bytecountp, data->set.infilesize);
743  conn->bits.close = TRUE; /* close this connection since we don't
744  know what state this error leaves us in */
745  return CURLE_PARTIAL_FILE;
746  }
747  }
748  else {
749  if((-1 != conn->size) && (conn->size != *ftp->bytecountp) &&
750  (conn->maxdownload != *ftp->bytecountp)) {
751  failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
752  *ftp->bytecountp);
753  conn->bits.close = TRUE; /* close this connection since we don't
754  know what state this error leaves us in */
755  return CURLE_PARTIAL_FILE;
756  }
757  else if(!ftp->dont_check &&
758  !*ftp->bytecountp &&
759  (conn->size>0)) {
760  /* We consider this an error, but there's no true FTP error received
761  why we need to continue to "read out" the server response too.
762  We don't want to leave a "waiting" server reply if we'll get told
763  to make a second request on this same connection! */
764  failf(data, "No data was received!");
766  }
767  }
768 
769 #ifdef HAVE_KRB4
771 #endif
772  /* shut down the socket to inform the server we're done */
773  sclose(conn->sock[SECONDARYSOCKET]);
775 
776  if(!ftp->no_transfer) {
777  /* Let's see what the server says about the transfer we just performed,
778  but lower the timeout as sometimes this connection has died while
779  the data has been transfered. This happens when doing through NATs
780  etc that abandon old silent connections.
781  */
782  ftp->response_time = 60; /* give it only a minute for now */
783 
784  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
785 
786  ftp->response_time = 3600; /* set this back to one hour waits */
787 
788  if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
789  failf(data, "control connection looks dead");
790  return result;
791  }
792 
793  if(result)
794  return result;
795 
796  if(!ftp->dont_check) {
797  /* 226 Transfer complete, 250 Requested file action okay, completed. */
798  if((ftpcode != 226) && (ftpcode != 250)) {
799  failf(data, "server did not report OK, got %d", ftpcode);
800  return CURLE_FTP_WRITE_ERROR;
801  }
802  }
803  }
804 
805  /* clear these for next connection */
806  ftp->no_transfer = FALSE;
807  ftp->dont_check = FALSE;
808 
809  /* Send any post-transfer QUOTE strings? */
810  if(!result && data->set.postquote)
811  result = ftp_sendquote(conn, data->set.postquote);
812 
813  return result;
814 }
815 
816 /***********************************************************************
817  *
818  * ftp_sendquote()
819  *
820  * Where a 'quote' means a list of custom commands to send to the server.
821  * The quote list is passed as an argument.
822  */
823 
824 static
825 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
826 {
827  struct curl_slist *item;
828  ssize_t nread;
829  int ftpcode;
831 
832  item = quote;
833  while (item) {
834  if (item->data) {
835  FTPSENDF(conn, "%s", item->data);
836 
837  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
838  if (result)
839  return result;
840 
841  if (ftpcode >= 400) {
842  failf(conn->data, "QUOT string not accepted: %s", item->data);
843  return CURLE_FTP_QUOTE_ERROR;
844  }
845  }
846 
847  item = item->next;
848  }
849 
850  return CURLE_OK;
851 }
852 
853 /***********************************************************************
854  *
855  * ftp_getfiletime()
856  *
857  * Get the timestamp of the given file.
858  */
859 static
860 CURLcode ftp_getfiletime(struct connectdata *conn, char *file)
861 {
862  CURLcode result=CURLE_OK;
863  int ftpcode; /* for ftp status */
864  ssize_t nread;
865  char *buf = conn->data->state.buffer;
866 
867  /* we have requested to get the modified-time of the file, this is yet
868  again a grey area as the MDTM is not kosher RFC959 */
869  FTPSENDF(conn, "MDTM %s", file);
870 
871  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
872  if(result)
873  return result;
874 
875  switch(ftpcode) {
876  case 213:
877  {
878  /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
879  last .sss part is optional and means fractions of a second */
880  int year, month, day, hour, minute, second;
881  if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
882  &year, &month, &day, &hour, &minute, &second)) {
883  /* we have a time, reformat it */
884  time_t secs=time(NULL);
885  sprintf(buf, "%04d%02d%02d %02d:%02d:%02d GMT",
886  year, month, day, hour, minute, second);
887  /* now, convert this into a time() value: */
888  conn->data->info.filetime = curl_getdate(buf, &secs);
889  }
890  }
891  break;
892  default:
893  infof(conn->data, "unsupported MDTM reply format\n");
894  break;
895  case 550: /* "No such file or directory" */
896  failf(conn->data, "Given file does not exist");
898  break;
899  }
900  return result;
901 }
902 
903 /***********************************************************************
904  *
905  * ftp_transfertype()
906  *
907  * Set transfer type. We only deal with ASCII or BINARY so this function
908  * sets one of them.
909  */
910 static CURLcode ftp_transfertype(struct connectdata *conn,
911  bool ascii)
912 {
913  struct SessionHandle *data = conn->data;
914  int ftpcode;
915  ssize_t nread;
917 
918  FTPSENDF(conn, "TYPE %s", ascii?"A":"I");
919 
920  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
921  if(result)
922  return result;
923 
924  if(ftpcode != 200) {
925  failf(data, "Couldn't set %s mode",
926  ascii?"ASCII":"binary");
928  }
929 
930  return CURLE_OK;
931 }
932 
933 /***********************************************************************
934  *
935  * ftp_getsize()
936  *
937  * Returns the file size (in bytes) of the given remote file.
938  */
939 
940 static
941 CURLcode ftp_getsize(struct connectdata *conn, char *file,
942  curl_off_t *size)
943 {
944  struct SessionHandle *data = conn->data;
945  int ftpcode;
946  ssize_t nread;
947  char *buf=data->state.buffer;
949 
950  FTPSENDF(conn, "SIZE %s", file);
951  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
952  if(result)
953  return result;
954 
955  if(ftpcode == 213) {
956  /* get the size from the ascii string: */
957  *size = strtoofft(buf+4, NULL, 0);
958  }
959  else
961 
962  return CURLE_OK;
963 }
964 
965 /***************************************************************************
966  *
967  * ftp_pasv_verbose()
968  *
969  * This function only outputs some informationals about this second connection
970  * when we've issued a PASV command before and thus we have connected to a
971  * possibly new IP address.
972  *
973  */
974 static void
975 ftp_pasv_verbose(struct connectdata *conn,
977  char *newhost, /* ascii version */
978  int port)
979 {
980 #ifndef ENABLE_IPV6
981  /*****************************************************************
982  *
983  * IPv4-only code section
984  */
985 
986  struct in_addr in;
987  struct hostent * answer;
988 
989 #ifdef HAVE_INET_NTOA_R
990  char ntoa_buf[64];
991 #endif
992  /* The array size trick below is to make this a large chunk of memory
993  suitably 8-byte aligned on 64-bit platforms. This was thoughtfully
994  suggested by Philip Gladstone. */
995  long bigbuf[9000 / sizeof(long)];
996 
997 #if defined(HAVE_INET_ADDR)
999 # if defined(HAVE_GETHOSTBYADDR_R)
1000  int h_errnop;
1001 # endif
1002  char *hostent_buf = (char *)bigbuf; /* get a char * to the buffer */
1003 
1004  address = inet_addr(newhost);
1005 # ifdef HAVE_GETHOSTBYADDR_R
1006 
1007 # ifdef HAVE_GETHOSTBYADDR_R_5
1008  /* AIX, Digital Unix (OSF1, Tru64) style:
1009  extern int gethostbyaddr_r(char *addr, size_t len, int type,
1010  struct hostent *htent, struct hostent_data *ht_data); */
1011 
1012  /* Fred Noz helped me try this out, now it at least compiles! */
1013 
1014  /* Bjorn Reese (November 28 2001):
1015  The Tru64 man page on gethostbyaddr_r() says that
1016  the hostent struct must be filled with zeroes before the call to
1017  gethostbyaddr_r().
1018 
1019  ... as must be struct hostent_data Craig Markwardt 19 Sep 2002. */
1020 
1021  memset(hostent_buf, 0, sizeof(struct hostent)+sizeof(struct hostent_data));
1022 
1023  if(gethostbyaddr_r((char *) &address,
1024  sizeof(address), AF_INET,
1025  (struct hostent *)hostent_buf,
1026  (struct hostent_data *)(hostent_buf + sizeof(*answer))))
1027  answer=NULL;
1028  else
1029  answer=(struct hostent *)hostent_buf;
1030 
1031 # endif
1032 # ifdef HAVE_GETHOSTBYADDR_R_7
1033  /* Solaris and IRIX */
1034  answer = gethostbyaddr_r((char *) &address, sizeof(address), AF_INET,
1035  (struct hostent *)bigbuf,
1036  hostent_buf + sizeof(*answer),
1037  sizeof(bigbuf) - sizeof(*answer),
1038  &h_errnop);
1039 # endif
1040 # ifdef HAVE_GETHOSTBYADDR_R_8
1041  /* Linux style */
1042  if(gethostbyaddr_r((char *) &address, sizeof(address), AF_INET,
1043  (struct hostent *)hostent_buf,
1044  hostent_buf + sizeof(*answer),
1045  sizeof(bigbuf) - sizeof(*answer),
1046  &answer,
1047  &h_errnop))
1048  answer=NULL; /* error */
1049 # endif
1050 
1051 # else
1052  (void)hostent_buf; /* avoid compiler warning */
1053  answer = gethostbyaddr((char *) &address, sizeof(address), AF_INET);
1054 # endif
1055 #else
1056  answer = NULL;
1057 #endif
1058  (void) memcpy(&in.s_addr, addr, sizeof (Curl_ipconnect));
1059  infof(conn->data, "Connecting to %s (%s) port %u\n",
1060  answer?answer->h_name:newhost,
1061 #if defined(HAVE_INET_NTOA_R)
1062  inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)),
1063 #else
1064  inet_ntoa(in),
1065 #endif
1066  port);
1067 
1068 #else
1069  /*****************************************************************
1070  *
1071  * IPv6-only code section
1072  */
1073  char hbuf[NI_MAXHOST]; /* ~1KB */
1074  char nbuf[NI_MAXHOST]; /* ~1KB */
1075  char sbuf[NI_MAXSERV]; /* around 32 */
1076 #ifdef NI_WITHSCOPEID
1077  const int niflags = NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID;
1078 #else
1079  const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
1080 #endif
1081  (void)port; /* prevent compiler warning */
1082  if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
1083  nbuf, sizeof(nbuf), sbuf, sizeof(sbuf), niflags)) {
1084  snprintf(nbuf, sizeof(nbuf), "?");
1085  snprintf(sbuf, sizeof(sbuf), "?");
1086  }
1087 
1088  if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
1089  hbuf, sizeof(hbuf), NULL, 0, 0)) {
1090  infof(conn->data, "Connecting to %s (%s) port %s\n", nbuf, newhost, sbuf);
1091  }
1092  else {
1093  infof(conn->data, "Connecting to %s (%s) port %s\n", hbuf, nbuf, sbuf);
1094  }
1095 #endif
1096 }
1097 
1098 /***********************************************************************
1099  *
1100  * ftp_use_port()
1101  *
1102  * Send the proper PORT command. PORT is the ftp client's way of telling the
1103  * server that *WE* open a port that we listen on an awaits the server to
1104  * connect to. This is the opposite of PASV.
1105  */
1106 
1107 static
1108 CURLcode ftp_use_port(struct connectdata *conn)
1109 {
1110  struct SessionHandle *data=conn->data;
1111  curl_socket_t portsock= CURL_SOCKET_BAD;
1112  ssize_t nread;
1113  int ftpcode; /* receive FTP response codes in this */
1114  CURLcode result;
1115 
1116 #ifdef ENABLE_IPV6
1117  /******************************************************************
1118  *
1119  * Here's a piece of IPv6-specific code coming up
1120  *
1121  */
1122 
1123  struct addrinfo hints, *res, *ai;
1124  struct sockaddr_storage ss;
1125  socklen_t sslen;
1126  char hbuf[NI_MAXHOST];
1127 
1128  struct sockaddr *sa=(struct sockaddr *)&ss;
1129 #ifdef NI_WITHSCOPEID
1130 #define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID
1131 #else
1132 #define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV
1133 #endif
1134  unsigned char *ap;
1135  unsigned char *pp;
1136  char portmsgbuf[4096], tmp[4096];
1137 
1138  const char *mode[] = { "EPRT", "LPRT", "PORT", NULL };
1139  char **modep;
1140  int rc;
1141 
1142  /*
1143  * we should use Curl_if2ip? given pickiness of recent ftpd,
1144  * I believe we should use the same address as the control connection.
1145  */
1146  sslen = sizeof(ss);
1147  rc = getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)&ss, &sslen);
1148  if(rc < 0) {
1149  failf(data, "getsockname() returned %d\n", rc);
1150  return CURLE_FTP_PORT_FAILED;
1151  }
1152 
1153  rc = getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, 0,
1154  NIFLAGS);
1155  if(rc) {
1156  failf(data, "getnameinfo() returned %d\n", rc);
1157  return CURLE_FTP_PORT_FAILED;
1158  }
1159 
1160  memset(&hints, 0, sizeof(hints));
1161  hints.ai_family = sa->sa_family;
1162  /*hints.ai_family = ss.ss_family;
1163  this way can be used if sockaddr_storage is properly defined, as glibc
1164  2.1.X doesn't do*/
1165  hints.ai_socktype = SOCK_STREAM;
1166  hints.ai_flags = AI_PASSIVE;
1167 
1168  rc = getaddrinfo(hbuf, NULL, &hints, &res);
1169  if(rc) {
1170  failf(data, "getaddrinfo() returned %d\n", rc);
1171  return CURLE_FTP_PORT_FAILED;
1172  }
1173 
1174  portsock = CURL_SOCKET_BAD;
1175  for (ai = res; ai; ai = ai->ai_next) {
1176  /*
1177  * Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype):
1178  */
1179  if (ai->ai_socktype == 0)
1180  ai->ai_socktype = hints.ai_socktype;
1181 
1182  portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1183  if (portsock == CURL_SOCKET_BAD)
1184  continue;
1185 
1186  if (bind(portsock, ai->ai_addr, ai->ai_addrlen) < 0) {
1187  sclose(portsock);
1188  portsock = CURL_SOCKET_BAD;
1189  continue;
1190  }
1191 
1192  if (listen(portsock, 1) < 0) {
1193  sclose(portsock);
1194  portsock = CURL_SOCKET_BAD;
1195  continue;
1196  }
1197 
1198  break;
1199  }
1200  freeaddrinfo(res);
1201  if (portsock == CURL_SOCKET_BAD) {
1202  failf(data, "%s", strerror(errno));
1203  return CURLE_FTP_PORT_FAILED;
1204  }
1205 
1206  sslen = sizeof(ss);
1207  if (getsockname(portsock, sa, &sslen) < 0) {
1208  failf(data, "%s", strerror(errno));
1209  return CURLE_FTP_PORT_FAILED;
1210  }
1211 
1212  for (modep = (char **)(data->set.ftp_use_eprt?&mode[0]:&mode[2]);
1213  modep && *modep; modep++) {
1214  int lprtaf, eprtaf;
1215  int alen=0, plen=0;
1216 
1217  switch (sa->sa_family) {
1218  case AF_INET:
1219  ap = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_addr;
1220  alen = sizeof(((struct sockaddr_in *)&ss)->sin_addr);
1221  pp = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_port;
1222  plen = sizeof(((struct sockaddr_in *)&ss)->sin_port);
1223  lprtaf = 4;
1224  eprtaf = 1;
1225  break;
1226  case AF_INET6:
1227  ap = (unsigned char *)&((struct sockaddr_in6 *)&ss)->sin6_addr;
1228  alen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_addr);
1229  pp = (unsigned char *)&((struct sockaddr_in6 *)&ss)->sin6_port;
1230  plen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_port);
1231  lprtaf = 6;
1232  eprtaf = 2;
1233  break;
1234  default:
1235  ap = pp = NULL;
1236  lprtaf = eprtaf = -1;
1237  break;
1238  }
1239 
1240  if (strcmp(*modep, "EPRT") == 0) {
1241  if (eprtaf < 0)
1242  continue;
1243  if (getnameinfo((struct sockaddr *)&ss, sslen,
1244  portmsgbuf, sizeof(portmsgbuf), tmp, sizeof(tmp),
1245  NIFLAGS))
1246  continue;
1247 
1248  /* do not transmit IPv6 scope identifier to the wire */
1249  if (sa->sa_family == AF_INET6) {
1250  char *q = strchr(portmsgbuf, '%');
1251  if (q)
1252  *q = '\0';
1253  }
1254 
1255  result = Curl_ftpsendf(conn, "%s |%d|%s|%s|", *modep, eprtaf,
1256  portmsgbuf, tmp);
1257  if(result)
1258  return result;
1259  } else if (strcmp(*modep, "LPRT") == 0 ||
1260  strcmp(*modep, "PORT") == 0) {
1261  int i;
1262 
1263  if (strcmp(*modep, "LPRT") == 0 && lprtaf < 0)
1264  continue;
1265  if (strcmp(*modep, "PORT") == 0 && sa->sa_family != AF_INET)
1266  continue;
1267 
1268  portmsgbuf[0] = '\0';
1269  if (strcmp(*modep, "LPRT") == 0) {
1270  snprintf(tmp, sizeof(tmp), "%d,%d", lprtaf, alen);
1271  if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1272  sizeof(portmsgbuf)) {
1273  continue;
1274  }
1275  }
1276 
1277  for (i = 0; i < alen; i++) {
1278  if (portmsgbuf[0])
1279  snprintf(tmp, sizeof(tmp), ",%u", ap[i]);
1280  else
1281  snprintf(tmp, sizeof(tmp), "%u", ap[i]);
1282 
1283  if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1284  sizeof(portmsgbuf)) {
1285  continue;
1286  }
1287  }
1288 
1289  if (strcmp(*modep, "LPRT") == 0) {
1290  snprintf(tmp, sizeof(tmp), ",%d", plen);
1291 
1292  if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf))
1293  continue;
1294  }
1295 
1296  for (i = 0; i < plen; i++) {
1297  snprintf(tmp, sizeof(tmp), ",%u", pp[i]);
1298 
1299  if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1300  sizeof(portmsgbuf)) {
1301  continue;
1302  }
1303  }
1304 
1305  result = Curl_ftpsendf(conn, "%s %s", *modep, portmsgbuf);
1306  if(result)
1307  return result;
1308  }
1309 
1310  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1311  if(result)
1312  return result;
1313 
1314  if (ftpcode != 200) {
1315  continue;
1316  }
1317  else
1318  break;
1319  }
1320 
1321  if (!*modep) {
1322  sclose(portsock);
1323  failf(data, "PORT command attempts failed");
1324  return CURLE_FTP_PORT_FAILED;
1325  }
1326  /* we set the secondary socket variable to this for now, it
1327  is only so that the cleanup function will close it in case
1328  we fail before the true secondary stuff is made */
1329  conn->sock[SECONDARYSOCKET] = portsock;
1330 
1331 #else
1332  /******************************************************************
1333  *
1334  * Here's a piece of IPv4-specific code coming up
1335  *
1336  */
1337  struct sockaddr_in sa;
1338  struct Curl_dns_entry *h=NULL;
1339  unsigned short porttouse;
1340  char myhost[256] = "";
1341  bool sa_filled_in = FALSE;
1342 
1343  if(data->set.ftpport) {
1344  in_addr_t in;
1345  int rc;
1346 
1347  /* First check if the given name is an IP address */
1348  in=inet_addr(data->set.ftpport);
1349 
1350  if((in == CURL_INADDR_NONE) &&
1351  Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) {
1352  rc = Curl_resolv(conn, myhost, 0, &h);
1353  if(rc == 1)
1354  rc = Curl_wait_for_resolv(conn, &h);
1355  }
1356  else {
1357  size_t len = strlen(data->set.ftpport);
1358  if(len>1) {
1359  rc = Curl_resolv(conn, data->set.ftpport, 0, &h);
1360  if(rc == 1)
1361  rc = Curl_wait_for_resolv(conn, &h);
1362  }
1363  if(h)
1364  strcpy(myhost, data->set.ftpport); /* buffer overflow risk */
1365  }
1366  }
1367  if(! *myhost) {
1368  /* pick a suitable default here */
1369 
1370  socklen_t sslen;
1371 
1372  sslen = sizeof(sa);
1373  if (getsockname(conn->sock[FIRSTSOCKET],
1374  (struct sockaddr *)&sa, &sslen) < 0) {
1375  failf(data, "getsockname() failed");
1376  return CURLE_FTP_PORT_FAILED;
1377  }
1378 
1379  sa_filled_in = TRUE; /* the sa struct is filled in */
1380  }
1381 
1382  if(h)
1383  /* when we return from here, we can forget about this */
1384  Curl_resolv_unlock(data, h);
1385 
1386  if ( h || sa_filled_in) {
1387  if( (portsock = socket(AF_INET, SOCK_STREAM, 0)) != CURL_SOCKET_BAD ) {
1388  int size;
1389 
1390  /* we set the secondary socket variable to this for now, it
1391  is only so that the cleanup function will close it in case
1392  we fail before the true secondary stuff is made */
1393  conn->sock[SECONDARYSOCKET] = portsock;
1394 
1395  if(!sa_filled_in) {
1396  memset((char *)&sa, 0, sizeof(sa));
1397  memcpy((char *)&sa.sin_addr,
1398  h->addr->h_addr,
1399  h->addr->h_length);
1400  sa.sin_family = AF_INET;
1401  sa.sin_addr.s_addr = INADDR_ANY;
1402  }
1403 
1404  sa.sin_port = 0;
1405  size = sizeof(sa);
1406 
1407  if(bind(portsock, (struct sockaddr *)&sa, size) >= 0) {
1408  /* we succeeded to bind */
1409  struct sockaddr_in add;
1410  socklen_t socksize = sizeof(add);
1411 
1412  if(getsockname(portsock, (struct sockaddr *) &add,
1413  &socksize)<0) {
1414  failf(data, "getsockname() failed");
1415  return CURLE_FTP_PORT_FAILED;
1416  }
1417  porttouse = ntohs(add.sin_port);
1418 
1419  if ( listen(portsock, 1) < 0 ) {
1420  failf(data, "listen(2) failed on socket");
1421  return CURLE_FTP_PORT_FAILED;
1422  }
1423  }
1424  else {
1425  failf(data, "bind(2) failed on socket");
1426  return CURLE_FTP_PORT_FAILED;
1427  }
1428  }
1429  else {
1430  failf(data, "socket(2) failed (%s)");
1431  return CURLE_FTP_PORT_FAILED;
1432  }
1433  }
1434  else {
1435  failf(data, "could't find my own IP address (%s)", myhost);
1436  return CURLE_FTP_PORT_FAILED;
1437  }
1438  {
1439 #ifdef HAVE_INET_NTOA_R
1440  char ntoa_buf[64];
1441 #endif
1442  struct in_addr in;
1443  unsigned short ip[5];
1444  (void) memcpy(&in.s_addr,
1445  h?*h->addr->h_addr_list:(char *)&sa.sin_addr.s_addr,
1446  sizeof (in.s_addr));
1447 
1448 #ifdef HAVE_INET_NTOA_R
1449  /* ignore the return code from inet_ntoa_r() as it is int or
1450  char * depending on system */
1451  inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf));
1452  sscanf( ntoa_buf, "%hu.%hu.%hu.%hu",
1453  &ip[0], &ip[1], &ip[2], &ip[3]);
1454 #else
1455  sscanf( inet_ntoa(in), "%hu.%hu.%hu.%hu",
1456  &ip[0], &ip[1], &ip[2], &ip[3]);
1457 #endif
1458  infof(data, "Telling server to connect to %d.%d.%d.%d:%d\n",
1459  ip[0], ip[1], ip[2], ip[3], porttouse);
1460 
1461  result=Curl_ftpsendf(conn, "PORT %d,%d,%d,%d,%d,%d",
1462  ip[0], ip[1], ip[2], ip[3],
1463  porttouse >> 8,
1464  porttouse & 255);
1465  if(result)
1466  return result;
1467  }
1468 
1469  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1470  if(result)
1471  return result;
1472 
1473  if(ftpcode != 200) {
1474  failf(data, "Server does not grok PORT, try without it!");
1475  return CURLE_FTP_PORT_FAILED;
1476  }
1477 #endif /* end of ipv4-specific code */
1478 
1479  return CURLE_OK;
1480 }
1481 
1482 /***********************************************************************
1483  *
1484  * ftp_use_pasv()
1485  *
1486  * Send the PASV command. PASV is the ftp client's way of asking the server to
1487  * open a second port that we can connect to (for the data transfer). This is
1488  * the opposite of PORT.
1489  */
1490 
1491 static
1492 CURLcode ftp_use_pasv(struct connectdata *conn,
1493  bool *connected)
1494 {
1495  struct SessionHandle *data = conn->data;
1496  ssize_t nread;
1497  char *buf = data->state.buffer; /* this is our buffer */
1498  int ftpcode; /* receive FTP response codes in this */
1499  CURLcode result;
1500  struct Curl_dns_entry *addr=NULL;
1501  Curl_ipconnect *conninfo;
1502  int rc;
1503 
1504  /*
1505  Here's the excecutive summary on what to do:
1506 
1507  PASV is RFC959, expect:
1508  227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1509 
1510  LPSV is RFC1639, expect:
1511  228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1512 
1513  EPSV is RFC2428, expect:
1514  229 Entering Extended Passive Mode (|||port|)
1515 
1516  */
1517 
1518  const char *mode[] = { "EPSV", "PASV", NULL };
1519  int results[] = { 229, 227, 0 };
1520  int modeoff;
1521  unsigned short connectport; /* the local port connect() should use! */
1522  unsigned short newport=0; /* remote port, not necessary the local one */
1523 
1524  /* newhost must be able to hold a full IP-style address in ASCII, which
1525  in the IPv6 case means 5*8-1 = 39 letters */
1526  char newhost[48];
1527  char *newhostp=NULL;
1528 
1529  for (modeoff = (data->set.ftp_use_epsv?0:1);
1530  mode[modeoff]; modeoff++) {
1531  result = Curl_ftpsendf(conn, "%s", mode[modeoff]);
1532  if(result)
1533  return result;
1534  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1535  if(result)
1536  return result;
1537  if (ftpcode == results[modeoff])
1538  break;
1539  }
1540 
1541  if (!mode[modeoff]) {
1542  failf(data, "Odd return code after PASV");
1544  }
1545  else if (227 == results[modeoff]) {
1546  int ip[4];
1547  int port[2];
1548  char *str=buf;
1549 
1550  /*
1551  * New 227-parser June 3rd 1999.
1552  * It now scans for a sequence of six comma-separated numbers and
1553  * will take them as IP+port indicators.
1554  *
1555  * Found reply-strings include:
1556  * "227 Entering Passive Mode (127,0,0,1,4,51)"
1557  * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1558  * "227 Entering passive mode. 127,0,0,1,4,51"
1559  */
1560 
1561  while(*str) {
1562  if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1563  &ip[0], &ip[1], &ip[2], &ip[3],
1564  &port[0], &port[1]))
1565  break;
1566  str++;
1567  }
1568 
1569  if(!*str) {
1570  failf(data, "Couldn't interpret this 227-reply: %s", buf);
1572  }
1573 
1574  sprintf(newhost, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1575  newhostp = newhost;
1576  newport = (port[0]<<8) + port[1];
1577  }
1578  else if (229 == results[modeoff]) {
1579  char *ptr = strchr(buf, '(');
1580  if(ptr) {
1581  unsigned int num;
1582  char separator[4];
1583  ptr++;
1584  if(5 == sscanf(ptr, "%c%c%c%u%c",
1585  &separator[0],
1586  &separator[1],
1587  &separator[2],
1588  &num,
1589  &separator[3])) {
1590  char sep1 = separator[0];
1591  int i;
1592 
1593  /* The four separators should be identical, or else this is an oddly
1594  formatted reply and we bail out immediately. */
1595  for(i=1; i<4; i++) {
1596  if(separator[i] != sep1) {
1597  ptr=NULL; /* set to NULL to signal error */
1598  break;
1599  }
1600  }
1601  if(ptr) {
1602  newport = num;
1603 
1604  /* we should use the same host we already are connected to */
1605  newhostp = conn->name;
1606  }
1607  }
1608  else
1609  ptr=NULL;
1610  }
1611  if(!ptr) {
1612  failf(data, "Weirdly formatted EPSV reply");
1614  }
1615  }
1616  else
1617  return CURLE_FTP_CANT_RECONNECT;
1618 
1619  if(data->change.proxy && *data->change.proxy) {
1620  /*
1621  * This is a tunnel through a http proxy and we need to connect to the
1622  * proxy again here.
1623  *
1624  * We don't want to rely on a former host lookup that might've expired
1625  * now, instead we remake the lookup here and now!
1626  */
1627  rc = Curl_resolv(conn, conn->proxyhost, conn->port, &addr);
1628  if(rc == 1)
1629  rc = Curl_wait_for_resolv(conn, &addr);
1630 
1631  connectport =
1632  (unsigned short)conn->port; /* we connect to the proxy's port */
1633 
1634  }
1635  else {
1636  /* normal, direct, ftp connection */
1637  rc = Curl_resolv(conn, newhostp, newport, &addr);
1638  if(rc == 1)
1639  rc = Curl_wait_for_resolv(conn, &addr);
1640 
1641  if(!addr) {
1642  failf(data, "Can't resolve new host %s:%d", newhostp, newport);
1643  return CURLE_FTP_CANT_GET_HOST;
1644  }
1645  connectport = newport; /* we connect to the remote port */
1646  }
1647 
1648  result = Curl_connecthost(conn,
1649  addr,
1650  connectport,
1651  &conn->sock[SECONDARYSOCKET],
1652  &conninfo,
1653  connected);
1654 
1655  Curl_resolv_unlock(data, addr); /* we're done using this address */
1656 
1657  if(result)
1658  return result;
1659 
1660  /*
1661  * When this is used from the multi interface, this might've returned with
1662  * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
1663  * connect to connect and we should not be "hanging" here waiting.
1664  */
1665 
1666  if(data->set.verbose)
1667  /* this just dumps information about this second connection */
1668  ftp_pasv_verbose(conn, conninfo, newhostp, connectport);
1669 
1670  if(data->set.tunnel_thru_httpproxy) {
1671  /* We want "seamless" FTP operations through HTTP proxy tunnel */
1673  newhostp, newport);
1674  if(CURLE_OK != result)
1675  return result;
1676  }
1677 
1678  return CURLE_OK;
1679 }
1680 
1681 /*
1682  * Curl_ftp_nextconnect()
1683  *
1684  * This function shall be called when the second FTP connection has been
1685  * established and is confirmed connected.
1686  */
1687 
1689 {
1690  struct SessionHandle *data=conn->data;
1691  char *buf = data->state.buffer; /* this is our buffer */
1692  CURLcode result;
1693  ssize_t nread;
1694  int ftpcode; /* for ftp status */
1695 
1696  /* the ftp struct is already inited in Curl_ftp_connect() */
1697  struct FTP *ftp = conn->proto.ftp;
1699 
1700  if(data->set.upload) {
1701 
1702  /* Set type to binary (unless specified ASCII) */
1703  result = ftp_transfertype(conn, data->set.ftp_ascii);
1704  if(result)
1705  return result;
1706 
1707  /* Send any PREQUOTE strings after transfer type is set? (Wesley Laxton)*/
1708  if(data->set.prequote) {
1709  if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
1710  return result;
1711  }
1712 
1713  if(conn->resume_from) {
1714  /* we're about to continue the uploading of a file */
1715  /* 1. get already existing file's size. We use the SIZE
1716  command for this which may not exist in the server!
1717  The SIZE command is not in RFC959. */
1718 
1719  /* 2. This used to set REST. But since we can do append, we
1720  don't another ftp command. We just skip the source file
1721  offset and then we APPEND the rest on the file instead */
1722 
1723  /* 3. pass file-size number of bytes in the source file */
1724  /* 4. lower the infilesize counter */
1725  /* => transfer as usual */
1726 
1727  if(conn->resume_from < 0 ) {
1728  /* we could've got a specified offset from the command line,
1729  but now we know we didn't */
1730  curl_off_t gottensize;
1731 
1732  if(CURLE_OK != ftp_getsize(conn, ftp->file, &gottensize)) {
1733  failf(data, "Couldn't get remote file size");
1735  }
1736  conn->resume_from = gottensize;
1737  }
1738 
1739  if(conn->resume_from) {
1740  /* do we still game? */
1741  curl_off_t passed=0;
1742  /* enable append instead */
1743  data->set.ftp_append = 1;
1744 
1745  /* Now, let's read off the proper amount of bytes from the
1746  input. If we knew it was a proper file we could've just
1747  fseek()ed but we only have a stream here */
1748  do {
1749  curl_off_t readthisamountnow = (conn->resume_from - passed);
1750  curl_off_t actuallyread;
1751 
1752  if(readthisamountnow > BUFSIZE)
1753  readthisamountnow = BUFSIZE;
1754 
1755  actuallyread =
1756  conn->fread(data->state.buffer, 1, (size_t)readthisamountnow,
1757  conn->fread_in);
1758 
1759  passed += actuallyread;
1760  if(actuallyread != readthisamountnow) {
1761  failf(data, "Could only read %" FORMAT_OFF_T
1762  " bytes from the input", passed);
1764  }
1765  }
1766  while(passed != conn->resume_from);
1767 
1768  /* now, decrease the size of the read */
1769  if(data->set.infilesize>0) {
1770  data->set.infilesize -= conn->resume_from;
1771 
1772  if(data->set.infilesize <= 0) {
1773  infof(data, "File already completely uploaded\n");
1774 
1775  /* no data to transfer */
1776  result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1777 
1778  /* Set no_transfer so that we won't get any error in
1779  * Curl_ftp_done() because we didn't transfer anything! */
1780  ftp->no_transfer = TRUE;
1781 
1782  return CURLE_OK;
1783  }
1784  }
1785  /* we've passed, proceed as normal */
1786  }
1787  }
1788 
1789  /* Send everything on data->state.in to the socket */
1790  if(data->set.ftp_append) {
1791  /* we append onto the file instead of rewriting it */
1792  FTPSENDF(conn, "APPE %s", ftp->file);
1793  }
1794  else {
1795  FTPSENDF(conn, "STOR %s", ftp->file);
1796  }
1797 
1798  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1799  if(result)
1800  return result;
1801 
1802  if(ftpcode>=400) {
1803  failf(data, "Failed FTP upload:%s", buf+3);
1804  /* oops, we never close the sockets! */
1806  }
1807 
1808  if(data->set.ftp_use_port) {
1809  /* PORT means we are now awaiting the server to connect to us. */
1810  result = AllowServerConnect(conn);
1811  if( result )
1812  return result;
1813  }
1814 
1815  if(conn->ssl[SECONDARYSOCKET].use) {
1816  /* since we only have a plaintext TCP connection here, we must now
1817  do the TLS stuff */
1818  infof(data, "Doing the SSL/TLS handshake on the data stream\n");
1819  result = Curl_SSLConnect(conn, SECONDARYSOCKET);
1820  if(result)
1821  return result;
1822  }
1823 
1824  *bytecountp=0;
1825 
1826  /* When we know we're uploading a specified file, we can get the file
1827  size prior to the actual upload. */
1828 
1829  Curl_pgrsSetUploadSize(data, data->set.infilesize);
1830 
1831  result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
1832  SECONDARYSOCKET, bytecountp);
1833  if(result)
1834  return result;
1835 
1836  }
1837  else if(!data->set.no_body) {
1838  /* Retrieve file or directory */
1839  bool dirlist=FALSE;
1840  curl_off_t downloadsize=-1;
1841 
1842  if(conn->bits.use_range && conn->range) {
1843  curl_off_t from, to;
1844  curl_off_t totalsize=-1;
1845  char *ptr;
1846  char *ptr2;
1847 
1848  from=strtoofft(conn->range, &ptr, 0);
1849  while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-')))
1850  ptr++;
1851  to=strtoofft(ptr, &ptr2, 0);
1852  if(ptr == ptr2) {
1853  /* we didn't get any digit */
1854  to=-1;
1855  }
1856  if((-1 == to) && (from>=0)) {
1857  /* X - */
1858  conn->resume_from = from;
1859  infof(data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n", from);
1860  }
1861  else if(from < 0) {
1862  /* -Y */
1863  totalsize = -from;
1864  conn->maxdownload = -from;
1865  conn->resume_from = from;
1866  infof(data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n", totalsize);
1867  }
1868  else {
1869  /* X-Y */
1870  totalsize = to-from;
1871  conn->maxdownload = totalsize+1; /* include the last mentioned byte */
1872  conn->resume_from = from;
1873  infof(data, "FTP RANGE from %" FORMAT_OFF_T
1874  " getting %" FORMAT_OFF_T " bytes\n", from, conn->maxdownload);
1875  }
1876  infof(data, "range-download from %" FORMAT_OFF_T
1877  " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
1878  from, to, conn->maxdownload);
1879  ftp->dont_check = TRUE; /* dont check for successful transfer */
1880  }
1881 
1882  if((data->set.ftp_list_only) || !ftp->file) {
1883  /* The specified path ends with a slash, and therefore we think this
1884  is a directory that is requested, use LIST. But before that we
1885  need to set ASCII transfer mode. */
1886  dirlist = TRUE;
1887 
1888  /* Set type to ASCII */
1889  result = ftp_transfertype(conn, TRUE /* ASCII enforced */);
1890  if(result)
1891  return result;
1892 
1893  /* if this output is to be machine-parsed, the NLST command will be
1894  better used since the LIST command output is not specified or
1895  standard in any way */
1896 
1897  FTPSENDF(conn, "%s",
1898  data->set.customrequest?data->set.customrequest:
1899  (data->set.ftp_list_only?"NLST":"LIST"));
1900  }
1901  else {
1902  curl_off_t foundsize;
1903 
1904  /* Set type to binary (unless specified ASCII) */
1905  result = ftp_transfertype(conn, data->set.ftp_ascii);
1906  if(result)
1907  return result;
1908 
1909  /* Send any PREQUOTE strings after transfer type is set? */
1910  if(data->set.prequote) {
1911  if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
1912  return result;
1913  }
1914 
1915  /* Attempt to get the size, it'll be useful in some cases: for resumed
1916  downloads and when talking to servers that don't give away the size
1917  in the RETR response line. */
1918  result = ftp_getsize(conn, ftp->file, &foundsize);
1919  if(CURLE_OK == result) {
1920  if (data->set.max_filesize && foundsize > data->set.max_filesize) {
1921  failf(data, "Maximum file size exceeded");
1922  return CURLE_FILESIZE_EXCEEDED;
1923  }
1924  downloadsize = foundsize;
1925  }
1926 
1927  if(conn->resume_from) {
1928 
1929  /* Daniel: (August 4, 1999)
1930  *
1931  * We start with trying to use the SIZE command to figure out the size
1932  * of the file we're gonna get. If we can get the size, this is by far
1933  * the best way to know if we're trying to resume beyond the EOF.
1934  *
1935  * Daniel, November 28, 2001. We *always* get the size on downloads
1936  * now, so it is done before this even when not doing resumes. I saved
1937  * the comment above for nostalgical reasons! ;-)
1938  */
1939  if(CURLE_OK != result) {
1940  infof(data, "ftp server doesn't support SIZE\n");
1941  /* We couldn't get the size and therefore we can't know if there
1942  really is a part of the file left to get, although the server
1943  will just close the connection when we start the connection so it
1944  won't cause us any harm, just not make us exit as nicely. */
1945  }
1946  else {
1947  /* We got a file size report, so we check that there actually is a
1948  part of the file left to get, or else we go home. */
1949  if(conn->resume_from< 0) {
1950  /* We're supposed to download the last abs(from) bytes */
1951  if(foundsize < -conn->resume_from) {
1952  failf(data, "Offset (%" FORMAT_OFF_T
1953  ") was beyond file size (%" FORMAT_OFF_T ")",
1954  conn->resume_from, foundsize);
1956  }
1957  /* convert to size to download */
1958  downloadsize = -conn->resume_from;
1959  /* download from where? */
1960  conn->resume_from = foundsize - downloadsize;
1961  }
1962  else {
1963  if(foundsize < conn->resume_from) {
1964  failf(data, "Offset (%" FORMAT_OFF_T
1965  ") was beyond file size (%" FORMAT_OFF_T ")",
1966  conn->resume_from, foundsize);
1968  }
1969  /* Now store the number of bytes we are expected to download */
1970  downloadsize = foundsize-conn->resume_from;
1971  }
1972  }
1973 
1974  if (downloadsize == 0) {
1975  /* no data to transfer */
1976  result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1977  infof(data, "File already completely downloaded\n");
1978 
1979  /* Set no_transfer so that we won't get any error in Curl_ftp_done()
1980  * because we didn't transfer the any file */
1981  ftp->no_transfer = TRUE;
1982  return CURLE_OK;
1983  }
1984 
1985  /* Set resume file transfer offset */
1986  infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
1987  "\n",
1988  conn->resume_from);
1989 
1990  FTPSENDF(conn, "REST %" FORMAT_OFF_T, conn->resume_from);
1991 
1992  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1993  if(result)
1994  return result;
1995 
1996  if(ftpcode != 350) {
1997  failf(data, "Couldn't use REST: %s", buf+4);
1999  }
2000  }
2001 
2002  FTPSENDF(conn, "RETR %s", ftp->file);
2003  }
2004 
2005  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2006  if(result)
2007  return result;
2008 
2009  if((ftpcode == 150) || (ftpcode == 125)) {
2010 
2011  /*
2012  A;
2013  150 Opening BINARY mode data connection for /etc/passwd (2241
2014  bytes). (ok, the file is being transfered)
2015 
2016  B:
2017  150 Opening ASCII mode data connection for /bin/ls
2018 
2019  C:
2020  150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2021 
2022  D:
2023  150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes).
2024 
2025  E:
2026  125 Data connection already open; Transfer starting. */
2027 
2028  curl_off_t size=-1; /* default unknown size */
2029 
2030 
2031  /*
2032  * It appears that there are FTP-servers that return size 0 for files
2033  * when SIZE is used on the file while being in BINARY mode. To work
2034  * around that (stupid) behavior, we attempt to parse the RETR response
2035  * even if the SIZE returned size zero.
2036  *
2037  * Debugging help from Salvatore Sorrentino on February 26, 2003.
2038  */
2039 
2040  if(!dirlist &&
2041  !data->set.ftp_ascii &&
2042  (downloadsize < 1)) {
2043  /*
2044  * It seems directory listings either don't show the size or very
2045  * often uses size 0 anyway. ASCII transfers may very well turn out
2046  * that the transfered amount of data is not the same as this line
2047  * tells, why using this number in those cases only confuses us.
2048  *
2049  * Example D above makes this parsing a little tricky */
2050  char *bytes;
2051  bytes=strstr(buf, " bytes");
2052  if(bytes--) {
2053  long in=bytes-buf;
2054  /* this is a hint there is size information in there! ;-) */
2055  while(--in) {
2056  /* scan for the parenthesis and break there */
2057  if('(' == *bytes)
2058  break;
2059  /* if only skip digits, or else we're in deep trouble */
2060  if(!isdigit((int)*bytes)) {
2061  bytes=NULL;
2062  break;
2063  }
2064  /* one more estep backwards */
2065  bytes--;
2066  }
2067  /* only if we have nothing but digits: */
2068  if(bytes++) {
2069  /* get the number! */
2070  size = strtoofft(bytes, NULL, 0);
2071  }
2072 
2073  }
2074  }
2075  else if(downloadsize > -1)
2076  size = downloadsize;
2077 
2078  if(data->set.ftp_use_port) {
2079  result = AllowServerConnect(conn);
2080  if( result )
2081  return result;
2082  }
2083 
2084  if(conn->ssl[SECONDARYSOCKET].use) {
2085  /* since we only have a plaintext TCP connection here, we must now
2086  do the TLS stuff */
2087  infof(data, "Doing the SSL/TLS handshake on the data stream\n");
2088  result = Curl_SSLConnect(conn, SECONDARYSOCKET);
2089  if(result)
2090  return result;
2091  }
2092 
2093  if(size > conn->maxdownload && conn->maxdownload > 0)
2094  size = conn->size = conn->maxdownload;
2095 
2096  infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
2097 
2098  /* FTP download: */
2099  result=Curl_Transfer(conn, SECONDARYSOCKET, size, FALSE,
2100  bytecountp,
2101  -1, NULL); /* no upload here */
2102  if(result)
2103  return result;
2104  }
2105  else {
2106  if(dirlist && (ftpcode == 450)) {
2107  /* simply no matching files */
2108  ftp->no_transfer = TRUE; /* don't think we should download anything */
2109  }
2110  else {
2111  failf(data, "%s", buf+4);
2113  }
2114  }
2115 
2116  }
2117  /* end of transfer */
2118 
2119  return CURLE_OK;
2120 }
2121 
2122 /***********************************************************************
2123  *
2124  * ftp_perform()
2125  *
2126  * This is the actual DO function for FTP. Get a file/directory according to
2127  * the options previously setup.
2128  */
2129 
2130 static
2131 CURLcode ftp_perform(struct connectdata *conn,
2132  bool *connected) /* for the TCP connect status after
2133  PASV / PORT */
2134 {
2135  /* this is FTP and no proxy */
2136  CURLcode result=CURLE_OK;
2137  struct SessionHandle *data=conn->data;
2138  char *buf = data->state.buffer; /* this is our buffer */
2139 
2140  /* the ftp struct is already inited in Curl_ftp_connect() */
2141  struct FTP *ftp = conn->proto.ftp;
2142 
2143  /* Send any QUOTE strings? */
2144  if(data->set.quote) {
2145  if ((result = ftp_sendquote(conn, data->set.quote)) != CURLE_OK)
2146  return result;
2147  }
2148 
2149  /* This is a re-used connection. Since we change directory to where the
2150  transfer is taking place, we must now get back to the original dir
2151  where we ended up after login: */
2152  if (conn->bits.reuse && ftp->entrypath) {
2153  if ((result = ftp_cwd_and_mkd(conn, ftp->entrypath)) != CURLE_OK)
2154  return result;
2155  }
2156 
2157  {
2158  int i; /* counter for loop */
2159  for (i=0; ftp->dirs[i]; i++) {
2160  /* RFC 1738 says empty components should be respected too, but
2161  that is plain stupid since CWD can't be used with an empty argument */
2162  if ((result = ftp_cwd_and_mkd(conn, ftp->dirs[i])) != CURLE_OK)
2163  return result;
2164  }
2165  }
2166 
2167  /* Requested time of file or time-depended transfer? */
2168  if((data->set.get_filetime || data->set.timecondition) &&
2169  ftp->file) {
2170  result = ftp_getfiletime(conn, ftp->file);
2171  switch( result )
2172  {
2174  case CURLE_OK:
2175  if(data->set.timecondition) {
2176  if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2177  switch(data->set.timecondition) {
2179  default:
2180  if(data->info.filetime < data->set.timevalue) {
2181  infof(data, "The requested document is not new enough\n");
2182  ftp->no_transfer = TRUE; /* mark this to not transfer data */
2183  return CURLE_OK;
2184  }
2185  break;
2187  if(data->info.filetime > data->set.timevalue) {
2188  infof(data, "The requested document is not old enough\n");
2189  ftp->no_transfer = TRUE; /* mark this to not transfer data */
2190  return CURLE_OK;
2191  }
2192  break;
2193  } /* switch */
2194  }
2195  else {
2196  infof(data, "Skipping time comparison\n");
2197  }
2198  }
2199  break;
2200  default:
2201  return result;
2202  } /* switch */
2203  }
2204 
2205  /* If we have selected NOBODY and HEADER, it means that we only want file
2206  information. Which in FTP can't be much more than the file size and
2207  date. */
2208  if(data->set.no_body && data->set.include_header && ftp->file) {
2209  /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
2210  may not support it! It is however the only way we have to get a file's
2211  size! */
2212  curl_off_t filesize;
2213  ssize_t nread;
2214  int ftpcode;
2215 
2216  ftp->no_transfer = TRUE; /* this means no actual transfer is made */
2217 
2218  /* Some servers return different sizes for different modes, and thus we
2219  must set the proper type before we check the size */
2220  result = ftp_transfertype(conn, data->set.ftp_ascii);
2221  if(result)
2222  return result;
2223 
2224  /* failing to get size is not a serious error */
2225  result = ftp_getsize(conn, ftp->file, &filesize);
2226 
2227  if(CURLE_OK == result) {
2228  sprintf(buf, "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
2229  result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
2230  if(result)
2231  return result;
2232  }
2233 
2234  /* Determine if server can respond to REST command and therefore
2235  whether it can do a range */
2236  FTPSENDF(conn, "REST 0", NULL);
2237  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2238 
2239  if ((CURLE_OK == result) && (ftpcode == 350)) {
2240  result = Curl_client_write(data, CLIENTWRITE_BOTH,
2241  (char *)"Accept-ranges: bytes\r\n", 0);
2242  if(result)
2243  return result;
2244  }
2245 
2246  /* If we asked for a time of the file and we actually got one as
2247  well, we "emulate" a HTTP-style header in our output. */
2248 
2249 #ifdef HAVE_STRFTIME
2250  if(data->set.get_filetime && (data->info.filetime>=0) ) {
2251  struct tm *tm;
2252  time_t clock = (time_t)data->info.filetime;
2253 #ifdef HAVE_GMTIME_R
2254  struct tm buffer;
2255  tm = (struct tm *)gmtime_r(&clock, &buffer);
2256 #else
2257  tm = gmtime(&clock);
2258 #endif
2259  /* format: "Tue, 15 Nov 1994 12:45:26" */
2260  strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S GMT\r\n",
2261  tm);
2262  result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
2263  if(result)
2264  return result;
2265  }
2266 #endif
2267 
2268  return CURLE_OK;
2269  }
2270 
2271  if(data->set.no_body)
2272  /* doesn't really transfer any data */
2273  ftp->no_transfer = TRUE;
2274  /* Get us a second connection up and connected */
2275  else if(data->set.ftp_use_port) {
2276  /* We have chosen to use the PORT command */
2277  result = ftp_use_port(conn);
2278  if(CURLE_OK == result) {
2279  /* we have the data connection ready */
2280  infof(data, "Ordered connect of the data stream with PORT!\n");
2281  *connected = TRUE; /* mark us "still connected" */
2282  }
2283  }
2284  else {
2285  /* We have chosen (this is default) to use the PASV command */
2286  result = ftp_use_pasv(conn, connected);
2287  if(CURLE_OK == result && *connected)
2288  infof(data, "Connected the data stream with PASV!\n");
2289  }
2290 
2291  return result;
2292 }
2293 
2294 /***********************************************************************
2295  *
2296  * Curl_ftp()
2297  *
2298  * This function is registered as 'curl_do' function. It decodes the path
2299  * parts etc as a wrapper to the actual DO function (ftp_perform).
2300  *
2301  * The input argument is already checked for validity.
2302  *
2303  * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
2304  * end of the function.
2305  */
2307 {
2308  CURLcode retcode=CURLE_OK;
2309  bool connected=0;
2310  struct SessionHandle *data = conn->data;
2311  struct FTP *ftp;
2312 
2313  char *slash_pos; /* position of the first '/' char in curpos */
2314  char *cur_pos=conn->ppath; /* current position in ppath. point at the begin
2315  of next path component */
2316  int path_part=0;/* current path component */
2317 
2318  /* the ftp struct is already inited in ftp_connect() */
2319  ftp = conn->proto.ftp;
2320  ftp->ctl_valid = FALSE;
2321  conn->size = -1; /* make sure this is unknown at this point */
2322 
2323  Curl_pgrsSetUploadCounter(data, 0);
2324  Curl_pgrsSetDownloadCounter(data, 0);
2325  Curl_pgrsSetUploadSize(data, 0);
2326  Curl_pgrsSetDownloadSize(data, 0);
2327 
2328  /* fixed : initialize ftp->dirs[xxx] to NULL !
2329  is done in Curl_ftp_connect() */
2330 
2331  /* parse the URL path into separate path components */
2332  while((slash_pos=strchr(cur_pos, '/'))) {
2333  /* 1 or 0 to indicate absolute directory */
2334  bool absolute_dir = (cur_pos - conn->ppath > 0) && (path_part == 0);
2335 
2336  /* seek out the next path component */
2337  if (slash_pos-cur_pos) {
2338  /* we skip empty path components, like "x//y" since the FTP command CWD
2339  requires a parameter and a non-existant parameter a) doesn't work on
2340  many servers and b) has no effect on the others. */
2341  ftp->dirs[path_part] = curl_unescape(cur_pos - absolute_dir,
2342  slash_pos - cur_pos + absolute_dir);
2343 
2344  if (!ftp->dirs[path_part]) { /* run out of memory ... */
2345  failf(data, "no memory");
2346  freedirs(ftp);
2347  return CURLE_OUT_OF_MEMORY;
2348  }
2349  }
2350  else {
2351  cur_pos = slash_pos + 1; /* jump to the rest of the string */
2352  continue;
2353  }
2354 
2355  if(!retcode) {
2356  cur_pos = slash_pos + 1; /* jump to the rest of the string */
2357  if(++path_part >= (CURL_MAX_FTP_DIRDEPTH-1)) {
2358  /* too deep, we need the last entry to be kept NULL at all
2359  times to signal end of list */
2360  failf(data, "too deep dir hierarchy");
2361  freedirs(ftp);
2362  return CURLE_URL_MALFORMAT;
2363  }
2364  }
2365  }
2366 
2367  ftp->file = cur_pos; /* the rest is the file name */
2368 
2369  if(*ftp->file) {
2370  ftp->file = curl_unescape(ftp->file, 0);
2371  if(NULL == ftp->file) {
2372  freedirs(ftp);
2373  failf(data, "no memory");
2374  return CURLE_OUT_OF_MEMORY;
2375  }
2376  }
2377  else
2378  ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL
2379  pointer */
2380 
2381  retcode = ftp_perform(conn, &connected);
2382 
2383  if(CURLE_OK == retcode) {
2384  if(connected)
2385  retcode = Curl_ftp_nextconnect(conn);
2386 
2387  if(retcode && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
2388  /* Failure detected, close the second socket if it was created already */
2389  sclose(conn->sock[SECONDARYSOCKET]);
2391  }
2392 
2393  if(ftp->no_transfer)
2394  /* no data to transfer */
2395  retcode=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2396  else if(!connected)
2397  /* since we didn't connect now, we want do_more to get called */
2398  conn->bits.do_more = TRUE;
2399  }
2400  else
2401  freedirs(ftp);
2402 
2403  ftp->ctl_valid = TRUE;
2404  return retcode;
2405 }
2406 
2407 /***********************************************************************
2408  *
2409  * Curl_ftpsendf()
2410  *
2411  * Sends the formated string as a ftp command to a ftp server
2412  *
2413  * NOTE: we build the command in a fixed-length buffer, which sets length
2414  * restrictions on the command!
2415  */
2417  const char *fmt, ...)
2418 {
2419  ssize_t bytes_written;
2420  char s[256];
2421  size_t write_len;
2422  char *sptr=s;
2423  CURLcode res = CURLE_OK;
2424 
2425  va_list ap;
2426  va_start(ap, fmt);
2427  vsnprintf(s, 250, fmt, ap);
2428  va_end(ap);
2429 
2430  strcat(s, "\r\n"); /* append a trailing CRLF */
2431 
2432  bytes_written=0;
2433  write_len = strlen(s);
2434 
2435  while(1) {
2436  res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
2437  &bytes_written);
2438 
2439  if(CURLE_OK != res)
2440  break;
2441 
2442  if(conn->data->set.verbose)
2443  Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, bytes_written);
2444 
2445  if(bytes_written != (ssize_t)write_len) {
2446  write_len -= bytes_written;
2447  sptr += bytes_written;
2448  }
2449  else
2450  break;
2451  }
2452 
2453  return res;
2454 }
2455 
2456 /***********************************************************************
2457  *
2458  * Curl_ftp_quit()
2459  *
2460  * This should be called before calling sclose() on an ftp control connection
2461  * (not data connections). We should then wait for the response from the
2462  * server before returning. The calling code should then try to close the
2463  * connection.
2464  *
2465  */
2467 {
2468  ssize_t nread;
2469  int ftpcode;
2470  CURLcode ret = CURLE_OK;
2471 
2472  if(conn->proto.ftp->ctl_valid) {
2473  ret = Curl_ftpsendf(conn, "%s", "QUIT");
2474  if(CURLE_OK == ret)
2475  ret = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2476  }
2477 
2478  return ret;
2479 }
2480 
2481 /***********************************************************************
2482  *
2483  * Curl_ftp_disconnect()
2484  *
2485  * Disconnect from an FTP server. Cleanup protocol-specific per-connection
2486  * resources
2487  */
2489 {
2490  struct FTP *ftp= conn->proto.ftp;
2491 
2492  /* We cannot send quit unconditionally. If this connection is stale or
2493  bad in any way, sending quit and waiting around here will make the
2494  disconnect wait in vain and cause more problems than we need to.
2495 
2496  Curl_ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
2497  will try to send the QUIT command, otherwise it will just return.
2498  */
2499 
2500  /* The FTP session may or may not have been allocated/setup at this point! */
2501  if(ftp) {
2502  (void)Curl_ftp_quit(conn); /* ignore errors on the QUIT */
2503 
2504  if(ftp->entrypath)
2505  free(ftp->entrypath);
2506  if(ftp->cache) {
2507  free(ftp->cache);
2508  ftp->cache = NULL;
2509  }
2510  if(ftp->file) {
2511  free(ftp->file);
2512  ftp->file = NULL; /* zero */
2513  }
2514  freedirs(ftp);
2515  }
2516  return CURLE_OK;
2517 }
2518 
2519 /***********************************************************************
2520  *
2521  * ftp_mkd()
2522  *
2523  * Makes a directory on the FTP server.
2524  *
2525  * Calls failf()
2526  */
2527 CURLcode ftp_mkd(struct connectdata *conn, char *path)
2528 {
2529  CURLcode result=CURLE_OK;
2530  int ftpcode; /* for ftp status */
2531  ssize_t nread;
2532 
2533  /* Create a directory on the remote server */
2534  FTPSENDF(conn, "MKD %s", path);
2535 
2536  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2537  if(result)
2538  return result;
2539 
2540  switch(ftpcode) {
2541  case 257:
2542  /* success! */
2543  infof( conn->data , "Created remote directory %s\n" , path );
2544  break;
2545  case 550:
2546  failf(conn->data, "Permission denied to make directory %s", path);
2547  result = CURLE_FTP_ACCESS_DENIED;
2548  break;
2549  default:
2550  failf(conn->data, "unrecognized MKD response: %d", ftpcode );
2551  result = CURLE_FTP_ACCESS_DENIED;
2552  break;
2553  }
2554  return result;
2555 }
2556 
2557 /***********************************************************************
2558  *
2559  * ftp_cwd()
2560  *
2561  * Send 'CWD' to the remote server to Change Working Directory. It is the ftp
2562  * version of the unix 'cd' command. This function is only called from the
2563  * ftp_cwd_and_mkd() function these days.
2564  *
2565  * This function does NOT call failf().
2566  */
2567 static
2568 CURLcode ftp_cwd(struct connectdata *conn, char *path)
2569 {
2570  ssize_t nread;
2571  int ftpcode;
2572  CURLcode result;
2573 
2574  FTPSENDF(conn, "CWD %s", path);
2575  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2576  if (!result) {
2577  /* According to RFC959, CWD is supposed to return 250 on success, but
2578  there seem to be non-compliant FTP servers out there that return 200,
2579  so we accept any '2xy' code here. */
2580  if (ftpcode/100 != 2)
2581  result = CURLE_FTP_ACCESS_DENIED;
2582  }
2583 
2584  return result;
2585 }
2586 
2587 /***********************************************************************
2588  *
2589  * ftp_cwd_and_mkd()
2590  *
2591  * Change to the given directory. If the directory is not present, and we
2592  * have been told to allow it, then create the directory and cd to it.
2593  *
2594  */
2595 static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path)
2596 {
2597  CURLcode result;
2598 
2599  result = ftp_cwd(conn, path);
2600  if (result) {
2601  if(conn->data->set.ftp_create_missing_dirs) {
2602  result = ftp_mkd(conn, path);
2603  if (result)
2604  /* ftp_mkd() calls failf() itself */
2605  return result;
2606  result = ftp_cwd(conn, path);
2607  }
2608  if(result)
2609  failf(conn->data, "Couldn't cd to %s", path);
2610  }
2611  return result;
2612 }
2613 
2614 #endif /* CURL_DISABLE_FTP */
struct FTP * ftp
Definition: urldata.h:542
GLdouble GLdouble GLdouble GLdouble q
Definition: glext.h:2959
bool krb4
Definition: urldata.h:872
int Curl_sec_read_msg(struct connectdata *conn, char *, int)
#define socklen_t
CURLcode Curl_krb_kauth(struct connectdata *conn)
struct ssl_connect_data ssl[2]
Definition: urldata.h:459
#define in_addr_t
void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size)
Definition: progress.c:180
bool no_body
Definition: urldata.h:864
#define CLIENTWRITE_BOTH
Definition: sendf.h:36
char * dirs[CURL_MAX_FTP_DIRDEPTH]
Definition: urldata.h:246
bool ftp_use_port
Definition: urldata.h:854
#define strcmp
Definition: Str.h:41
curl_off_t cache_size
Definition: urldata.h:252
struct ConnectBits bits
Definition: urldata.h:462
curl_off_t bytecount
Definition: urldata.h:437
char buffer[BUFSIZE+1]
Definition: urldata.h:679
char * curl_unescape(const char *string, int length)
Definition: escape.c:86
union connectdata::@11 proto
int curl_socket_t
Definition: setup.h:254
int Curl_resolv(struct connectdata *conn, char *hostname, int port, struct Curl_dns_entry **entry)
Definition: hostip.c:315
#define FIRSTSOCKET
Definition: urldata.h:394
long tv_sec
Definition: timeval.h:37
long connecttimeout
Definition: urldata.h:795
struct DynamicStatic change
Definition: urldata.h:899
bool ftp_use_epsv
Definition: urldata.h:876
GLenum GLsizei n
Definition: glext.h:3705
#define failf
Definition: sendf.h:32
char * data
Definition: curl.h:1062
case const int
Definition: Callbacks.cpp:52
char * customrequest
Definition: urldata.h:821
bool ctl_valid
Definition: urldata.h:261
CURLcode Curl_client_write(struct SessionHandle *data, int type, char *ptr, size_t len)
Definition: sendf.c:319
time_t curl_getdate(const char *p, const time_t *now)
Definition: getdate.c:1991
CURLcode Curl_ftp_quit(struct connectdata *conn)
Definition: ftp.c:2466
CURLcode
Definition: curl.h:209
char * user
Definition: urldata.h:243
CURLcode Curl_GetFTPResponse(ssize_t *nreadp, struct connectdata *conn, int *ftpcode)
Definition: ftp.c:208
bool no_transfer
Definition: urldata.h:256
struct in_addr Curl_ipconnect
Definition: setup.h:276
struct curl_slist * quote
Definition: urldata.h:813
curl_ftpssl ftp_ssl
Definition: urldata.h:878
bool upload
Definition: urldata.h:866
unsigned short remote_port
Definition: urldata.h:434
#define SECONDARYSOCKET
Definition: urldata.h:395
GLdouble s
Definition: glext.h:2935
GLenum GLsizei len
Definition: glext.h:3472
struct UrlState state
Definition: urldata.h:903
CURLcode Curl_ftpsendf(struct connectdata *conn, const char *fmt,...)
Definition: ftp.c:2416
off_t curl_off_t
Definition: curl.h:96
int Curl_read(struct connectdata *conn, curl_socket_t sockfd, char *buf, size_t buffersize, ssize_t *n)
Definition: sendf.c:362
#define CURL_MAX_FTP_DIRDEPTH
Definition: urldata.h:111
#define CURL_INADDR_NONE
Definition: hostip.h:93
int i
Definition: process.py:33
long ftp_response_timeout
Definition: urldata.h:796
CURLcode Curl_ftp(struct connectdata *conn)
Definition: ftp.c:2306
GLuint GLuint num
Definition: glext.h:5390
Boolean result
#define ssize_t
Definition: config-win32.h:27
int Curl_sec_request_prot(struct connectdata *conn, const char *level)
#define vsnprintf
int Curl_nonblock(curl_socket_t sockfd, int nonblock)
Definition: connect.c:114
bool reuse
Definition: urldata.h:279
bool dont_check
Definition: urldata.h:253
CURLcode Curl_write(struct connectdata *conn, curl_socket_t sockfd, void *mem, size_t len, ssize_t *written)
Definition: sendf.c:221
bool tunnel_thru_httpproxy
Definition: urldata.h:849
#define lastline(line)
bool get_filetime
Definition: urldata.h:848
curl_off_t resume_from
Definition: urldata.h:442
long timeout
Definition: urldata.h:794
char * inet_ntoa_r(const struct in_addr in, char *buffer, int buflen)
bool crlf
Definition: urldata.h:812
char * passwd
Definition: urldata.h:447
long tv_usec
Definition: timeval.h:38
void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size)
Definition: progress.c:170
int Curl_pgrsUpdate(struct connectdata *conn)
Definition: progress.c:206
bool ftp_use_eprt
Definition: urldata.h:877
char * proxy
Definition: urldata.h:740
#define strlcat(x, y, z)
Definition: strequal.h:40
void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size)
Definition: progress.c:175
struct PureInfo info
Definition: urldata.h:905
Curl_addrinfo * addr
Definition: hostip.h:41
void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns)
Definition: hostip.c:408
curl_off_t size
Definition: urldata.h:494
char * hostname
Definition: urldata.h:432
bool ftp_create_missing_dirs
Definition: urldata.h:853
#define FORMAT_OFF_T
Definition: setup.h:99
Definition: hostip.h:40
#define NULL
Definition: Lib.h:88
void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size)
Definition: progress.c:189
struct curl_slist * next
Definition: curl.h:1063
#define select(args...)
Definition: amigaos.h:39
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:2853
GLuint buffer
Definition: glext.h:3108
char * cache
Definition: urldata.h:251
struct timeval now
Definition: urldata.h:452
char * ppath
Definition: urldata.h:436
int Curl_sec_fflush_fd(struct connectdata *conn, int fd)
GLint mode
Definition: glext.h:4165
const char * path
Definition: sws.c:117
void Curl_sec_set_protection_level(struct connectdata *conn)
Definition: urldata.h:241
bool include_header
Definition: urldata.h:859
#define CLIENTWRITE_HEADER
Definition: sendf.h:35
struct tm * gmtime(const time_t *)
CURLcode Curl_Transfer(struct connectdata *c_conn, int sockindex, curl_off_t size, bool getheader, curl_off_t *bytecountp, int writesockindex, curl_off_t *writecountp)
Definition: transfer.c:1998
char * range
Definition: urldata.h:440
long Curl_tvdiff(struct timeval newer, struct timeval older)
Definition: timeval.c:92
GLenum const GLvoid * addr
Definition: glext.h:5393
Definition: curl.h:210
struct SessionHandle * data
Definition: urldata.h:403
curl_read_callback fread
Definition: urldata.h:565
char * entrypath
Definition: urldata.h:249
bool close
Definition: urldata.h:278
#define sclose(x)
Definition: setup.h:220
#define PROT_FTPS
Definition: urldata.h:417
char * proxyhost
Definition: urldata.h:444
bool ftp_append
Definition: urldata.h:850
char * Curl_if2ip(char *interface, char *buf, int buf_size)
Definition: if2ip.c:84
char * name
Definition: urldata.h:430
curl_off_t infilesize
Definition: urldata.h:797
int Curl_debug(struct SessionHandle *data, curl_infotype type, char *ptr, size_t size)
Definition: sendf.c:439
int httpcode
Definition: urldata.h:587
CURLcode Curl_connecthost(struct connectdata *conn, struct Curl_dns_entry *remotehost, int port, curl_socket_t *sockconn, Curl_ipconnect **addr, bool *connected)
Definition: connect.c:513
CURLcode Curl_ftp_done(struct connectdata *conn)
Definition: ftp.c:720
bool ftp_ascii
Definition: urldata.h:851
curl_off_t max_filesize
Definition: urldata.h:842
char * ftpport
Definition: urldata.h:786
struct curl_slist * postquote
Definition: urldata.h:814
curl_socket_t sock[2]
Definition: urldata.h:454
GLuint in
Definition: glext.h:5388
bool verbose
Definition: urldata.h:871
#define snprintf
Definition: Str.h:70
GLsizeiptr size
Definition: glext.h:3112
time_t timevalue
Definition: urldata.h:818
CURLcode Curl_wait_for_resolv(struct connectdata *conn, struct Curl_dns_entry **entry)
Definition: hostip.c:676
char * file
Definition: urldata.h:247
#define CURL_SOCKET_BAD
Definition: setup.h:255
GLuint address
Definition: glext.h:5165
#define infof
Definition: sendf.h:31
typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLclampf red
void * fread_in
Definition: urldata.h:566
#define FALSE
Definition: mprintf.c:70
struct timeval Curl_tvnow(void)
Definition: timeval.c:81
char * krb4_level
Definition: urldata.h:828
#define inet_ntoa(x)
Definition: amigaos.h:40
struct UserDefined set
Definition: urldata.h:898
long port
Definition: urldata.h:433
bool use_range
Definition: urldata.h:286
#define strtoofft
Definition: strtoofft.h:58
GLuint res
Definition: glext.h:5385
CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
Definition: ftp.c:1688
#define TRUE
Definition: mprintf.c:69
struct curl_slist * prequote
Definition: urldata.h:815
curl_off_t * bytecountp
Definition: urldata.h:242
long protocol
Definition: urldata.h:407
#define FTPSENDF(x, y, z)
Definition: ftp.c:115
bool do_more
Definition: urldata.h:289
CURLcode Curl_SSLConnect(struct connectdata *conn, int sockindex)
Definition: ssluse.c:913
char * passwd
Definition: urldata.h:244
long response_time
Definition: urldata.h:258
curl_off_t maxdownload
Definition: urldata.h:456
bool ftp_list_only
Definition: urldata.h:852
curl_TimeCond timecondition
Definition: urldata.h:817
CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, int sockindex, char *hostname, int remote_port)
Definition: http.c:731
CURLcode Curl_ftp_disconnect(struct connectdata *conn)
Definition: ftp.c:2488
CURLcode Curl_ftp_connect(struct connectdata *conn)
Definition: ftp.c:441
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
long filetime
Definition: urldata.h:590
int Curl_sec_login(struct connectdata *)
#define CURLE_OPERATION_TIMEDOUT
Definition: curl.h:286
#define BUFSIZE
Definition: urldata.h:104
char * user
Definition: urldata.h:446
#define CURLE_FTP_BAD_DOWNLOAD_RESUME
Definition: curl.h:310